From: Arthur Cohen <[email protected]>
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.
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/2ba24ed657e97ef420bf1c51d3a7cc1c64dfbccd
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4943
gcc/rust/rust-gcc.cc | 75 ++++++++++++++++++++-----
gcc/testsuite/rust/compile/float-rem.rs | 19 +++++++
2 files changed, 80 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/float-rem.rs
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 88781f52b..b3e5a5cdd 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 000000000..0836f84a9
--- /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 } }
+}
base-commit: 3e2669c77156403468137a6f8d651d9e824dfb12
--
2.55.0