Skip to content

Commit

Permalink
[mlir][arith] Match folding of arith.remf to llvm.frem semantics (l…
Browse files Browse the repository at this point in the history
…lvm#96537)

There are multiple ways to define a remainder operation. Depending on
the definition, the result could be either always positive or have the
sign of the dividend.
The pattern lowering `arith.remf` to LLVM assumes that the semantics
match `llvm.frem`, which seems to be reasonable. The folder, however, is
implemented via `APFloat::remainder()` which has different semantics.

This patch matches the folding behaviour to lowering behavior by using
`APFloat::mod()`, which matches the behavior of `llvm.frem` and libm's
`fmod()`. It also updates the documentation of `arith.remf` to explain
this behavior: The sign of the result of the remainder operation always
matches the sign of the dividend (LHS operand).

frem documentation: https://llvm.org/docs/LangRef.html#frem-instruction

Fix llvm#94431

---------

Co-authored-by: Jakub Kuderski <kubakuderski@gmail.com>
  • Loading branch information
2 people authored and AlexisPerry committed Jun 27, 2024
1 parent ffbb0d0 commit 52ccd6c
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 3 deletions.
4 changes: 4 additions & 0 deletions mlir/include/mlir/Dialect/Arith/IR/ArithOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,10 @@ def Arith_DivFOp : Arith_FloatBinaryOp<"divf"> {

def Arith_RemFOp : Arith_FloatBinaryOp<"remf"> {
let summary = "floating point division remainder operation";
let description = [{
Returns the floating point division remainder.
The remainder has the same sign as the dividend (lhs operand).
}];
let hasFolder = 1;
}

Expand Down
5 changes: 4 additions & 1 deletion mlir/lib/Dialect/Arith/IR/ArithOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,10 @@ OpFoldResult arith::RemFOp::fold(FoldAdaptor adaptor) {
return constFoldBinaryOp<FloatAttr>(adaptor.getOperands(),
[](const APFloat &a, const APFloat &b) {
APFloat result(a);
(void)result.remainder(b);
// APFloat::mod() offers the remainder
// behavior we want, i.e. the result has
// the sign of LHS operand.
(void)result.mod(b);
return result;
});
}
Expand Down
17 changes: 15 additions & 2 deletions mlir/test/Dialect/Arith/canonicalize.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2467,7 +2467,7 @@ func.func @test_remsi_1(%arg : vector<4xi32>) -> (vector<4xi32>) {
// -----

// CHECK-LABEL: @test_remf(
// CHECK: %[[res:.+]] = arith.constant -1.000000e+00 : f32
// CHECK: %[[res:.+]] = arith.constant 1.000000e+00 : f32
// CHECK: return %[[res]]
func.func @test_remf() -> (f32) {
%v1 = arith.constant 3.0 : f32
Expand All @@ -2476,11 +2476,24 @@ func.func @test_remf() -> (f32) {
return %0 : f32
}

// CHECK-LABEL: @test_remf2(
// CHECK: %[[respos:.+]] = arith.constant 1.000000e+00 : f32
// CHECK: %[[resneg:.+]] = arith.constant -1.000000e+00 : f32
// CHECK: return %[[respos]], %[[resneg]]
func.func @test_remf2() -> (f32, f32) {
%v1 = arith.constant 3.0 : f32
%v2 = arith.constant -2.0 : f32
%v3 = arith.constant -3.0 : f32
%0 = arith.remf %v1, %v2 : f32
%1 = arith.remf %v3, %v2 : f32
return %0, %1 : f32, f32
}

// CHECK-LABEL: @test_remf_vec(
// CHECK: %[[res:.+]] = arith.constant dense<[1.000000e+00, 0.000000e+00, -1.000000e+00, 0.000000e+00]> : vector<4xf32>
// CHECK: return %[[res]]
func.func @test_remf_vec() -> (vector<4xf32>) {
%v1 = arith.constant dense<[1.0, 2.0, 3.0, 4.0]> : vector<4xf32>
%v1 = arith.constant dense<[1.0, 2.0, -3.0, 4.0]> : vector<4xf32>
%v2 = arith.constant dense<[2.0, 2.0, 2.0, 2.0]> : vector<4xf32>
%0 = arith.remf %v1, %v2 : vector<4xf32>
return %0 : vector<4xf32>
Expand Down

0 comments on commit 52ccd6c

Please sign in to comment.