From d5bd00c0454a2c11db3adc47c1a91a0a318f49af Mon Sep 17 00:00:00 2001 From: Tomer Solomon Date: Tue, 22 Oct 2024 16:05:58 +0300 Subject: [PATCH 1/6] [mlir][EmitC] Add MathToEmitC pass for math function lowering to EmitC This commit introduces a new `MathToEmitC` conversion pass that lowers selected math operations to the `emitc.call_opaque` operation in the EmitC dialect. The supported math operations include: - math.floor -> emitc.call_opaque<"floor"> - math.exp -> emitc.call_opaque<"exp"> - math.cos -> emitc.call_opaque<"cos"> - math.sin -> emitc.call_opaque<"sin"> - math.ipowi -> emitc.call_opaque<"pow"> We chose to use `emitc.call_opaque` instead of `emitc.call` to better align with C-style function overloading. Unlike `emitc.call`, which requires unique type signatures, `emitc.call_opaque` allows us to call functions without specifying a unique type-based signature. This flexibility is essential for mimicking function overloading behavior as seen in ``. Additionally, the pass inserts an `emitc.include` operation to generate `#include ` at the top of the module to ensure the availability of the necessary math functions in the generated code. This pass enables the use of EmitC as an intermediate layer to generate C/C++ code with opaque calls to standard math functions. --- .../mlir/Conversion/MathToEmitC/MathToEmitC.h | 25 ++++ mlir/include/mlir/Conversion/Passes.h | 1 + mlir/include/mlir/Conversion/Passes.td | 19 +++ mlir/lib/Conversion/CMakeLists.txt | 1 + .../lib/Conversion/MathToEmitC/CMakeLists.txt | 19 +++ .../Conversion/MathToEmitC/MathToEmitC.cpp | 99 +++++++++++++ .../Conversion/MathToEmitC/math-to-emitc.mlir | 140 ++++++++++++++++++ .../llvm-project-overlay/mlir/BUILD.bazel | 22 +++ 8 files changed, 326 insertions(+) create mode 100644 mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h create mode 100644 mlir/lib/Conversion/MathToEmitC/CMakeLists.txt create mode 100644 mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp create mode 100644 mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h new file mode 100644 index 0000000000000..f2e8779b05793 --- /dev/null +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h @@ -0,0 +1,25 @@ +//===- MathToEmitC.h - Math to EmitC Pass -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H +#define MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H + +#include "mlir/IR/BuiltinOps.h" +#include "mlir/Pass/Pass.h" +#include + +namespace mlir { + +#define GEN_PASS_DECL_CONVERTMATHTOEMITC +#include "mlir/Conversion/Passes.h.inc" + +std::unique_ptr> createConvertMathToEmitCPass(); + +} // namespace mlir + +#endif // MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h index 2ab32836c80b1..54e795cd137d3 100644 --- a/mlir/include/mlir/Conversion/Passes.h +++ b/mlir/include/mlir/Conversion/Passes.h @@ -43,6 +43,7 @@ #include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h" #include "mlir/Conversion/IndexToSPIRV/IndexToSPIRV.h" #include "mlir/Conversion/LinalgToStandard/LinalgToStandard.h" +#include "mlir/Conversion/MathToEmitC/MathToEmitC.h" #include "mlir/Conversion/MathToFuncs/MathToFuncs.h" #include "mlir/Conversion/MathToLLVM/MathToLLVM.h" #include "mlir/Conversion/MathToLibm/MathToLibm.h" diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index 4d272ba219c6f..09a93439ab898 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -780,6 +780,25 @@ def ConvertMathToSPIRV : Pass<"convert-math-to-spirv"> { let dependentDialects = ["spirv::SPIRVDialect"]; } +//===----------------------------------------------------------------------===// +// MathToEmitC +//===----------------------------------------------------------------------===// + +def ConvertMathToEmitC : Pass<"convert-math-to-emitc", "ModuleOp"> { + let summary = "Convert some Math operations to EmitC Call_opaque"; + let description = [{ + This pass converts supported Math ops to call_opaque calls to compiler generated + functions implementing these operations in software. + Unlike convert-math-to-funcs pass, this pass uses call_opaque, + therefore enables us to overload the same funtion with different argument types + }]; + + let constructor = "mlir::createConvertMathToEmitCPass()"; + let dependentDialects = ["emitc::EmitCDialect", + "math::MathDialect" + ]; +} + //===----------------------------------------------------------------------===// // MathToFuncs //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt index 6651d87162257..120b4972454d5 100644 --- a/mlir/lib/Conversion/CMakeLists.txt +++ b/mlir/lib/Conversion/CMakeLists.txt @@ -33,6 +33,7 @@ add_subdirectory(IndexToLLVM) add_subdirectory(IndexToSPIRV) add_subdirectory(LinalgToStandard) add_subdirectory(LLVMCommon) +add_subdirectory(MathToEmitC) add_subdirectory(MathToFuncs) add_subdirectory(MathToLibm) add_subdirectory(MathToLLVM) diff --git a/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt new file mode 100644 index 0000000000000..7b02a57dff3d4 --- /dev/null +++ b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt @@ -0,0 +1,19 @@ +add_mlir_conversion_library(MLIRMathToEmitC + MathToEmitC.cpp + + ADDITIONAL_HEADER_DIRS + ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/MathToEmitC + + DEPENDS + MLIRConversionPassIncGen + + LINK_COMPONENTS + Core + + LINK_LIBS PUBLIC + MLIRLLVMCommonConversion + MLIREmitCDialect + MLIRMathDialect + MLIRPass + MLIRTransforms +) diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp new file mode 100644 index 0000000000000..43641a8ad634a --- /dev/null +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp @@ -0,0 +1,99 @@ + +//===- MathToEmitC.cpp - Math to EmitC Pass Implementation ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "mlir/Conversion/MathToEmitC/MathToEmitC.h" +#include "mlir/Dialect/EmitC/IR/EmitC.h" +#include "mlir/Dialect/Math/IR/Math.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" + +namespace mlir { +#define GEN_PASS_DEF_CONVERTMATHTOEMITC +#include "mlir/Conversion/Passes.h.inc" +} // namespace mlir + +using namespace mlir; +namespace { + +// Replaces Math operations with `emitc.call_opaque` operations. +struct ConvertMathToEmitCPass + : public impl::ConvertMathToEmitCBase { +public: + void runOnOperation() final; +}; + +} // end anonymous namespace + +template +class LowerToEmitCCallOpaque : public mlir::OpRewritePattern { + std::string calleeStr; + +public: + LowerToEmitCCallOpaque(MLIRContext *context, std::string calleeStr) + : OpRewritePattern(context), calleeStr(calleeStr) {} + + LogicalResult matchAndRewrite(OpType op, + PatternRewriter &rewriter) const override; +}; + +// Populates patterns to replace `math` operations with `emitc.call_opaque`, +// using function names consistent with those in . +static void populateConvertMathToEmitCPatterns(RewritePatternSet &patterns) { + auto *context = patterns.getContext(); + patterns.insert>(context, "floor"); + patterns.insert>(context, "rint"); + patterns.insert>(context, "exp"); + patterns.insert>(context, "cos"); + patterns.insert>(context, "sin"); + patterns.insert>(context, "acos"); + patterns.insert>(context, "asin"); + patterns.insert>(context, "atan2"); + patterns.insert>(context, "ceil"); + patterns.insert>(context, "fabs"); + patterns.insert>(context, "powf"); + patterns.insert>(context, "pow"); +} + +template +LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( + OpType op, PatternRewriter &rewriter) const { + mlir::StringAttr callee = rewriter.getStringAttr(calleeStr); + auto actualOp = mlir::cast(op); + rewriter.replaceOpWithNewOp( + actualOp, actualOp.getType(), callee, actualOp->getOperands()); + return mlir::success(); +} + +void ConvertMathToEmitCPass::runOnOperation() { + auto moduleOp = getOperation(); + // Insert #include at the beginning of the module + OpBuilder builder(moduleOp.getBodyRegion()); + builder.setInsertionPointToStart(&moduleOp.getBodyRegion().front()); + builder.create(moduleOp.getLoc(), + builder.getStringAttr("math.h")); + + ConversionTarget target(getContext()); + target.addLegalOp(); + + target.addIllegalOp(); + + RewritePatternSet patterns(&getContext()); + populateConvertMathToEmitCPatterns(patterns); + + if (failed(applyPartialConversion(moduleOp, target, std::move(patterns)))) + signalPassFailure(); +} + +std::unique_ptr> +mlir::createConvertMathToEmitCPass() { + return std::make_unique(); +} diff --git a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir new file mode 100644 index 0000000000000..9add25d71ef47 --- /dev/null +++ b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir @@ -0,0 +1,140 @@ +// RUN: mlir-opt --split-input-file -convert-math-to-emitc %s | FileCheck %s + +// CHECK-LABEL: emitc.include "math.h" + +// CHECK-LABEL: func.func @absf_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "fabs"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @absf_to_call_opaque(%arg0: f32) { + %1 = math.absf %arg0 : f32 + return + } + +// ----- + +// CHECK-LABEL: func.func @floor_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "floor"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @floor_to_call_opaque(%arg0: f32) { + %1 = math.floor %arg0 : f32 + return + } + +// ----- + +// CHECK-LABEL: func.func @sin_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "sin"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @sin_to_call_opaque(%arg0: f32) { + %1 = math.sin %arg0 : f32 + return + } + +// ----- + +// CHECK-LABEL: func.func @cos_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "cos"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @cos_to_call_opaque(%arg0: f32) { + %1 = math.cos %arg0 : f32 + return + } + + +// ----- + +// CHECK-LABEL: func.func @asin_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "asin"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @asin_to_call_opaque(%arg0: f32) { + %1 = math.asin %arg0 : f32 + return + } + +// ----- + +// CHECK-LABEL: func.func @acos_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "acos"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @acos_to_call_opaque(%arg0: f32) { + %1 = math.acos %arg0 : f32 + return + } + +// ----- + +// CHECK-LABEL: func.func @atan2_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32, +// CHECK-SAME: %[[VAL_1:.*]]: f32) { +// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "atan2"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 +// CHECK: return +// CHECK: } +func.func @atan2_to_call_opaque(%arg0: f32, %arg1: f32) { + %1 = math.atan2 %arg0, %arg1 : f32 + return + } + +// ----- + +// CHECK-LABEL: func.func @ceil_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "ceil"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @ceil_to_call_opaque(%arg0: f32) { + %1 = math.ceil %arg0 : f32 + return + } + +// ----- + +// CHECK-LABEL: func.func @exp_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32) { +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "exp"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: return +// CHECK: } +func.func @exp_to_call_opaque(%arg0: f32) { + %1 = math.exp %arg0 : f32 + return + } + + +// ----- + +// CHECK-LABEL: func.func @fpowi_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: f32, +// CHECK-SAME: %[[VAL_1:.*]]: i32) { +// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "powf"(%[[VAL_0]], %[[VAL_1]]) : (f32, i32) -> f32 +// CHECK: return +// CHECK: } +func.func @fpowi_to_call_opaque(%arg0: f32, %arg1: i32) { + %1 = math.fpowi %arg0, %arg1 : f32, i32 + return + } + +// ----- + +// CHECK-LABEL: func.func @ipowi_to_call_opaque( +// CHECK-SAME: %[[VAL_0:.*]]: i32, +// CHECK-SAME: %[[VAL_1:.*]]: i32) { +// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "pow"(%[[VAL_0]], %[[VAL_1]]) : (i32, i32) -> i32 +// CHECK: return +// CHECK: } +func.func @ipowi_to_call_opaque(%arg0: i32, %arg1: i32) { + %1 = math.ipowi %arg0, %arg1 : i32 + return + } + + diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel index 779609340d722..b193e4295e475 100644 --- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel @@ -4201,6 +4201,7 @@ cc_library( ":IndexToLLVM", ":IndexToSPIRV", ":LinalgToStandard", + ":MathToEmitC", ":MathToFuncs", ":MathToLLVM", ":MathToLibm", @@ -8721,6 +8722,27 @@ cc_library( ], ) +cc_library( + name = "MathToEmitC", + srcs = glob([ + "lib/Conversion/MathToEmitC/*.cpp", + ]), + hdrs = glob([ + "include/mlir/Conversion/MathToEmitC/*.h", + ]), + includes = [ + "include", + "lib/Conversion/MathToEmitC", + ], + deps = [ + ":ConversionPassIncGen", + ":EmitCDialect", + ":MathDialect", + ":Pass", + ":TransformUtils", + ], +) + cc_library( name = "MathToFuncs", srcs = glob(["lib/Conversion/MathToFuncs/*.cpp"]), From ad9af428683e8dba4d17a31b4193c709b15726c6 Mon Sep 17 00:00:00 2001 From: Tomer Solomon Date: Tue, 29 Oct 2024 11:47:39 +0200 Subject: [PATCH 2/6] [MLIR][MathToEmitC] Ensure scalar type handling and refactor This patch ensures that the MathToEmitC pass only converts scalar `FloatType`s, avoiding invalid conversions of non-scalar types like tensors. - **Validation:** Added checks to convert only scalar types. - **Refactoring:** Moved implementation to `MathToEmitCPass.cpp` and split headers. - **Testing:** Added test cases to ensure proper error handling for non-scalar types. --- .../mlir/Conversion/MathToEmitC/MathToEmitC.h | 10 +-- .../Conversion/MathToEmitC/MathToEmitCPass.h | 21 +++++ mlir/include/mlir/Conversion/Passes.h | 2 +- mlir/include/mlir/Conversion/Passes.td | 2 - .../lib/Conversion/MathToEmitC/CMakeLists.txt | 1 + .../Conversion/MathToEmitC/MathToEmitC.cpp | 84 ++++++------------- .../MathToEmitC/MathToEmitCPass.cpp | 58 +++++++++++++ .../Conversion/MathToEmitC/math-to-emitc.mlir | 31 +++---- 8 files changed, 120 insertions(+), 89 deletions(-) create mode 100644 mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h create mode 100644 mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h index f2e8779b05793..e2a8d59ffcd6b 100644 --- a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h @@ -9,16 +9,10 @@ #ifndef MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H #define MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H -#include "mlir/IR/BuiltinOps.h" -#include "mlir/Pass/Pass.h" -#include - namespace mlir { +class RewritePatternSet; -#define GEN_PASS_DECL_CONVERTMATHTOEMITC -#include "mlir/Conversion/Passes.h.inc" - -std::unique_ptr> createConvertMathToEmitCPass(); +void populateConvertMathToEmitCPatterns(RewritePatternSet &patterns); } // namespace mlir diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h new file mode 100644 index 0000000000000..5e92fba71b510 --- /dev/null +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h @@ -0,0 +1,21 @@ +//===- MathToEmitCPass.h - Math to EmitC Pass -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H +#define MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H + +#include + +namespace mlir { +class Pass; + +#define GEN_PASS_DECL_CONVERTMATHTOEMITC +#include "mlir/Conversion/Passes.h.inc" +} // namespace mlir + +#endif // MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H \ No newline at end of file diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h index 54e795cd137d3..6749cee0edccc 100644 --- a/mlir/include/mlir/Conversion/Passes.h +++ b/mlir/include/mlir/Conversion/Passes.h @@ -43,7 +43,7 @@ #include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h" #include "mlir/Conversion/IndexToSPIRV/IndexToSPIRV.h" #include "mlir/Conversion/LinalgToStandard/LinalgToStandard.h" -#include "mlir/Conversion/MathToEmitC/MathToEmitC.h" +#include "mlir/Conversion/MathToEmitC/MathToEmitCPass.h" #include "mlir/Conversion/MathToFuncs/MathToFuncs.h" #include "mlir/Conversion/MathToLLVM/MathToLLVM.h" #include "mlir/Conversion/MathToLibm/MathToLibm.h" diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index 09a93439ab898..20baaf40ead2f 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -792,8 +792,6 @@ def ConvertMathToEmitC : Pass<"convert-math-to-emitc", "ModuleOp"> { Unlike convert-math-to-funcs pass, this pass uses call_opaque, therefore enables us to overload the same funtion with different argument types }]; - - let constructor = "mlir::createConvertMathToEmitCPass()"; let dependentDialects = ["emitc::EmitCDialect", "math::MathDialect" ]; diff --git a/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt index 7b02a57dff3d4..8996869c0e7a5 100644 --- a/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt +++ b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt @@ -1,5 +1,6 @@ add_mlir_conversion_library(MLIRMathToEmitC MathToEmitC.cpp + MathToEmitCPass.cpp ADDITIONAL_HEADER_DIRS ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/MathToEmitC diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp index 43641a8ad634a..c5422c09c6c22 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp @@ -1,4 +1,3 @@ - //===- MathToEmitC.cpp - Math to EmitC Pass Implementation ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -8,43 +7,49 @@ //===----------------------------------------------------------------------===// #include "mlir/Conversion/MathToEmitC/MathToEmitC.h" + #include "mlir/Dialect/EmitC/IR/EmitC.h" #include "mlir/Dialect/Math/IR/Math.h" -#include "mlir/Pass/Pass.h" #include "mlir/Transforms/DialectConversion.h" -namespace mlir { -#define GEN_PASS_DEF_CONVERTMATHTOEMITC -#include "mlir/Conversion/Passes.h.inc" -} // namespace mlir - using namespace mlir; -namespace { - -// Replaces Math operations with `emitc.call_opaque` operations. -struct ConvertMathToEmitCPass - : public impl::ConvertMathToEmitCBase { -public: - void runOnOperation() final; -}; - -} // end anonymous namespace +namespace { template class LowerToEmitCCallOpaque : public mlir::OpRewritePattern { std::string calleeStr; public: LowerToEmitCCallOpaque(MLIRContext *context, std::string calleeStr) - : OpRewritePattern(context), calleeStr(calleeStr) {} + : OpRewritePattern(context), calleeStr(std::move(calleeStr)) {} LogicalResult matchAndRewrite(OpType op, PatternRewriter &rewriter) const override; }; +template +LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( + OpType op, PatternRewriter &rewriter) const { + auto actualOp = mlir::cast(op); + if (!llvm::all_of( + actualOp->getOperands(), + [](Value operand) { return isa(operand.getType()); }) || + !llvm::all_of(actualOp->getResultTypes(), + [](mlir::Type type) { return isa(type); })) { + op.emitError("non-float types are not supported"); + return mlir::failure(); + } + mlir::StringAttr callee = rewriter.getStringAttr(calleeStr); + rewriter.replaceOpWithNewOp( + actualOp, actualOp.getType(), callee, actualOp->getOperands()); + return mlir::success(); +} + +} // namespace + // Populates patterns to replace `math` operations with `emitc.call_opaque`, // using function names consistent with those in . -static void populateConvertMathToEmitCPatterns(RewritePatternSet &patterns) { +void mlir::populateConvertMathToEmitCPatterns(RewritePatternSet &patterns) { auto *context = patterns.getContext(); patterns.insert>(context, "floor"); patterns.insert>(context, "rint"); @@ -56,44 +61,5 @@ static void populateConvertMathToEmitCPatterns(RewritePatternSet &patterns) { patterns.insert>(context, "atan2"); patterns.insert>(context, "ceil"); patterns.insert>(context, "fabs"); - patterns.insert>(context, "powf"); - patterns.insert>(context, "pow"); -} - -template -LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( - OpType op, PatternRewriter &rewriter) const { - mlir::StringAttr callee = rewriter.getStringAttr(calleeStr); - auto actualOp = mlir::cast(op); - rewriter.replaceOpWithNewOp( - actualOp, actualOp.getType(), callee, actualOp->getOperands()); - return mlir::success(); -} - -void ConvertMathToEmitCPass::runOnOperation() { - auto moduleOp = getOperation(); - // Insert #include at the beginning of the module - OpBuilder builder(moduleOp.getBodyRegion()); - builder.setInsertionPointToStart(&moduleOp.getBodyRegion().front()); - builder.create(moduleOp.getLoc(), - builder.getStringAttr("math.h")); - - ConversionTarget target(getContext()); - target.addLegalOp(); - - target.addIllegalOp(); - - RewritePatternSet patterns(&getContext()); - populateConvertMathToEmitCPatterns(patterns); - - if (failed(applyPartialConversion(moduleOp, target, std::move(patterns)))) - signalPassFailure(); -} - -std::unique_ptr> -mlir::createConvertMathToEmitCPass() { - return std::make_unique(); + patterns.insert>(context, "pow"); } diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp new file mode 100644 index 0000000000000..6e0ea81b34a92 --- /dev/null +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp @@ -0,0 +1,58 @@ +//===- MathToEmitCPass.cpp - Math to EmitC Pass -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a pass to convert the Math dialect to the EmitC dialect. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Conversion/MathToEmitC/MathToEmitCPass.h" +#include "mlir/Conversion/MathToEmitC/MathToEmitC.h" +#include "mlir/Dialect/EmitC/IR/EmitC.h" +#include "mlir/Dialect/Math/IR/Math.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" + +namespace mlir { +#define GEN_PASS_DEF_CONVERTMATHTOEMITC +#include "mlir/Conversion/Passes.h.inc" +} // namespace mlir + +using namespace mlir; +namespace { + +// Replaces Math operations with `emitc.call_opaque` operations. +struct ConvertMathToEmitCPass + : public impl::ConvertMathToEmitCBase { +public: + void runOnOperation() final; +}; + +} // end anonymous namespace + +void ConvertMathToEmitCPass::runOnOperation() { + auto moduleOp = getOperation(); + // Insert #include at the beginning of the module + OpBuilder builder(moduleOp.getBodyRegion()); + builder.setInsertionPointToStart(&moduleOp.getBodyRegion().front()); + builder.create(moduleOp.getLoc(), + builder.getStringAttr("math.h")); + + ConversionTarget target(getContext()); + target.addLegalOp(); + + target.addIllegalOp(); + + RewritePatternSet patterns(&getContext()); + populateConvertMathToEmitCPatterns(patterns); + + if (failed(applyPartialConversion(moduleOp, target, std::move(patterns)))) + signalPassFailure(); +} \ No newline at end of file diff --git a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir index 9add25d71ef47..6cf8b53e73839 100644 --- a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir +++ b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir @@ -1,4 +1,4 @@ -// RUN: mlir-opt --split-input-file -convert-math-to-emitc %s | FileCheck %s +// RUN: mlir-opt --split-input-file -convert-math-to-emitc -verify-diagnostics %s | FileCheck %s // CHECK-LABEL: emitc.include "math.h" @@ -110,31 +110,24 @@ func.func @exp_to_call_opaque(%arg0: f32) { return } - // ----- -// CHECK-LABEL: func.func @fpowi_to_call_opaque( +// CHECK-LABEL: func.func @powf_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32, -// CHECK-SAME: %[[VAL_1:.*]]: i32) { -// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "powf"(%[[VAL_0]], %[[VAL_1]]) : (f32, i32) -> f32 +// CHECK-SAME: %[[VAL_1:.*]]: f32) { +// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "pow"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 // CHECK: return // CHECK: } -func.func @fpowi_to_call_opaque(%arg0: f32, %arg1: i32) { - %1 = math.fpowi %arg0, %arg1 : f32, i32 +func.func @powf_to_call_opaque(%arg0: f32, %arg1: f32) { + %1 = math.powf %arg0, %arg1 : f32 return } // ----- -// CHECK-LABEL: func.func @ipowi_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: i32, -// CHECK-SAME: %[[VAL_1:.*]]: i32) { -// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "pow"(%[[VAL_0]], %[[VAL_1]]) : (i32, i32) -> i32 -// CHECK: return -// CHECK: } -func.func @ipowi_to_call_opaque(%arg0: i32, %arg1: i32) { - %1 = math.ipowi %arg0, %arg1 : i32 - return - } - - +func.func @test(%arg0 : tensor<4xf32>) -> tensor<4xf32> { +// expected-error @+2 {{failed to legalize operation 'math.absf' that was explicitly marked illegal}} +// expected-error @+1 {{non-float types are not supported}} + %0 = math.absf %arg0 : tensor<4xf32> + return %0 : tensor<4xf32> +} \ No newline at end of file From f6c240675e6281552badf8ef1df16a66cfaa18eb Mon Sep 17 00:00:00 2001 From: Tomer Solomon Date: Tue, 29 Oct 2024 18:50:55 +0200 Subject: [PATCH 3/6] [MLIR][MathToEmitC] Refactor code, add tests for unsupported types, and restrict to f32 only Refactored code (added newlines and nits). Added tests to verify behavior with unsupported types. Now only f32 is supported. Deleted generation of emitc.include Changed the conversion to apply at the operation level instead of the module level. --- .../mlir/Conversion/MathToEmitC/MathToEmitC.h | 3 +- .../Conversion/MathToEmitC/MathToEmitCPass.h | 4 +- mlir/include/mlir/Conversion/Passes.td | 13 ++--- .../lib/Conversion/MathToEmitC/CMakeLists.txt | 1 - .../Conversion/MathToEmitC/MathToEmitC.cpp | 45 +++++++--------- .../MathToEmitC/MathToEmitCPass.cpp | 20 +++---- .../MathToEmitC/math-to-emitc-failed.mlir | 23 ++++++++ .../Conversion/MathToEmitC/math-to-emitc.mlir | 53 +++++-------------- 8 files changed, 69 insertions(+), 93 deletions(-) create mode 100644 mlir/test/Conversion/MathToEmitC/math-to-emitc-failed.mlir diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h index e2a8d59ffcd6b..9406909e2d853 100644 --- a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h @@ -1,4 +1,4 @@ -//===- MathToEmitC.h - Math to EmitC Pass -----------*- C++ -*-===// +//===- MathToEmitC.h - Math to EmitCPatterns -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,7 +13,6 @@ namespace mlir { class RewritePatternSet; void populateConvertMathToEmitCPatterns(RewritePatternSet &patterns); - } // namespace mlir #endif // MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h index 5e92fba71b510..6d5502a903042 100644 --- a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h @@ -1,4 +1,4 @@ -//===- MathToEmitCPass.h - Math to EmitC Pass -----------------*- C++ -*-===// +//===- MathToEmitCPass.h - Math to EmitC Pass -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -18,4 +18,4 @@ class Pass; #include "mlir/Conversion/Passes.h.inc" } // namespace mlir -#endif // MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H \ No newline at end of file +#endif // MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index 20baaf40ead2f..ea34b1b111bb6 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -784,17 +784,14 @@ def ConvertMathToSPIRV : Pass<"convert-math-to-spirv"> { // MathToEmitC //===----------------------------------------------------------------------===// -def ConvertMathToEmitC : Pass<"convert-math-to-emitc", "ModuleOp"> { +def ConvertMathToEmitC : Pass<"convert-math-to-emitc"> { let summary = "Convert some Math operations to EmitC Call_opaque"; let description = [{ - This pass converts supported Math ops to call_opaque calls to compiler generated - functions implementing these operations in software. - Unlike convert-math-to-funcs pass, this pass uses call_opaque, - therefore enables us to overload the same funtion with different argument types + This pass converts supported Math ops to `opaque_call` ops targeting libc/libm + functions. Unlike convert-math-to-funcs pass, converting to `call_opaque` ops + allows to overload the same function with different argument types. }]; - let dependentDialects = ["emitc::EmitCDialect", - "math::MathDialect" - ]; + let dependentDialects = ["emitc::EmitCDialect"]; } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt index 8996869c0e7a5..63850c08ec902 100644 --- a/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt +++ b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt @@ -12,7 +12,6 @@ add_mlir_conversion_library(MLIRMathToEmitC Core LINK_LIBS PUBLIC - MLIRLLVMCommonConversion MLIREmitCDialect MLIRMathDialect MLIRPass diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp index c5422c09c6c22..6bcb95b613dfe 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp @@ -1,4 +1,4 @@ -//===- MathToEmitC.cpp - Math to EmitC Pass Implementation ----------===// +//===- MathToEmitC.cpp - Math to EmitC Patterns ----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -16,7 +16,7 @@ using namespace mlir; namespace { template -class LowerToEmitCCallOpaque : public mlir::OpRewritePattern { +class LowerToEmitCCallOpaque : public OpRewritePattern { std::string calleeStr; public: @@ -30,19 +30,12 @@ class LowerToEmitCCallOpaque : public mlir::OpRewritePattern { template LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( OpType op, PatternRewriter &rewriter) const { - auto actualOp = mlir::cast(op); - if (!llvm::all_of( - actualOp->getOperands(), - [](Value operand) { return isa(operand.getType()); }) || - !llvm::all_of(actualOp->getResultTypes(), - [](mlir::Type type) { return isa(type); })) { - op.emitError("non-float types are not supported"); - return mlir::failure(); - } - mlir::StringAttr callee = rewriter.getStringAttr(calleeStr); - rewriter.replaceOpWithNewOp( - actualOp, actualOp.getType(), callee, actualOp->getOperands()); - return mlir::success(); + if (!llvm::all_of(op->getOperandTypes(), llvm::IsaPred)|| + !llvm::all_of(op->getResultTypes(),llvm::IsaPred)) + return rewriter.notifyMatchFailure(op.getLoc(), "expected all operands and results to be of type f32 or f64"); + rewriter.replaceOpWithNewOp( + op, op.getType(), calleeStr, op->getOperands()); + return success(); } } // namespace @@ -51,15 +44,15 @@ LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( // using function names consistent with those in . void mlir::populateConvertMathToEmitCPatterns(RewritePatternSet &patterns) { auto *context = patterns.getContext(); - patterns.insert>(context, "floor"); - patterns.insert>(context, "rint"); - patterns.insert>(context, "exp"); - patterns.insert>(context, "cos"); - patterns.insert>(context, "sin"); - patterns.insert>(context, "acos"); - patterns.insert>(context, "asin"); - patterns.insert>(context, "atan2"); - patterns.insert>(context, "ceil"); - patterns.insert>(context, "fabs"); - patterns.insert>(context, "pow"); + patterns.insert>(context, "floorf"); + patterns.insert>(context, "roundf"); + patterns.insert>(context, "expf"); + patterns.insert>(context, "cosf"); + patterns.insert>(context, "sinf"); + patterns.insert>(context, "acosf"); + patterns.insert>(context, "asinf"); + patterns.insert>(context, "atan2f"); + patterns.insert>(context, "ceilf"); + patterns.insert>(context, "fabsf"); + patterns.insert>(context, "powf"); } diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp index 6e0ea81b34a92..2e914b21555a1 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp @@ -26,33 +26,25 @@ using namespace mlir; namespace { // Replaces Math operations with `emitc.call_opaque` operations. -struct ConvertMathToEmitCPass - : public impl::ConvertMathToEmitCBase { +struct ConvertMathToEmitC + : public impl::ConvertMathToEmitCBase { public: void runOnOperation() final; }; } // end anonymous namespace -void ConvertMathToEmitCPass::runOnOperation() { - auto moduleOp = getOperation(); - // Insert #include at the beginning of the module - OpBuilder builder(moduleOp.getBodyRegion()); - builder.setInsertionPointToStart(&moduleOp.getBodyRegion().front()); - builder.create(moduleOp.getLoc(), - builder.getStringAttr("math.h")); - +void ConvertMathToEmitC::runOnOperation() { ConversionTarget target(getContext()); target.addLegalOp(); target.addIllegalOp(); + math::AcosOp, math::AsinOp, math::AbsFOp, math::PowFOp>(); RewritePatternSet patterns(&getContext()); populateConvertMathToEmitCPatterns(patterns); - if (failed(applyPartialConversion(moduleOp, target, std::move(patterns)))) + if (failed(applyPartialConversion(getOperation(), target, std::move(patterns)))) signalPassFailure(); -} \ No newline at end of file +} diff --git a/mlir/test/Conversion/MathToEmitC/math-to-emitc-failed.mlir b/mlir/test/Conversion/MathToEmitC/math-to-emitc-failed.mlir new file mode 100644 index 0000000000000..f1de97c5465a9 --- /dev/null +++ b/mlir/test/Conversion/MathToEmitC/math-to-emitc-failed.mlir @@ -0,0 +1,23 @@ +// RUN: mlir-opt -split-input-file -convert-math-to-emitc -verify-diagnostics %s + +func.func @unsupported_tensor_type(%arg0 : tensor<4xf32>) -> tensor<4xf32> { +// expected-error @+1 {{failed to legalize operation 'math.absf' that was explicitly marked illegal}} + %0 = math.absf %arg0 : tensor<4xf32> + return %0 : tensor<4xf32> +} + +// ----- + +func.func @unsupported_f16_type(%arg0 : f16) -> f16 { +// expected-error @+1 {{failed to legalize operation 'math.absf' that was explicitly marked illegal}} + %0 = math.absf %arg0 : f16 + return %0 : f16 +} + +// ----- + +func.func @unsupported_f128_type(%arg0 : f128) -> f128 { +// expected-error @+1 {{failed to legalize operation 'math.absf' that was explicitly marked illegal}} + %0 = math.absf %arg0 : f128 + return %0 : f128 +} diff --git a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir index 6cf8b53e73839..56ea1a958f124 100644 --- a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir +++ b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir @@ -1,34 +1,27 @@ -// RUN: mlir-opt --split-input-file -convert-math-to-emitc -verify-diagnostics %s | FileCheck %s +// RUN: mlir-opt -convert-math-to-emitc %s | FileCheck %s -// CHECK-LABEL: emitc.include "math.h" // CHECK-LABEL: func.func @absf_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "fabs"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "fabsf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @absf_to_call_opaque(%arg0: f32) { %1 = math.absf %arg0 : f32 return } - -// ----- - // CHECK-LABEL: func.func @floor_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "floor"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "floorf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @floor_to_call_opaque(%arg0: f32) { %1 = math.floor %arg0 : f32 return } - -// ----- - // CHECK-LABEL: func.func @sin_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "sin"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "sinf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @sin_to_call_opaque(%arg0: f32) { @@ -36,11 +29,9 @@ func.func @sin_to_call_opaque(%arg0: f32) { return } -// ----- - // CHECK-LABEL: func.func @cos_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "cos"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "cosf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @cos_to_call_opaque(%arg0: f32) { @@ -48,12 +39,9 @@ func.func @cos_to_call_opaque(%arg0: f32) { return } - -// ----- - // CHECK-LABEL: func.func @asin_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "asin"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "asinf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @asin_to_call_opaque(%arg0: f32) { @@ -61,11 +49,9 @@ func.func @asin_to_call_opaque(%arg0: f32) { return } -// ----- - // CHECK-LABEL: func.func @acos_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "acos"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "acosf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @acos_to_call_opaque(%arg0: f32) { @@ -73,12 +59,10 @@ func.func @acos_to_call_opaque(%arg0: f32) { return } -// ----- - // CHECK-LABEL: func.func @atan2_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32, // CHECK-SAME: %[[VAL_1:.*]]: f32) { -// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "atan2"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 +// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "atan2f"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 // CHECK: return // CHECK: } func.func @atan2_to_call_opaque(%arg0: f32, %arg1: f32) { @@ -86,11 +70,10 @@ func.func @atan2_to_call_opaque(%arg0: f32, %arg1: f32) { return } -// ----- // CHECK-LABEL: func.func @ceil_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "ceil"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "ceilf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @ceil_to_call_opaque(%arg0: f32) { @@ -98,11 +81,9 @@ func.func @ceil_to_call_opaque(%arg0: f32) { return } -// ----- - // CHECK-LABEL: func.func @exp_to_call_opaque( // CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "exp"(%[[VAL_0]]) : (f32) -> f32 +// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "expf"(%[[VAL_0]]) : (f32) -> f32 // CHECK: return // CHECK: } func.func @exp_to_call_opaque(%arg0: f32) { @@ -110,12 +91,11 @@ func.func @exp_to_call_opaque(%arg0: f32) { return } -// ----- // CHECK-LABEL: func.func @powf_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32, -// CHECK-SAME: %[[VAL_1:.*]]: f32) { -// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "pow"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 +// CHECK-SAME: %[[VAL_0:.*]]: f32, +// CHECK-SAME: %[[VAL_1:.*]]: f32) { +// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "powf"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 // CHECK: return // CHECK: } func.func @powf_to_call_opaque(%arg0: f32, %arg1: f32) { @@ -123,11 +103,4 @@ func.func @powf_to_call_opaque(%arg0: f32, %arg1: f32) { return } -// ----- -func.func @test(%arg0 : tensor<4xf32>) -> tensor<4xf32> { -// expected-error @+2 {{failed to legalize operation 'math.absf' that was explicitly marked illegal}} -// expected-error @+1 {{non-float types are not supported}} - %0 = math.absf %arg0 : tensor<4xf32> - return %0 : tensor<4xf32> -} \ No newline at end of file From 23ada46a9c6db4a4e3ee977bf1722414b7e43a7c Mon Sep 17 00:00:00 2001 From: Tomer Solomon Date: Thu, 31 Oct 2024 10:18:07 +0200 Subject: [PATCH 4/6] [MLIR][MathToEmitC] Add support for C and C++ targets with Lit tests C target: Generates specific callee names based on operand types by appending the appropriate suffix C++ target: Uses standard library functions with the std:: namespace Updated LIT tests --- .../mlir/Conversion/MathToEmitC/MathToEmitC.h | 5 +- .../Conversion/MathToEmitC/MathToEmitCPass.h | 2 +- mlir/include/mlir/Conversion/Passes.td | 8 ++ .../mlir/Dialect/EmitC/IR/EmitCAttributes.td | 9 ++ .../Conversion/MathToEmitC/MathToEmitC.cpp | 57 +++++++--- .../MathToEmitC/MathToEmitCPass.cpp | 6 +- .../Conversion/MathToEmitC/math-to-emitc.mlir | 105 ++++++------------ 7 files changed, 99 insertions(+), 93 deletions(-) diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h index 9406909e2d853..dd866768df6c4 100644 --- a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h @@ -8,11 +8,14 @@ #ifndef MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H #define MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H +#include "mlir/Dialect/EmitC/IR/EmitC.h" namespace mlir { class RewritePatternSet; -void populateConvertMathToEmitCPatterns(RewritePatternSet &patterns); +void populateConvertMathToEmitCPatterns( + RewritePatternSet &patterns, + emitc::MathToEmitCLanguageTarget languageTarget); } // namespace mlir #endif // MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h index 6d5502a903042..448ed48f31148 100644 --- a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h @@ -9,8 +9,8 @@ #ifndef MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H #define MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H +#include "mlir/Dialect/EmitC/IR/EmitC.h" #include - namespace mlir { class Pass; diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index ea34b1b111bb6..4b06cb34fc022 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -792,6 +792,14 @@ def ConvertMathToEmitC : Pass<"convert-math-to-emitc"> { allows to overload the same function with different argument types. }]; let dependentDialects = ["emitc::EmitCDialect"]; + let options = [ + Option<"languageTarget", "language-target", "::mlir::emitc::MathToEmitCLanguageTarget", + /*default=*/"::mlir::emitc::MathToEmitCLanguageTarget::CPP", "Select the language target for callees (C or CPP).", + [{::llvm::cl::values( + clEnumValN(::mlir::emitc::MathToEmitCLanguageTarget::C, "C", "C"), + clEnumValN(::mlir::emitc::MathToEmitCLanguageTarget::CPP, "CPP", "CPP") + )}]> + ]; } //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td index ea5e9efd5fa0b..6899bca3a57f9 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td @@ -62,4 +62,13 @@ def EmitC_OpaqueAttr : EmitC_Attr<"Opaque", "opaque"> { def EmitC_OpaqueOrTypedAttr : AnyAttrOf<[EmitC_OpaqueAttr, TypedAttrInterface]>; +def MathToEmitCLanguageTarget : I32EnumAttr<"MathToEmitCLanguageTarget", + "Specifies the language target for generating callees.", [ + I32EnumAttrCase<"C", 0, "Use C-style function names">, + I32EnumAttrCase<"CPP", 1, "Use C++-style function names"> + ]> { + let cppNamespace = "::mlir::emitc"; +} + + #endif // MLIR_DIALECT_EMITC_IR_EMITCATTRIBUTES diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp index 6bcb95b613dfe..d7f164950298b 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp @@ -18,10 +18,13 @@ namespace { template class LowerToEmitCCallOpaque : public OpRewritePattern { std::string calleeStr; + emitc::MathToEmitCLanguageTarget languageTarget; public: - LowerToEmitCCallOpaque(MLIRContext *context, std::string calleeStr) - : OpRewritePattern(context), calleeStr(std::move(calleeStr)) {} + LowerToEmitCCallOpaque(MLIRContext *context, std::string calleeStr, + emitc::MathToEmitCLanguageTarget languageTarget) + : OpRewritePattern(context), calleeStr(std::move(calleeStr)), + languageTarget(languageTarget) {} LogicalResult matchAndRewrite(OpType op, PatternRewriter &rewriter) const override; @@ -32,9 +35,18 @@ LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( OpType op, PatternRewriter &rewriter) const { if (!llvm::all_of(op->getOperandTypes(), llvm::IsaPred)|| !llvm::all_of(op->getResultTypes(),llvm::IsaPred)) - return rewriter.notifyMatchFailure(op.getLoc(), "expected all operands and results to be of type f32 or f64"); + return rewriter.notifyMatchFailure( + op.getLoc(), "expected all operands and results to be of type f32"); + std::string modifiedCalleeStr = calleeStr; + if (languageTarget == emitc::MathToEmitCLanguageTarget::CPP) { + modifiedCalleeStr = "std::" + calleeStr; + } else if (languageTarget == emitc::MathToEmitCLanguageTarget::C) { + auto operandType = op->getOperandTypes()[0]; + if (operandType.isF32()) + modifiedCalleeStr = calleeStr + "f"; + } rewriter.replaceOpWithNewOp( - op, op.getType(), calleeStr, op->getOperands()); + op, op.getType(), modifiedCalleeStr, op->getOperands()); return success(); } @@ -42,17 +54,30 @@ LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( // Populates patterns to replace `math` operations with `emitc.call_opaque`, // using function names consistent with those in . -void mlir::populateConvertMathToEmitCPatterns(RewritePatternSet &patterns) { +void mlir::populateConvertMathToEmitCPatterns( + RewritePatternSet &patterns, + emitc::MathToEmitCLanguageTarget languageTarget) { auto *context = patterns.getContext(); - patterns.insert>(context, "floorf"); - patterns.insert>(context, "roundf"); - patterns.insert>(context, "expf"); - patterns.insert>(context, "cosf"); - patterns.insert>(context, "sinf"); - patterns.insert>(context, "acosf"); - patterns.insert>(context, "asinf"); - patterns.insert>(context, "atan2f"); - patterns.insert>(context, "ceilf"); - patterns.insert>(context, "fabsf"); - patterns.insert>(context, "powf"); + patterns.insert>(context, "floor", + languageTarget); + patterns.insert>(context, "round", + languageTarget); + patterns.insert>(context, "exp", + languageTarget); + patterns.insert>(context, "cos", + languageTarget); + patterns.insert>(context, "sin", + languageTarget); + patterns.insert>(context, "acos", + languageTarget); + patterns.insert>(context, "asin", + languageTarget); + patterns.insert>(context, "atan2", + languageTarget); + patterns.insert>(context, "ceil", + languageTarget); + patterns.insert>(context, "fabs", + languageTarget); + patterns.insert>(context, "pow", + languageTarget); } diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp index 2e914b21555a1..3b345d7667083 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp @@ -28,11 +28,13 @@ namespace { // Replaces Math operations with `emitc.call_opaque` operations. struct ConvertMathToEmitC : public impl::ConvertMathToEmitCBase { + using ConvertMathToEmitCBase::ConvertMathToEmitCBase; + public: void runOnOperation() final; }; -} // end anonymous namespace +} // namespace void ConvertMathToEmitC::runOnOperation() { ConversionTarget target(getContext()); @@ -43,7 +45,7 @@ void ConvertMathToEmitC::runOnOperation() { math::AcosOp, math::AsinOp, math::AbsFOp, math::PowFOp>(); RewritePatternSet patterns(&getContext()); - populateConvertMathToEmitCPatterns(patterns); + populateConvertMathToEmitCPatterns(patterns, languageTarget); if (failed(applyPartialConversion(getOperation(), target, std::move(patterns)))) signalPassFailure(); diff --git a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir index 56ea1a958f124..95b25e5859043 100644 --- a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir +++ b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir @@ -1,105 +1,64 @@ -// RUN: mlir-opt -convert-math-to-emitc %s | FileCheck %s +// RUN: mlir-opt -convert-math-to-emitc=language-target=C %s | FileCheck %s --check-prefix=C +// RUN: mlir-opt -convert-math-to-emitc=language-target=CPP %s | FileCheck %s --check-prefix=CPP - -// CHECK-LABEL: func.func @absf_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "fabsf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } func.func @absf_to_call_opaque(%arg0: f32) { + // C: emitc.call_opaque "fabsf" + // CPP: emitc.call_opaque "std::fabs" %1 = math.absf %arg0 : f32 return } -// CHECK-LABEL: func.func @floor_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "floorf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } func.func @floor_to_call_opaque(%arg0: f32) { + // C: emitc.call_opaque "floorf" + // CPP: emitc.call_opaque "std::floor" %1 = math.floor %arg0 : f32 return } -// CHECK-LABEL: func.func @sin_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "sinf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } func.func @sin_to_call_opaque(%arg0: f32) { + // C: emitc.call_opaque "sinf" + // CPP: emitc.call_opaque "std::sin" %1 = math.sin %arg0 : f32 return } - -// CHECK-LABEL: func.func @cos_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "cosf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } func.func @cos_to_call_opaque(%arg0: f32) { + // C: emitc.call_opaque "cosf" + // CPP: emitc.call_opaque "std::cos" %1 = math.cos %arg0 : f32 return } - -// CHECK-LABEL: func.func @asin_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "asinf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } func.func @asin_to_call_opaque(%arg0: f32) { + // C: emitc.call_opaque "asinf" + // CPP: emitc.call_opaque "std::asin" %1 = math.asin %arg0 : f32 return } - -// CHECK-LABEL: func.func @acos_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "acosf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } -func.func @acos_to_call_opaque(%arg0: f32) { - %1 = math.acos %arg0 : f32 +func.func @acos_to_call_opaque(%arg0: f64) { + // C: emitc.call_opaque "acos" + // CPP: emitc.call_opaque "std::acos" + %1 = math.acos %arg0 : f64 return } - -// CHECK-LABEL: func.func @atan2_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32, -// CHECK-SAME: %[[VAL_1:.*]]: f32) { -// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "atan2f"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 -// CHECK: return -// CHECK: } -func.func @atan2_to_call_opaque(%arg0: f32, %arg1: f32) { - %1 = math.atan2 %arg0, %arg1 : f32 +func.func @atan2_to_call_opaque(%arg0: f64, %arg1: f64) { + // C: emitc.call_opaque "atan2" + // CPP: emitc.call_opaque "std::atan2" + %1 = math.atan2 %arg0, %arg1 : f64 return } - - -// CHECK-LABEL: func.func @ceil_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "ceilf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } -func.func @ceil_to_call_opaque(%arg0: f32) { - %1 = math.ceil %arg0 : f32 +func.func @ceil_to_call_opaque(%arg0: f64) { + // C: emitc.call_opaque "ceil" + // CPP: emitc.call_opaque "std::ceil" + %1 = math.ceil %arg0 : f64 return } - -// CHECK-LABEL: func.func @exp_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32) { -// CHECK: %[[VAL_1:.*]] = emitc.call_opaque "expf"(%[[VAL_0]]) : (f32) -> f32 -// CHECK: return -// CHECK: } -func.func @exp_to_call_opaque(%arg0: f32) { - %1 = math.exp %arg0 : f32 +func.func @exp_to_call_opaque(%arg0: f64) { + // C: emitc.call_opaque "exp" + // CPP: emitc.call_opaque "std::exp" + %1 = math.exp %arg0 : f64 return } - - -// CHECK-LABEL: func.func @powf_to_call_opaque( -// CHECK-SAME: %[[VAL_0:.*]]: f32, -// CHECK-SAME: %[[VAL_1:.*]]: f32) { -// CHECK: %[[VAL_2:.*]] = emitc.call_opaque "powf"(%[[VAL_0]], %[[VAL_1]]) : (f32, f32) -> f32 -// CHECK: return -// CHECK: } -func.func @powf_to_call_opaque(%arg0: f32, %arg1: f32) { - %1 = math.powf %arg0, %arg1 : f32 +func.func @powf_to_call_opaque(%arg0: f64, %arg1: f64) { + // C: emitc.call_opaque "pow" + // CPP: emitc.call_opaque "std::pow" + %1 = math.powf %arg0, %arg1 : f64 return } From 8992fd51687cac4ffe2a332406ccc01b9914a1fc Mon Sep 17 00:00:00 2001 From: Tomer Solomon Date: Wed, 20 Nov 2024 16:25:22 +0200 Subject: [PATCH 5/6] [MLIR][MathToEmitC] Add language standard option, create LanguageTarget enum class - Created LanguageTarget enum class in MathToEmitC.h. An enum that specifies the language target for code generation. - Added language standard target option (c99, cpp11): allowing users to choose between C99 and C++11. --- .../mlir/Conversion/MathToEmitC/MathToEmitC.h | 14 +- .../Conversion/MathToEmitC/MathToEmitCPass.h | 2 +- mlir/include/mlir/Conversion/Passes.td | 12 +- .../mlir/Dialect/EmitC/IR/EmitCAttributes.td | 9 -- .../lib/Conversion/MathToEmitC/CMakeLists.txt | 2 +- .../Conversion/MathToEmitC/MathToEmitC.cpp | 16 +- .../MathToEmitC/MathToEmitCPass.cpp | 6 +- .../Conversion/MathToEmitC/math-to-emitc.mlir | 153 ++++++++++++------ 8 files changed, 128 insertions(+), 86 deletions(-) diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h index dd866768df6c4..0fc33bf790be4 100644 --- a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitC.h @@ -1,4 +1,4 @@ -//===- MathToEmitC.h - Math to EmitCPatterns -------------------*- C++ -*-===// +//===- MathToEmitC.h - Math to EmitC Patterns -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,13 +9,17 @@ #ifndef MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H #define MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H #include "mlir/Dialect/EmitC/IR/EmitC.h" - namespace mlir { class RewritePatternSet; +namespace emitc { + +/// Enum to specify the language target for EmitC code generation. +enum class LanguageTarget { c99, cpp11 }; + +} // namespace emitc -void populateConvertMathToEmitCPatterns( - RewritePatternSet &patterns, - emitc::MathToEmitCLanguageTarget languageTarget); +void populateConvertMathToEmitCPatterns(RewritePatternSet &patterns, + emitc::LanguageTarget languageTarget); } // namespace mlir #endif // MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITC_H diff --git a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h index 448ed48f31148..c3861db7764c3 100644 --- a/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h +++ b/mlir/include/mlir/Conversion/MathToEmitC/MathToEmitCPass.h @@ -9,7 +9,7 @@ #ifndef MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H #define MLIR_CONVERSION_MATHTOEMITC_MATHTOEMITCPASS_H -#include "mlir/Dialect/EmitC/IR/EmitC.h" +#include "mlir/Conversion/MathToEmitC/MathToEmitC.h" #include namespace mlir { class Pass; diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index 4b06cb34fc022..4d4b3390b0de6 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -785,19 +785,19 @@ def ConvertMathToSPIRV : Pass<"convert-math-to-spirv"> { //===----------------------------------------------------------------------===// def ConvertMathToEmitC : Pass<"convert-math-to-emitc"> { - let summary = "Convert some Math operations to EmitC Call_opaque"; + let summary = "Convert some Math operations to EmitC call_opaque operations"; let description = [{ - This pass converts supported Math ops to `opaque_call` ops targeting libc/libm + This pass converts supported Math ops to `call_opaque` ops targeting libc/libm functions. Unlike convert-math-to-funcs pass, converting to `call_opaque` ops allows to overload the same function with different argument types. }]; let dependentDialects = ["emitc::EmitCDialect"]; let options = [ - Option<"languageTarget", "language-target", "::mlir::emitc::MathToEmitCLanguageTarget", - /*default=*/"::mlir::emitc::MathToEmitCLanguageTarget::CPP", "Select the language target for callees (C or CPP).", + Option<"languageTarget", "language-target", "::mlir::emitc::LanguageTarget", + /*default=*/"::mlir::emitc::LanguageTarget::c99", "Select the language standard target for callees (c99 or cpp11).", [{::llvm::cl::values( - clEnumValN(::mlir::emitc::MathToEmitCLanguageTarget::C, "C", "C"), - clEnumValN(::mlir::emitc::MathToEmitCLanguageTarget::CPP, "CPP", "CPP") + clEnumValN(::mlir::emitc::LanguageTarget::c99, "c99", "c99"), + clEnumValN(::mlir::emitc::LanguageTarget::cpp11, "cpp11", "cpp11") )}]> ]; } diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td index 6899bca3a57f9..ea5e9efd5fa0b 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td @@ -62,13 +62,4 @@ def EmitC_OpaqueAttr : EmitC_Attr<"Opaque", "opaque"> { def EmitC_OpaqueOrTypedAttr : AnyAttrOf<[EmitC_OpaqueAttr, TypedAttrInterface]>; -def MathToEmitCLanguageTarget : I32EnumAttr<"MathToEmitCLanguageTarget", - "Specifies the language target for generating callees.", [ - I32EnumAttrCase<"C", 0, "Use C-style function names">, - I32EnumAttrCase<"CPP", 1, "Use C++-style function names"> - ]> { - let cppNamespace = "::mlir::emitc"; -} - - #endif // MLIR_DIALECT_EMITC_IR_EMITCATTRIBUTES diff --git a/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt index 63850c08ec902..12a99c31e2ba5 100644 --- a/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt +++ b/mlir/lib/Conversion/MathToEmitC/CMakeLists.txt @@ -15,5 +15,5 @@ add_mlir_conversion_library(MLIRMathToEmitC MLIREmitCDialect MLIRMathDialect MLIRPass - MLIRTransforms + MLIRTransformUtils ) diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp index d7f164950298b..34e1c7ffd97f3 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp @@ -1,4 +1,4 @@ -//===- MathToEmitC.cpp - Math to EmitC Patterns ----------------*- C++ -*-===// +//===- MathToEmitC.cpp - Math to EmitC Patterns -----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -18,11 +18,11 @@ namespace { template class LowerToEmitCCallOpaque : public OpRewritePattern { std::string calleeStr; - emitc::MathToEmitCLanguageTarget languageTarget; + emitc::LanguageTarget languageTarget; public: LowerToEmitCCallOpaque(MLIRContext *context, std::string calleeStr, - emitc::MathToEmitCLanguageTarget languageTarget) + emitc::LanguageTarget languageTarget) : OpRewritePattern(context), calleeStr(std::move(calleeStr)), languageTarget(languageTarget) {} @@ -36,11 +36,12 @@ LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( if (!llvm::all_of(op->getOperandTypes(), llvm::IsaPred)|| !llvm::all_of(op->getResultTypes(),llvm::IsaPred)) return rewriter.notifyMatchFailure( - op.getLoc(), "expected all operands and results to be of type f32"); + op.getLoc(), + "expected all operands and results to be of type f32 or f64"); std::string modifiedCalleeStr = calleeStr; - if (languageTarget == emitc::MathToEmitCLanguageTarget::CPP) { + if (languageTarget == emitc::LanguageTarget::cpp11) { modifiedCalleeStr = "std::" + calleeStr; - } else if (languageTarget == emitc::MathToEmitCLanguageTarget::C) { + } else if (languageTarget == emitc::LanguageTarget::c99) { auto operandType = op->getOperandTypes()[0]; if (operandType.isF32()) modifiedCalleeStr = calleeStr + "f"; @@ -55,8 +56,7 @@ LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( // Populates patterns to replace `math` operations with `emitc.call_opaque`, // using function names consistent with those in . void mlir::populateConvertMathToEmitCPatterns( - RewritePatternSet &patterns, - emitc::MathToEmitCLanguageTarget languageTarget) { + RewritePatternSet &patterns, emitc::LanguageTarget languageTarget) { auto *context = patterns.getContext(); patterns.insert>(context, "floor", languageTarget); diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp index 3b345d7667083..114277e23c9f9 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp @@ -40,9 +40,9 @@ void ConvertMathToEmitC::runOnOperation() { ConversionTarget target(getContext()); target.addLegalOp(); - target.addIllegalOp(); + target.addIllegalOp(); RewritePatternSet patterns(&getContext()); populateConvertMathToEmitCPatterns(patterns, languageTarget); diff --git a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir index 95b25e5859043..111d93de1accb 100644 --- a/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir +++ b/mlir/test/Conversion/MathToEmitC/math-to-emitc.mlir @@ -1,65 +1,112 @@ -// RUN: mlir-opt -convert-math-to-emitc=language-target=C %s | FileCheck %s --check-prefix=C -// RUN: mlir-opt -convert-math-to-emitc=language-target=CPP %s | FileCheck %s --check-prefix=CPP +// RUN: mlir-opt -convert-math-to-emitc=language-target=c99 %s | FileCheck %s --check-prefix=c99 +// RUN: mlir-opt -convert-math-to-emitc=language-target=cpp11 %s | FileCheck %s --check-prefix=cpp11 -func.func @absf_to_call_opaque(%arg0: f32) { - // C: emitc.call_opaque "fabsf" - // CPP: emitc.call_opaque "std::fabs" - %1 = math.absf %arg0 : f32 +func.func @absf(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "fabsf" + // c99-NEXT: emitc.call_opaque "fabs" + // cpp11: emitc.call_opaque "std::fabs" + // cpp11-NEXT: emitc.call_opaque "std::fabs" + %0 = math.absf %arg0 : f32 + %1 = math.absf %arg1 : f64 return - } -func.func @floor_to_call_opaque(%arg0: f32) { - // C: emitc.call_opaque "floorf" - // CPP: emitc.call_opaque "std::floor" - %1 = math.floor %arg0 : f32 - return - } -func.func @sin_to_call_opaque(%arg0: f32) { - // C: emitc.call_opaque "sinf" - // CPP: emitc.call_opaque "std::sin" - %1 = math.sin %arg0 : f32 +} + +func.func @floor(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "floorf" + // c99-NEXT: emitc.call_opaque "floor" + // cpp11: emitc.call_opaque "std::floor" + // cpp11-NEXT: emitc.call_opaque "std::floor" + %0 = math.floor %arg0 : f32 + %1 = math.floor %arg1 : f64 return - } -func.func @cos_to_call_opaque(%arg0: f32) { - // C: emitc.call_opaque "cosf" - // CPP: emitc.call_opaque "std::cos" - %1 = math.cos %arg0 : f32 +} + +func.func @sin(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "sinf" + // c99-NEXT: emitc.call_opaque "sin" + // cpp11: emitc.call_opaque "std::sin" + // cpp11-NEXT: emitc.call_opaque "std::sin" + %0 = math.sin %arg0 : f32 + %1 = math.sin %arg1 : f64 return - } -func.func @asin_to_call_opaque(%arg0: f32) { - // C: emitc.call_opaque "asinf" - // CPP: emitc.call_opaque "std::asin" - %1 = math.asin %arg0 : f32 +} + +func.func @cos(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "cosf" + // c99-NEXT: emitc.call_opaque "cos" + // cpp11: emitc.call_opaque "std::cos" + // cpp11-NEXT: emitc.call_opaque "std::cos" + %0 = math.cos %arg0 : f32 + %1 = math.cos %arg1 : f64 return - } -func.func @acos_to_call_opaque(%arg0: f64) { - // C: emitc.call_opaque "acos" - // CPP: emitc.call_opaque "std::acos" - %1 = math.acos %arg0 : f64 +} + +func.func @asin(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "asinf" + // c99-NEXT: emitc.call_opaque "asin" + // cpp11: emitc.call_opaque "std::asin" + // cpp11-NEXT: emitc.call_opaque "std::asin" + %0 = math.asin %arg0 : f32 + %1 = math.asin %arg1 : f64 return - } -func.func @atan2_to_call_opaque(%arg0: f64, %arg1: f64) { - // C: emitc.call_opaque "atan2" - // CPP: emitc.call_opaque "std::atan2" - %1 = math.atan2 %arg0, %arg1 : f64 +} + +func.func @acos(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "acosf" + // c99-NEXT: emitc.call_opaque "acos" + // cpp11: emitc.call_opaque "std::acos" + // cpp11-NEXT: emitc.call_opaque "std::acos" + %0 = math.acos %arg0 : f32 + %1 = math.acos %arg1 : f64 return - } -func.func @ceil_to_call_opaque(%arg0: f64) { - // C: emitc.call_opaque "ceil" - // CPP: emitc.call_opaque "std::ceil" - %1 = math.ceil %arg0 : f64 +} + +func.func @atan2(%arg0: f32, %arg1: f32, %arg2: f64, %arg3: f64) { + // c99: emitc.call_opaque "atan2f" + // c99-NEXT: emitc.call_opaque "atan2" + // cpp11: emitc.call_opaque "std::atan2" + // cpp11-NEXT: emitc.call_opaque "std::atan2" + %0 = math.atan2 %arg0, %arg1 : f32 + %1 = math.atan2 %arg2, %arg3 : f64 return - } -func.func @exp_to_call_opaque(%arg0: f64) { - // C: emitc.call_opaque "exp" - // CPP: emitc.call_opaque "std::exp" - %1 = math.exp %arg0 : f64 +} + +func.func @ceil(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "ceilf" + // c99-NEXT: emitc.call_opaque "ceil" + // cpp11: emitc.call_opaque "std::ceil" + // cpp11-NEXT: emitc.call_opaque "std::ceil" + %0 = math.ceil %arg0 : f32 + %1 = math.ceil %arg1 : f64 return - } -func.func @powf_to_call_opaque(%arg0: f64, %arg1: f64) { - // C: emitc.call_opaque "pow" - // CPP: emitc.call_opaque "std::pow" - %1 = math.powf %arg0, %arg1 : f64 +} + +func.func @exp(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "expf" + // c99-NEXT: emitc.call_opaque "exp" + // cpp11: emitc.call_opaque "std::exp" + // cpp11-NEXT: emitc.call_opaque "std::exp" + %0 = math.exp %arg0 : f32 + %1 = math.exp %arg1 : f64 return - } +} +func.func @powf(%arg0: f32, %arg1: f32, %arg2: f64, %arg3: f64) { + // c99: emitc.call_opaque "powf" + // c99-NEXT: emitc.call_opaque "pow" + // cpp11: emitc.call_opaque "std::pow" + // cpp11-NEXT: emitc.call_opaque "std::pow" + %0 = math.powf %arg0, %arg1 : f32 + %1 = math.powf %arg2, %arg3 : f64 + return +} +func.func @round(%arg0: f32, %arg1: f64) { + // c99: emitc.call_opaque "roundf" + // c99-NEXT: emitc.call_opaque "round" + // cpp11: emitc.call_opaque "std::round" + // cpp11-NEXT: emitc.call_opaque "std::round" + %0 = math.round %arg0 : f32 + %1 = math.round %arg1 : f64 + return +} From 52c35a60801525026c0ac21deefd1335457fc4a6 Mon Sep 17 00:00:00 2001 From: Tomer Solomon Date: Sat, 18 Jan 2025 11:59:46 +0200 Subject: [PATCH 6/6] [mlir][EmitC] Apply formatting fixes --- mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp | 6 ++++-- mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp index 34e1c7ffd97f3..9a0651a5445e6 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitC.cpp @@ -33,8 +33,10 @@ class LowerToEmitCCallOpaque : public OpRewritePattern { template LogicalResult LowerToEmitCCallOpaque::matchAndRewrite( OpType op, PatternRewriter &rewriter) const { - if (!llvm::all_of(op->getOperandTypes(), llvm::IsaPred)|| - !llvm::all_of(op->getResultTypes(),llvm::IsaPred)) + if (!llvm::all_of(op->getOperandTypes(), + llvm::IsaPred) || + !llvm::all_of(op->getResultTypes(), + llvm::IsaPred)) return rewriter.notifyMatchFailure( op.getLoc(), "expected all operands and results to be of type f32 or f64"); diff --git a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp index 114277e23c9f9..87a27644210fa 100644 --- a/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp +++ b/mlir/lib/Conversion/MathToEmitC/MathToEmitCPass.cpp @@ -47,6 +47,7 @@ void ConvertMathToEmitC::runOnOperation() { RewritePatternSet patterns(&getContext()); populateConvertMathToEmitCPatterns(patterns, languageTarget); - if (failed(applyPartialConversion(getOperation(), target, std::move(patterns)))) + if (failed( + applyPartialConversion(getOperation(), target, std::move(patterns)))) signalPassFailure(); }