Index: flang/include/flang/Optimizer/Support/InitFIR.h =================================================================== --- flang/include/flang/Optimizer/Support/InitFIR.h +++ flang/include/flang/Optimizer/Support/InitFIR.h @@ -81,6 +81,7 @@ mlir::registerAffineDataCopyGenerationPass(); mlir::registerConvertAffineToStandardPass(); + mlir::registerConvertMathToFuncsPass(); } /// Register the interfaces needed to lower to LLVM IR. Index: flang/include/flang/Tools/CLOptions.inc =================================================================== --- flang/include/flang/Tools/CLOptions.inc +++ flang/include/flang/Tools/CLOptions.inc @@ -9,6 +9,7 @@ /// This file defines some shared command-line options that can be used when /// debugging the test tools. This file must be included into the tool. +#include "mlir/Conversion/MathToFuncs/MathToFuncs.h" #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" #include "mlir/Pass/PassManager.h" #include "mlir/Transforms/GreedyPatternRewriteDriver.h" @@ -130,6 +131,8 @@ inline void addFIRToLLVMPass(mlir::PassManager &pm) { fir::FIRToLLVMPassOptions options; options.ignoreMissingTypeDescriptors = ignoreMissingTypeDescriptors; + addPassConditionally(pm, disableFirToLlvmIr, + [&]() { return mlir::createConvertMathToFuncsPass(); }); addPassConditionally(pm, disableFirToLlvmIr, [&]() { return fir::createFIRToLLVMPass(options); }); } Index: flang/lib/Lower/IntrinsicCall.cpp =================================================================== --- flang/lib/Lower/IntrinsicCall.cpp +++ flang/lib/Lower/IntrinsicCall.cpp @@ -1153,6 +1153,12 @@ return mlir::FunctionType::get(context, {itype, ftype}, {ftype}); } +template +static mlir::FunctionType genIntIntIntFuncType(mlir::MLIRContext *context) { + auto itype = mlir::IntegerType::get(context, Bits); + return mlir::FunctionType::get(context, {itype, itype}, {itype}); +} + /// Callback type for generating lowering for a math operation. using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location, llvm::StringRef, mlir::FunctionType, @@ -1220,7 +1226,12 @@ // can be also lowered to libm calls for "fast" and "relaxed" // modes. mlir::Value result; - if (mathRuntimeVersion == preciseVersion) { + if (mathRuntimeVersion == preciseVersion && + // Some operations do not have to be lowered as conservative + // calls, since they do not affect strict FP behavior. + // For example, purely integer operations like exponentiation + // with integer operands fall into this class. + !mathLibFuncName.empty()) { result = genLibCall(builder, loc, mathLibFuncName, mathLibFuncType, args); } else { LLVM_DEBUG(llvm::dbgs() << "Generating '" << mathLibFuncName @@ -1310,6 +1321,10 @@ {"nint", "llvm.lround.i64.f32", genIntF32FuncType<64>, genLibCall}, {"nint", "llvm.lround.i32.f64", genIntF64FuncType<32>, genLibCall}, {"nint", "llvm.lround.i32.f32", genIntF32FuncType<32>, genLibCall}, + {"pow", {}, genIntIntIntFuncType<8>, genMathOp}, + {"pow", {}, genIntIntIntFuncType<16>, genMathOp}, + {"pow", {}, genIntIntIntFuncType<32>, genMathOp}, + {"pow", {}, genIntIntIntFuncType<64>, genMathOp}, {"pow", "powf", genF32F32F32FuncType, genMathOp}, {"pow", "pow", genF64F64F64FuncType, genMathOp}, // TODO: add PowIOp in math and complex dialects. Index: flang/lib/Optimizer/Support/CMakeLists.txt =================================================================== --- flang/lib/Optimizer/Support/CMakeLists.txt +++ flang/lib/Optimizer/Support/CMakeLists.txt @@ -11,9 +11,10 @@ MLIRIR ${dialect_libs} - LINK_LIBS + LINK_LIBS PUBLIC ${dialect_libs} MLIROpenMPToLLVMIRTranslation MLIRLLVMToLLVMIRTranslation + MLIRMathToFuncs MLIRTargetLLVMIRExport ) Index: flang/test/Driver/mlir-pass-pipeline.f90 =================================================================== --- flang/test/Driver/mlir-pass-pipeline.f90 +++ flang/test/Driver/mlir-pass-pipeline.f90 @@ -62,5 +62,6 @@ ! ALL-NEXT: (S) 0 num-dce'd - Number of operations eliminated ! ALL-NEXT: TargetRewrite ! ALL-NEXT: ExternalNameConversion +! ALL-NEXT: ConvertMathToFuncs ! ALL-NEXT: FIRToLLVMLowering ! ALL-NOT: LLVMIRLoweringPass Index: flang/test/Fir/basic-program.fir =================================================================== --- flang/test/Fir/basic-program.fir +++ flang/test/Fir/basic-program.fir @@ -61,5 +61,6 @@ // PASSES-NEXT: CodeGenRewrite // PASSES-NEXT: (S) 0 num-dce'd - Number of operations eliminated // PASSES-NEXT: TargetRewrite +// PASSES-NEXT: ConvertMathToFuncs // PASSES-NEXT: FIRToLLVMLowering // PASSES-NEXT: LLVMIRLoweringPass Index: flang/test/Intrinsics/math-codegen.fir =================================================================== --- flang/test/Intrinsics/math-codegen.fir +++ flang/test/Intrinsics/math-codegen.fir @@ -1466,6 +1466,19 @@ func.func private @llvm.powi.f64.i32(f64, i32) -> f64 func.func private @pow(f64, f64) -> f64 +//--- exponentiation_integer.fir +// RUN: fir-opt %t/exponentiation_integer.fir --convert-math-to-funcs --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exponentiation_integer.fir +// CHECK: @_QPtest_int4 +// CHECK: llvm.call @__mlir_math_ipowi_i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (i32, i32) -> i32 + +func.func @_QPtest_int4(%arg0: !fir.ref {fir.bindc_name = "x"}, %arg1: !fir.ref {fir.bindc_name = "y"}, %arg2: !fir.ref {fir.bindc_name = "z"}) { + %0 = fir.load %arg0 : !fir.ref + %1 = fir.load %arg1 : !fir.ref + %2 = math.ipowi %0, %1 : i32 + fir.store %2 to %arg2 : !fir.ref + return +} + //--- sign_fast.fir // RUN: fir-opt %t/sign_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/sign_fast.fir // CHECK: @_QPtest_real4 Index: flang/test/Lower/power-operator.f90 =================================================================== --- flang/test/Lower/power-operator.f90 +++ flang/test/Lower/power-operator.f90 @@ -57,18 +57,32 @@ ! CHECK: math.powf %{{.*}}, %{{.*}} : f64 end subroutine +! CHECK-LABEL: pow_i1_i1 +subroutine pow_i1_i1(x, y, z) + integer(1) :: x, y, z + z = x ** y + ! CHECK: math.ipowi %{{.*}}, %{{.*}} : i8 +end subroutine + +! CHECK-LABEL: pow_i2_i2 +subroutine pow_i2_i2(x, y, z) + integer(2) :: x, y, z + z = x ** y + ! CHECK: math.ipowi %{{.*}}, %{{.*}} : i16 +end subroutine + ! CHECK-LABEL: pow_i4_i4 subroutine pow_i4_i4(x, y, z) integer(4) :: x, y, z z = x ** y - ! CHECK: call @__mth_i_ipowi + ! CHECK: math.ipowi %{{.*}}, %{{.*}} : i32 end subroutine ! CHECK-LABEL: pow_i8_i8 subroutine pow_i8_i8(x, y, z) integer(8) :: x, y, z z = x ** y - ! CHECK: call @__mth_i_kpowk + ! CHECK: math.ipowi %{{.*}}, %{{.*}} : i64 end subroutine ! CHECK-LABEL: pow_c4_i4