[flang-commits] [flang] [mlir] [mlir][math] Replace roundeven call by nearbyint call when target does not have C23 features (PR #88687)

Corentin Ferry via flang-commits flang-commits at lists.llvm.org
Mon Apr 15 00:22:26 PDT 2024


https://github.com/cferry-AMD updated https://github.com/llvm/llvm-project/pull/88687

>From 6079696ff9e4d37779f144c22d7824031bb3b2ab Mon Sep 17 00:00:00 2001
From: Corentin Ferry <corentin.ferry at amd.com>
Date: Fri, 12 Apr 2024 08:48:47 +0200
Subject: [PATCH 1/3] Merge pull request #156 from Xilinx/corentin.roundeven

[FXML-4442] Roundeven is only C23, emit nearbyint otherwise
---
 .../mlir/Conversion/MathToLibm/MathToLibm.h   |  5 ++-
 mlir/include/mlir/Conversion/Passes.td        |  6 +++
 mlir/lib/Conversion/MathToLibm/MathToLibm.cpp | 24 +++++++++--
 .../test/Conversion/MathToLibm/nearbyint.mlir | 41 +++++++++++++++++++
 .../MathToLibm/roundeven-failed.mlir          |  8 ++++
 5 files changed, 79 insertions(+), 5 deletions(-)
 create mode 100644 mlir/test/Conversion/MathToLibm/nearbyint.mlir
 create mode 100644 mlir/test/Conversion/MathToLibm/roundeven-failed.mlir

diff --git a/mlir/include/mlir/Conversion/MathToLibm/MathToLibm.h b/mlir/include/mlir/Conversion/MathToLibm/MathToLibm.h
index ab9a1cef20cab7..1fac96abef621f 100644
--- a/mlir/include/mlir/Conversion/MathToLibm/MathToLibm.h
+++ b/mlir/include/mlir/Conversion/MathToLibm/MathToLibm.h
@@ -19,10 +19,13 @@ class OperationPass;
 
 /// Populate the given list with patterns that convert from Math to Libm calls.
 /// If log1pBenefit is present, use it instead of benefit for the Log1p op.
-void populateMathToLibmConversionPatterns(RewritePatternSet &patterns);
+void populateMathToLibmConversionPatterns(
+    RewritePatternSet &patterns, const ConvertMathToLibmOptions &options);
 
 /// Create a pass to convert Math operations to libm calls.
 std::unique_ptr<OperationPass<ModuleOp>> createConvertMathToLibmPass();
+std::unique_ptr<OperationPass<ModuleOp>>
+createConvertMathToLibmPass(const ConvertMathToLibmOptions &options);
 
 } // namespace mlir
 
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index d094ee3b36ab95..8f8eacdb6e8c1c 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -692,6 +692,12 @@ def ConvertMathToLibm : Pass<"convert-math-to-libm", "ModuleOp"> {
     "func::FuncDialect",
     "vector::VectorDialect",
   ];
+  let options = [
+    Option<"allowC23Features", "allow-c23-features", "bool", "true",
+           "Allow calls to C23-specific functions">,
+    Option<"roundingModeIsDefault", "rounding-mode-is-default", "bool", "false",
+           "Assume default rounding mode">
+  ];
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp b/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp
index 5b1c59d0c95e92..1c500b397edd4c 100644
--- a/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp
+++ b/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp
@@ -159,7 +159,8 @@ ScalarOpToLibmCall<Op>::matchAndRewrite(Op op,
   return success();
 }
 
