https://gcc.gnu.org/g:5ce9793d513038aa7f1d7ad40334574f2da7e212
commit r17-5445-g5ce9793d513038aa7f1d7ad40334574f2da7e212 Author: Arthur Cohen <[email protected]> Date: Fri Oct 2 15:49:12 2026 +0200 gccrs: intrinsics: Add float_to_int_unchecked And open Rust-GCC/gccrs#4949 as this means our regular casts from float to int are invalid and missing some extra checks. gcc/rust/ChangeLog: * backend/rust-compile-intrinsic.cc: Declare the new intrinsic. * backend/rust-intrinsic-handlers.cc (float_to_int_unchecked): New handler. * backend/rust-intrinsic-handlers.h (float_to_int_unchecked): Declare it. * typecheck/rust-hir-type-check-intrinsic.cc: Add the intrinsic to the typecheck info. * util/rust-intrinsic-values.h: New value for float_to_int_unchecked. gcc/testsuite/ChangeLog: * rust/execute/torture/float_to_int_unchecked.rs: New test. Diff: --- gcc/rust/backend/rust-compile-intrinsic.cc | 1 + gcc/rust/backend/rust-intrinsic-handlers.cc | 44 ++++++++++++++++++++++ gcc/rust/backend/rust-intrinsic-handlers.h | 3 ++ .../typecheck/rust-hir-type-check-intrinsic.cc | 5 +++ gcc/rust/util/rust-intrinsic-values.h | 2 + .../rust/execute/torture/float_to_int_unchecked.rs | 22 +++++++++++ 6 files changed, 77 insertions(+) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index c16db442f3cc..0202f493cc8f 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -92,6 +92,7 @@ static const std::map<std::string, handlers::HandlerBuilder> generic_intrinsics handlers::fop_fast (ArithmeticOrLogicalOperator::DIVIDE)}, {IValue::FREM_FAST, handlers::fop_fast (ArithmeticOrLogicalOperator::MODULUS)}, + {IValue::FLOAT_TO_INT_UNCHECKED, handlers::float_to_int_unchecked}, }; Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {} diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc b/gcc/rust/backend/rust-intrinsic-handlers.cc index 2d8dad76379b..c07609891bdd 100644 --- a/gcc/rust/backend/rust-intrinsic-handlers.cc +++ b/gcc/rust/backend/rust-intrinsic-handlers.cc @@ -2316,6 +2316,50 @@ assert_zero_valid_handler (Context *ctx, TyTy::FnType *fntype, location_t) return fndecl; } +tree +float_to_int_unchecked (Context *ctx, TyTy::FnType *fntype, location_t loc) +{ + rust_assert (fntype->get_params ().size () == 1); + rust_assert (fntype->get_num_substitutions () == 2); + + tree lookup = NULL_TREE; + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) + return lookup; + + auto fndecl = compile_intrinsic_function (ctx, fntype); + + auto &dst_param = fntype->get_substs ().at (1); + const auto dst_ty = dst_param.get_param_ty (); + auto int_ty_resolved = dst_ty->resolve (); + + auto int_ty = TyTyResolveCompile::compile (ctx, int_ty_resolved); + + // setup the params + std::vector<Bvariable *> param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); + + rust_assert (param_vars.size () == 1); + + auto &float_param = param_vars.at (0); + + if (!Backend::function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + enter_intrinsic_block (ctx, fndecl); + + tree float_value = Backend::var_expression (float_param, UNDEF_LOCATION); + + auto convert_expr = Backend::convert_expression (int_ty, float_value, loc); + + auto return_statement = Backend::return_statement (fndecl, convert_expr, loc); + + ctx->add_statement (return_statement); + + finalize_intrinsic_block (ctx, fndecl); + + return fndecl; +} + } // namespace handlers } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h b/gcc/rust/backend/rust-intrinsic-handlers.h index 6161b7fa2c43..bc668a7f1404 100644 --- a/gcc/rust/backend/rust-intrinsic-handlers.h +++ b/gcc/rust/backend/rust-intrinsic-handlers.h @@ -112,6 +112,9 @@ tree assert_zero_valid_handler (Context *ctx, TyTy::FnType *fntype, */ HandlerBuilder fop_fast (ArithmeticOrLogicalOperator op); +tree float_to_int_unchecked (Context *ctx, TyTy::FnType *fntype, + location_t loc); + } // namespace handlers } // namespace Compile diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc index 716df7880557..1498a09c4da9 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc @@ -327,6 +327,11 @@ const std::unordered_map<std::string, IntrinsicRules> {IValue::FREM_FAST, {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}}, + // fn float_to_int_unchecked<Float, Int>(x: Float) -> Int + // where Float: FloatPrimitive, Int: Copy + {IValue::FLOAT_TO_INT_UNCHECKED, + {2, {IRT::FirstGeneric}, IRT::SecondGeneric}}, + }; IntrinsicCheckResult diff --git a/gcc/rust/util/rust-intrinsic-values.h b/gcc/rust/util/rust-intrinsic-values.h index 9223e20abedc..0da1f0c3ac31 100644 --- a/gcc/rust/util/rust-intrinsic-values.h +++ b/gcc/rust/util/rust-intrinsic-values.h @@ -181,6 +181,8 @@ public: static constexpr auto &FMUL_FAST = "fmul_fast"; static constexpr auto &FDIV_FAST = "fdiv_fast"; static constexpr auto &FREM_FAST = "frem_fast"; + + static constexpr auto &FLOAT_TO_INT_UNCHECKED = "float_to_int_unchecked"; }; } // namespace Values } // namespace Rust diff --git a/gcc/testsuite/rust/execute/torture/float_to_int_unchecked.rs b/gcc/testsuite/rust/execute/torture/float_to_int_unchecked.rs new file mode 100644 index 000000000000..4f342c2919ca --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/float_to_int_unchecked.rs @@ -0,0 +1,22 @@ +#![feature(no_core)] +#![feature(intrinsics)] +#![feature(lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +extern "rust-intrinsic" { + fn float_to_int_unchecked<Float, Int>(value: Float) -> Int; +} + +fn main() -> i32 { + let a = 15.07; + + let b = a as i32; + let c: i32 = unsafe { float_to_int_unchecked(a) }; + + // NOTE: This is only valid for certain floating point values as f32 -> i32 conversions + // are different for invalid values when using the cast and when using the unchecked intrinsic + b - c +}
