https://gcc.gnu.org/g:579d47d0b3d005494ca9e5a175da914387d16c5e
commit r17-5440-g579d47d0b3d005494ca9e5a175da914387d16c5e Author: Arthur Cohen <[email protected]> Date: Tue Sep 29 16:15:25 2026 +0200 gccrs: backend: Properly implement remainder operation for f32 and f64 When performing the mod/remainder operation on floating point values, we cannot simply make a fold_build2 binary op as this operation is not defined in later passes of GCC for f32 and f64. We have to call the remainder{,f,l} builtins and store the result instead. This was previously uncaught in our testsuite, and the associated testcase would simply ICE. gcc/rust/ChangeLog: * rust-gcc.cc (builtin_remainder_float_call): New function. (maybe_extend_precision): Likewise. (arithmetic_or_logical_expression): Call them and adapt logic. gcc/testsuite/ChangeLog: * rust/compile/float-rem.rs: New test. Diff: --- gcc/rust/rust-gcc.cc | 75 +++++++++++++++++++++++++++------ gcc/testsuite/rust/compile/float-rem.rs | 19 +++++++++ 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 88781f52b172..b3e5a5cdddc4 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -30,6 +30,7 @@ #include "fold-const.h" #include "stringpool.h" #include "stor-layout.h" +#include "util/optional.h" #include "varasm.h" #include "tree-iterator.h" #include "tm.h" @@ -1087,6 +1088,55 @@ negation_expression (NegationOperator op, tree expr_tree, location_t location) return new_tree; } +static tree +builtin_remainder_float_call (tree lhs, tree rhs, location_t loc) +{ + auto builtin_ctx = Rust::Compile::BuiltinsContext::get (); + tl::optional<tree> remainder = tl::nullopt; + + if (TYPE_PRECISION (TREE_TYPE (lhs)) == TYPE_PRECISION (float_type_node)) + remainder = builtin_ctx.lookup_simple_builtin ("__builtin_remainderf"); + else if (TYPE_PRECISION (TREE_TYPE (lhs)) + == TYPE_PRECISION (double_type_node)) + remainder = builtin_ctx.lookup_simple_builtin ("__builtin_remainder"); + // For f128, we will need to do the following - but gccrs doesn't handle f128 + // at the moment AFAIK + else if (TYPE_PRECISION (TREE_TYPE (lhs)) + == TYPE_PRECISION (long_double_type_node)) + remainder = builtin_ctx.lookup_simple_builtin ("__builtin_remainderl"); + else + rust_unreachable (); + + rust_assert (remainder); + + return build_call_expr_loc (loc, *remainder, 2, lhs, rhs); +} + +/** + * For floating point operations we may need to extend the precision of the + * type. For example, a 64-bit machine may not support operations on f32s. + * + * Returns NULL_TREE if there was no need to extend the type and the extended + * type otherwise. + */ +static tree +maybe_extend_precision (bool floating_point, tree &lhs, tree &rhs, tree &ty) +{ + auto extended_type = NULL_TREE; + if (floating_point) + { + extended_type = excess_precision_type (ty); + if (extended_type != NULL_TREE) + { + lhs = convert (extended_type, lhs); + rhs = convert (extended_type, rhs); + ty = extended_type; + } + } + + return extended_type; +} + tree arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, tree right, location_t location) @@ -1111,23 +1161,20 @@ arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, as the lhs operand. */ auto tree_type = TREE_TYPE (left); auto original_type = tree_type; + auto extended_type + = maybe_extend_precision (floating_point, left, right, tree_type); + auto tree_code = operator_to_tree_code (op, floating_point); - /* For floating point operations we may need to extend the precision of type. - For example, a 64-bit machine may not support operations on float32. */ - auto extended_type = NULL_TREE; - if (floating_point) - { - extended_type = excess_precision_type (tree_type); - if (extended_type != NULL_TREE) - { - left = convert (extended_type, left); - right = convert (extended_type, right); - tree_type = extended_type; - } - } + /* In the case of a floating point remainder operation, we have to perform a + * call to a builtin function instead as the mod operation is not supported on + * floating point values. But for all other operations, this is simply a + * build2 */ + if (floating_point && op == ArithmeticOrLogicalOperator::MODULUS) + ret = builtin_remainder_float_call (left, right, location); + else + ret = build2_loc (location, tree_code, tree_type, left, right); - ret = build2_loc (location, tree_code, tree_type, left, right); TREE_CONSTANT (ret) = TREE_CONSTANT (left) & TREE_CONSTANT (right); // TODO: How do we handle floating point? diff --git a/gcc/testsuite/rust/compile/float-rem.rs b/gcc/testsuite/rust/compile/float-rem.rs new file mode 100644 index 000000000000..0836f84a9e8a --- /dev/null +++ b/gcc/testsuite/rust/compile/float-rem.rs @@ -0,0 +1,19 @@ +// { dg-options "-fdump-tree-gimple" } + +#![feature(no_core)] +#![no_core] + +// so that nothing gets const folded + +fn two_something() -> f32 { + 2.9 +} + +fn four_something() -> f32 { + 4.07 +} + +fn main() { + let _ = four_something() % two_something(); + // { dg-final { scan-tree-dump-times {__builtin_remainder} 1 gimple } } +}