-void mlir::populateMathToLibmConversionPatterns(RewritePatternSet &patterns) {
+void mlir::populateMathToLibmConversionPatterns(
+    RewritePatternSet &patterns, const ConvertMathToLibmOptions &options) {
   MLIRContext *ctx = patterns.getContext();
 
   populatePatternsForOp<math::AbsFOp>(patterns, ctx, "fabsf", "fabs");
@@ -185,8 +186,15 @@ void mlir::populateMathToLibmConversionPatterns(RewritePatternSet &patterns) {
   populatePatternsForOp<math::Log10Op>(patterns, ctx, "log10f", "log10");
   populatePatternsForOp<math::Log1pOp>(patterns, ctx, "log1pf", "log1p");
   populatePatternsForOp<math::PowFOp>(patterns, ctx, "powf", "pow");
-  populatePatternsForOp<math::RoundEvenOp>(patterns, ctx, "roundevenf",
-                                           "roundeven");
+  if (options.allowC23Features)
+    populatePatternsForOp<math::RoundEvenOp>(patterns, ctx, "roundevenf",
+                                             "roundeven");
+  else if (options.roundingModeIsDefault)
+    populatePatternsForOp<math::RoundEvenOp>(patterns, ctx, "nearbyintf",
+                                             "nearbyint");
+  // Roundeven: using nearbyint (pre-C23) for roundeven requires the
+  // rounding mode to be FE_TONEAREST (the default). Otherwise we need to
+  // issue a call to set the rounding mode (which this pass currently can't do).
   populatePatternsForOp<math::RoundOp>(patterns, ctx, "roundf", "round");
   populatePatternsForOp<math::SinOp>(patterns, ctx, "sinf", "sin");
   populatePatternsForOp<math::SinhOp>(patterns, ctx, "sinhf", "sinh");
@@ -199,6 +207,7 @@ void mlir::populateMathToLibmConversionPatterns(RewritePatternSet &patterns) {
 namespace {
 struct ConvertMathToLibmPass
     : public impl::ConvertMathToLibmBase<ConvertMathToLibmPass> {
+  using Base::Base;
   void runOnOperation() override;
 };
 } // namespace
@@ -207,7 +216,9 @@ void ConvertMathToLibmPass::runOnOperation() {
   auto module = getOperation();
 
   RewritePatternSet patterns(&getContext());
-  populateMathToLibmConversionPatterns(patterns);
+  populateMathToLibmConversionPatterns(
+      patterns, {/*allowC23Features=*/allowC23Features,
+                 /*roundingModeIsDefault=*/roundingModeIsDefault});
 
   ConversionTarget target(getContext());
   target.addLegalDialect<arith::ArithDialect, BuiltinDialect, func::FuncDialect,
@@ -220,3 +231,8 @@ void ConvertMathToLibmPass::runOnOperation() {
 std::unique_ptr<OperationPass<ModuleOp>> mlir::createConvertMathToLibmPass() {
   return std::make_unique<ConvertMathToLibmPass>();
 }
+
+std::unique_ptr<OperationPass<ModuleOp>>
+mlir::createConvertMathToLibmPass(const ConvertMathToLibmOptions &options) {
+  return std::make_unique<ConvertMathToLibmPass>(options);
+}
diff --git a/mlir/test/Conversion/MathToLibm/nearbyint.mlir b/mlir/test/Conversion/MathToLibm/nearbyint.mlir
new file mode 100644
index 00000000000000..82d03dab5d985e
--- /dev/null
+++ b/mlir/test/Conversion/MathToLibm/nearbyint.mlir
@@ -0,0 +1,41 @@
+// RUN: mlir-opt %s --pass-pipeline='builtin.module(convert-math-to-libm{allow-c23-features=0 rounding-mode-is-default}, canonicalize)' | FileCheck %s
+
+// CHECK-DAG: @nearbyint(f64) -> f64 attributes {libm, llvm.readnone}
+// CHECK-DAG: @nearbyintf(f32) -> f32 attributes {libm, llvm.readnone}
+
+// CHECK-LABEL: func @nearbyint_caller
+// CHECK-SAME: %[[FLOAT:.*]]: f32
+// CHECK-SAME: %[[DOUBLE:.*]]: f64
+func.func @nearbyint_caller(%float: f32, %double: f64) -> (f32, f64)  {
+  // CHECK-DAG: %[[FLOAT_RESULT:.*]] = call @nearbyintf(%[[FLOAT]]) : (f32) -> f32
+  %float_result = math.roundeven %float : f32
+  // CHECK-DAG: %[[DOUBLE_RESULT:.*]] = call @nearbyint(%[[DOUBLE]]) : (f64) -> f64
+  %double_result = math.roundeven %double : f64
+  // CHECK: return %[[FLOAT_RESULT]], %[[DOUBLE_RESULT]]
+  return %float_result, %double_result : f32, f64
+}
+
+// CHECK-LABEL:   func @nearbyint_vec_caller(
+// CHECK-SAME:                           %[[VAL_0:.*]]: vector<2xf32>,
+// CHECK-SAME:                           %[[VAL_1:.*]]: vector<2xf64>) -> (vector<2xf32>, vector<2xf64>) {
+// CHECK-DAG:       %[[CVF:.*]] = arith.constant dense<0.000000e+00> : vector<2xf32>
+// CHECK-DAG:       %[[CVD:.*]] = arith.constant dense<0.000000e+00> : vector<2xf64>
+// CHECK:           %[[IN0_F32:.*]] = vector.extract %[[VAL_0]][0] : f32 from vector<2xf32>
+// CHECK:           %[[OUT0_F32:.*]] = call @nearbyintf(%[[IN0_F32]]) : (f32) -> f32
+// CHECK:           %[[VAL_8:.*]] = vector.insert %[[OUT0_F32]], %[[CVF]] [0] : f32 into vector<2xf32>
+// CHECK:           %[[IN1_F32:.*]] = vector.extract %[[VAL_0]][1] : f32 from vector<2xf32>
+// CHECK:           %[[OUT1_F32:.*]] = call @nearbyintf(%[[IN1_F32]]) : (f32) -> f32
+// CHECK:           %[[VAL_11:.*]] = vector.insert %[[OUT1_F32]], %[[VAL_8]] [1] : f32 into vector<2xf32>
+// CHECK:           %[[IN0_F64:.*]] = vector.extract %[[VAL_1]][0] : f64 from vector<2xf64>
+// CHECK:           %[[OUT0_F64:.*]] = call @nearbyint(%[[IN0_F64]]) : (f64) -> f64
+// CHECK:           %[[VAL_14:.*]] = vector.insert %[[OUT0_F64]], %[[CVD]] [0] : f64 into vector<2xf64>
+// CHECK:           %[[IN1_F64:.*]] = vector.extract %[[VAL_1]][1] : f64 from vector<2xf64>
+// CHECK:           %[[OUT1_F64:.*]] = call @nearbyint(%[[IN1_F64]]) : (f64) -> f64
+// CHECK:           %[[VAL_17:.*]] = vector.insert %[[OUT1_F64]], %[[VAL_14]] [1] : f64 into vector<2xf64>
+// CHECK:           return %[[VAL_11]], %[[VAL_17]] : vector<2xf32>, vector<2xf64>
+// CHECK:         }
+func.func @nearbyint_vec_caller(%float: vector<2xf32>, %double: vector<2xf64>) -> (vector<2xf32>, vector<2xf64>) {
+  %float_result = math.roundeven %float : vector<2xf32>
+  %double_result = math.roundeven %double : vector<2xf64>
+  return %float_result, %double_result : vector<2xf32>, vector<2xf64>
+}
diff --git a/mlir/test/Conversion/MathToLibm/roundeven-failed.mlir b/mlir/test/Conversion/MathToLibm/roundeven-failed.mlir
new file mode 100644
index 00000000000000..d7aa976a496ba6
--- /dev/null
+++ b/mlir/test/Conversion/MathToLibm/roundeven-failed.mlir
@@ -0,0 +1,8 @@
+// RUN: mlir-opt %s --pass-pipeline='builtin.module(convert-math-to-libm{allow-c23-features=0 rounding-mode-is-default=0})' -verify-diagnostics
+
+func.func @nearbyint_caller(%float: f32, %double: f64) -> (f32, f64)  {
+  // expected-error at +1 {{failed to legalize operation 'math.roundeven'}}
+  %float_result = math.roundeven %float : f32
+  %double_result = math.roundeven %double : f64
+  return %float_result, %double_result : f32, f64
+}

>From b1a59eeea849b528b5056cf31b0272777e4d5b94 Mon Sep 17 00:00:00 2001
From: Corentin Ferry <corentin.ferry at amd.com>
Date: Mon, 15 Apr 2024 07:56:24 +0100
Subject: [PATCH 2/3] Fix flang usage of math conversion patterns

---
 flang/lib/Optimizer/CodeGen/CodeGen.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index d909bda89cdeb4..09c43878626b70 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3589,7 +3589,7 @@ class FIRToLLVMLowering
                                                           pattern);
     // Math operations that have not been converted yet must be converted
     // to Libm.
-    mlir::populateMathToLibmConversionPatterns(pattern);
+    mlir::populateMathToLibmConversionPatterns(typeConverter, pattern);
     mlir::populateComplexToLLVMConversionPatterns(typeConverter, pattern);
     mlir::populateVectorToLLVMConversionPatterns(typeConverter, pattern);
 

>From 260d0b488ccb0222f72e9fa94b5e5ef4418c18a0 Mon Sep 17 00:00:00 2001
From: Corentin Ferry <corentin.ferry at amd.com>
Date: Mon, 15 Apr 2024 07:56:53 +0100
Subject: [PATCH 3/3] Remove libm flag on MathToLibm emitted prototypes

---
 mlir/test/Conversion/MathToLibm/nearbyint.mlir | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mlir/test/Conversion/MathToLibm/nearbyint.mlir b/mlir/test/Conversion/MathToLibm/nearbyint.mlir
index 82d03dab5d985e..c8e293239de6e8 100644
--- a/mlir/test/Conversion/MathToLibm/nearbyint.mlir
+++ b/mlir/test/Conversion/MathToLibm/nearbyint.mlir
@@ -1,7 +1,7 @@
 // RUN: mlir-opt %s --pass-pipeline='builtin.module(convert-math-to-libm{allow-c23-features=0 rounding-mode-is-default}, canonicalize)' | FileCheck %s
 
-// CHECK-DAG: @nearbyint(f64) -> f64 attributes {libm, llvm.readnone}
-// CHECK-DAG: @nearbyintf(f32) -> f32 attributes {libm, llvm.readnone}
+// CHECK-DAG: @nearbyint(f64) -> f64 attributes {llvm.readnone}
+// CHECK-DAG: @nearbyintf(f32) -> f32 attributes {llvm.readnone}
 
 // CHECK-LABEL: func @nearbyint_caller
 // CHECK-SAME: %[[FLOAT:.*]]: f32



More information about the flang-commits mailing list