diff --git a/flang/include/flang/Optimizer/Support/InitFIR.h b/flang/include/flang/Optimizer/Support/InitFIR.h --- a/flang/include/flang/Optimizer/Support/InitFIR.h +++ b/flang/include/flang/Optimizer/Support/InitFIR.h @@ -17,6 +17,7 @@ #include "flang/Optimizer/HLFIR/HLFIRDialect.h" #include "mlir/Conversion/Passes.h" #include "mlir/Dialect/Affine/Passes.h" +#include "mlir/Dialect/Complex/IR/Complex.h" #include "mlir/InitAllDialects.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassRegistry.h" @@ -30,7 +31,8 @@ mlir::acc::OpenACCDialect, mlir::omp::OpenMPDialect, \ mlir::scf::SCFDialect, mlir::arith::ArithDialect, \ mlir::cf::ControlFlowDialect, mlir::func::FuncDialect, \ - mlir::vector::VectorDialect, mlir::math::MathDialect + mlir::vector::VectorDialect, mlir::math::MathDialect, \ + mlir::complex::ComplexDialect // The definitive list of dialects used by flang. #define FLANG_DIALECT_LIST \ diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -35,6 +35,7 @@ #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Support/FatalError.h" #include "flang/Runtime/entry-names.h" +#include "mlir/Dialect/Complex/IR/Complex.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" #include "llvm/Support/CommandLine.h" @@ -1072,6 +1073,12 @@ clEnumValN(preciseVersion, "precise", "use precise runtime behavior")), llvm::cl::init(fastVersion)); +static llvm::cl::opt + disableMlirComplex("disable-mlir-complex", + llvm::cl::desc("Use libm instead of the MLIR complex " + "dialect to lower complex operations"), + llvm::cl::init(false)); + struct RuntimeFunction { // llvm::StringRef comparison operator are not constexpr, so use string_view. using Key = std::string_view; @@ -1308,6 +1315,49 @@ return result; } +template +static mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, + mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args) { + mlir::Value result; + if (disableMlirComplex || + (mathRuntimeVersion == preciseVersion && !mathLibFuncName.empty())) { + result = genLibCall(builder, loc, mathLibFuncName, mathLibFuncType, args); + LLVM_DEBUG(result.dump(); llvm::dbgs() << "\n"); + return result; + } + + LLVM_DEBUG(llvm::dbgs() << "Generating '" << mathLibFuncName + << "' operation with type "; + mathLibFuncType.dump(); llvm::dbgs() << "\n"); + auto type = mathLibFuncType.getInput(0).cast(); + auto kind = type.getElementType().cast().getFKind(); + auto realTy = builder.getRealType(kind); + auto mComplexTy = mlir::ComplexType::get(realTy); + + llvm::SmallVector cargs; + for (const mlir::Value &arg : args) { + // Convert the fir.complex to a mlir::complex + cargs.push_back(builder.createConvert(loc, mComplexTy, arg)); + } + + // Builder expects an extra return type to be provided if different to + // the argument types for an operation + if constexpr (T::template hasTrait< + mlir::OpTrait::SameOperandsAndResultType>()) { + result = builder.create(loc, cargs); + result = builder.createConvert(loc, mathLibFuncType.getResult(0), result); + } else { + result = builder.create(loc, realTy, cargs); + result = builder.createConvert(loc, mathLibFuncType.getResult(0), result); + } + + LLVM_DEBUG(result.dump(); llvm::dbgs() << "\n"); + return result; +} + /// Mapping between mathematical intrinsic operations and MLIR operations /// of some appropriate dialect (math, complex, etc.) or libm calls. /// TODO: support remaining Fortran math intrinsics. @@ -1318,8 +1368,10 @@ {"abs", "fabs", genF64F64FuncType, genMathOp}, {"abs", "llvm.fabs.f128", genF128F128FuncType, genMathOp}, - {"abs", "cabsf", genF32ComplexFuncType, genLibCall}, - {"abs", "cabs", genF64ComplexFuncType, genLibCall}, + {"abs", "cabsf", genF32ComplexFuncType, + genComplexMathOp}, + {"abs", "cabs", genF64ComplexFuncType, + genComplexMathOp}, {"acos", "acosf", genF32F32FuncType, genLibCall}, {"acos", "acos", genF64F64FuncType, genLibCall}, {"acos", "cacosf", genComplexComplexFuncType<4>, genLibCall}, @@ -1374,8 +1426,10 @@ {"ceil", "ceil", genF64F64FuncType, genMathOp}, {"cos", "cosf", genF32F32FuncType, genMathOp}, {"cos", "cos", genF64F64FuncType, genMathOp}, - {"cos", "ccosf", genComplexComplexFuncType<4>, genLibCall}, - {"cos", "ccos", genComplexComplexFuncType<8>, genLibCall}, + {"cos", "ccosf", genComplexComplexFuncType<4>, + genComplexMathOp}, + {"cos", "ccos", genComplexComplexFuncType<8>, + genComplexMathOp}, {"cosh", "coshf", genF32F32FuncType, genLibCall}, {"cosh", "cosh", genF64F64FuncType, genLibCall}, {"cosh", "ccoshf", genComplexComplexFuncType<4>, genLibCall}, @@ -1386,8 +1440,10 @@ {"erfc", "erfc", genF64F64FuncType, genLibCall}, {"exp", "expf", genF32F32FuncType, genMathOp}, {"exp", "exp", genF64F64FuncType, genMathOp}, - {"exp", "cexpf", genComplexComplexFuncType<4>, genLibCall}, - {"exp", "cexp", genComplexComplexFuncType<8>, genLibCall}, + {"exp", "cexpf", genComplexComplexFuncType<4>, + genComplexMathOp}, + {"exp", "cexp", genComplexComplexFuncType<8>, + genComplexMathOp}, // math::FloorOp returns a real, while Fortran FLOOR returns integer. {"floor", "floorf", genF32F32FuncType, genMathOp}, {"floor", "floor", genF64F64FuncType, genMathOp}, @@ -1397,8 +1453,10 @@ {"hypot", "hypot", genF64F64F64FuncType, genLibCall}, {"log", "logf", genF32F32FuncType, genMathOp}, {"log", "log", genF64F64FuncType, genMathOp}, - {"log", "clogf", genComplexComplexFuncType<4>, genLibCall}, - {"log", "clog", genComplexComplexFuncType<8>, genLibCall}, + {"log", "clogf", genComplexComplexFuncType<4>, + genComplexMathOp}, + {"log", "clog", genComplexComplexFuncType<8>, + genComplexMathOp}, {"log10", "log10f", genF32F32FuncType, genMathOp}, {"log10", "log10", genF64F64FuncType, genMathOp}, {"log_gamma", "lgammaf", genF32F32FuncType, genLibCall}, @@ -1414,8 +1472,10 @@ {"pow", {}, genIntIntIntFuncType<64>, genMathOp}, {"pow", "powf", genF32F32F32FuncType, genMathOp}, {"pow", "pow", genF64F64F64FuncType, genMathOp}, - {"pow", "cpowf", genComplexComplexComplexFuncType<4>, genLibCall}, - {"pow", "cpow", genComplexComplexComplexFuncType<8>, genLibCall}, + {"pow", "cpowf", genComplexComplexComplexFuncType<4>, + genComplexMathOp}, + {"pow", "cpow", genComplexComplexComplexFuncType<8>, + genComplexMathOp}, // TODO: add PowIOp in math and complex dialects. {"pow", "llvm.powi.f32.i32", genF32F32IntFuncType<32>, genLibCall}, {"pow", "llvm.powi.f64.i32", genF64F64IntFuncType<32>, genLibCall}, @@ -1437,24 +1497,32 @@ genMathOp}, {"sin", "sinf", genF32F32FuncType, genMathOp}, {"sin", "sin", genF64F64FuncType, genMathOp}, - {"sin", "csinf", genComplexComplexFuncType<4>, genLibCall}, - {"sin", "csin", genComplexComplexFuncType<8>, genLibCall}, + {"sin", "csinf", genComplexComplexFuncType<4>, + genComplexMathOp}, + {"sin", "csin", genComplexComplexFuncType<8>, + genComplexMathOp}, {"sinh", "sinhf", genF32F32FuncType, genLibCall}, {"sinh", "sinh", genF64F64FuncType, genLibCall}, {"sinh", "csinhf", genComplexComplexFuncType<4>, genLibCall}, {"sinh", "csinh", genComplexComplexFuncType<8>, genLibCall}, {"sqrt", "sqrtf", genF32F32FuncType, genMathOp}, {"sqrt", "sqrt", genF64F64FuncType, genMathOp}, - {"sqrt", "csqrtf", genComplexComplexFuncType<4>, genLibCall}, - {"sqrt", "csqrt", genComplexComplexFuncType<8>, genLibCall}, + {"sqrt", "csqrtf", genComplexComplexFuncType<4>, + genComplexMathOp}, + {"sqrt", "csqrt", genComplexComplexFuncType<8>, + genComplexMathOp}, {"tan", "tanf", genF32F32FuncType, genMathOp}, {"tan", "tan", genF64F64FuncType, genMathOp}, - {"tan", "ctanf", genComplexComplexFuncType<4>, genLibCall}, - {"tan", "ctan", genComplexComplexFuncType<8>, genLibCall}, + {"tan", "ctanf", genComplexComplexFuncType<4>, + genComplexMathOp}, + {"tan", "ctan", genComplexComplexFuncType<8>, + genComplexMathOp}, {"tanh", "tanhf", genF32F32FuncType, genMathOp}, {"tanh", "tanh", genF64F64FuncType, genMathOp}, - {"tanh", "ctanhf", genComplexComplexFuncType<4>, genLibCall}, - {"tanh", "ctanh", genComplexComplexFuncType<8>, genLibCall}, + {"tanh", "ctanhf", genComplexComplexFuncType<4>, + genComplexMathOp}, + {"tanh", "ctanh", genComplexComplexFuncType<8>, + genComplexMathOp}, }; // This helper class computes a "distance" between two function types. diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -20,6 +20,8 @@ #include "flang/Optimizer/Support/TypeCode.h" #include "flang/Semantics/runtime-type-info.h" #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" +#include "mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h" +#include "mlir/Conversion/ComplexToStandard/ComplexToStandard.h" #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h" #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h" #include "mlir/Conversion/LLVMCommon/Pattern.h" @@ -3509,6 +3511,7 @@ // as passes here. mlir::OpPassManager mathConvertionPM("builtin.module"); mathConvertionPM.addPass(mlir::createConvertMathToFuncsPass()); + mathConvertionPM.addPass(mlir::createConvertComplexToStandardPass()); if (mlir::failed(runPipeline(mathConvertionPM, mod))) return signalPassFailure(); @@ -3573,6 +3576,7 @@ // when late math lowering mode is used, into llvm dialect. mlir::populateMathToLLVMConversionPatterns(typeConverter, pattern); mlir::populateMathToLibmConversionPatterns(pattern, /*benefit=*/0); + mlir::populateComplexToLLVMConversionPatterns(typeConverter, pattern); mlir::ConversionTarget target{*context}; target.addLegalDialect(); // The OpenMP dialect is legal for Operations without regions, for those diff --git a/flang/test/Lower/Intrinsics/abs.f90 b/flang/test/Lower/Intrinsics/abs.f90 --- a/flang/test/Lower/Intrinsics/abs.f90 +++ b/flang/test/Lower/Intrinsics/abs.f90 @@ -1,5 +1,9 @@ -! RUN: bbc -emit-fir %s -o - | FileCheck %s -! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s +! RUN: bbc -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX,CMPLX-FAST" +! RUN: bbc -emit-fir --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: bbc --disable-mlir-complex -emit-fir %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX,CMPLX-FAST" +! RUN: %flang_fc1 -emit-fir -mllvm --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm --disable-mlir-complex %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" ! Test abs intrinsic for various types (int, float, complex) @@ -90,25 +94,29 @@ b = abs(a) end subroutine -! CHECK-LABEL: func @_QPabs_testzr( -! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>{{.*}}, %[[VAL_1:.*]]: !fir.ref{{.*}}) { +! CMPLX-LABEL: func @_QPabs_testzr( +! CMPLX-SAME: %[[VAL_0:.*]]: !fir.ref>{{.*}}, %[[VAL_1:.*]]: !fir.ref{{.*}}) { subroutine abs_testzr(a, b) -! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref> -! CHECK: %[[VAL_3:.*]] = fir.call @cabsf(%[[VAL_2]]) : (!fir.complex<4>) -> f32 -! CHECK: fir.store %[[VAL_3]] to %[[VAL_1]] : !fir.ref -! CHECK: return +! CMPLX: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref> +! CMPLX-FAST: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.complex<4>) -> complex +! CMPLX-FAST: %[[VAL_4:.*]] = complex.abs %[[VAL_3]] : complex +! CMPLX-PRECISE: %[[VAL_4:.*]] = fir.call @cabsf(%[[VAL_2]]) : (!fir.complex<4>) -> f32 +! CMPLX: fir.store %[[VAL_4]] to %[[VAL_1]] : !fir.ref +! CMPLX: return complex :: a real :: b b = abs(a) end subroutine abs_testzr -! CHECK-LABEL: func @_QPabs_testzd( -! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>{{.*}}, %[[VAL_1:.*]]: !fir.ref{{.*}}) { +! CMPLX-LABEL: func @_QPabs_testzd( +! CMPLX-SAME: %[[VAL_0:.*]]: !fir.ref>{{.*}}, %[[VAL_1:.*]]: !fir.ref{{.*}}) { subroutine abs_testzd(a, b) -! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref> -! CHECK: %[[VAL_3:.*]] = fir.call @cabs(%[[VAL_2]]) : (!fir.complex<8>) -> f64 -! CHECK: fir.store %[[VAL_3]] to %[[VAL_1]] : !fir.ref -! CHECK: return +! CMPLX: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref> +! CMPLX-FAST: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.complex<8>) -> complex +! CMPLX-FAST: %[[VAL_4:.*]] = complex.abs %[[VAL_3]] : complex +! CMPLX-PRECISE: %[[VAL_4:.*]] = fir.call @cabs(%[[VAL_2]]) : (!fir.complex<8>) -> f64 +! CMPLX: fir.store %[[VAL_4]] to %[[VAL_1]] : !fir.ref +! CMPLX: return complex(kind=8) :: a real(kind=8) :: b b = abs(a) diff --git a/flang/test/Lower/Intrinsics/exp.f90 b/flang/test/Lower/Intrinsics/exp.f90 --- a/flang/test/Lower/Intrinsics/exp.f90 +++ b/flang/test/Lower/Intrinsics/exp.f90 @@ -1,5 +1,9 @@ -! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s -! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s +! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX,CMPLX-FAST" +! RUN: bbc -emit-fir --math-runtime=precise -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: bbc -emit-fir --disable-mlir-complex -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX,CMPLX-FAST" +! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics -mllvm --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics -mllvm --disable-mlir-complex %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" ! CHECK-LABEL: exp_testr ! CHECK-SAME: (%[[AREF:.*]]: !fir.ref {{.*}}, %[[BREF:.*]]: !fir.ref {{.*}}) @@ -51,12 +55,18 @@ ! CHECK: %[[RESULT64_OUTLINE:.*]] = math.exp %[[ARG64_OUTLINE]] : f64 ! CHECK: return %[[RESULT64_OUTLINE]] : f64 -! CHECK-LABEL: private @fir.exp.z4.z4 -! CHECK-SAME: (%[[ARG32_OUTLINE]]: !fir.complex<4>) -> !fir.complex<4> -! CHECK: %[[RESULT32_OUTLINE]] = fir.call @cexpf(%[[ARG32_OUTLINE]]) : (!fir.complex<4>) -> !fir.complex<4> -! CHECK: return %[[RESULT32_OUTLINE]] : !fir.complex<4> +! CMPLX-LABEL: private @fir.exp.z4.z4 +! CMPLX-SAME: (%[[ARG32_OUTLINE:.*]]: !fir.complex<4>) -> !fir.complex<4> +! CMPLX-FAST: %[[C:.*]] = fir.convert %[[ARG32_OUTLINE]] : (!fir.complex<4>) -> complex +! CMPLX-FAST: %[[E:.*]] = complex.exp %[[C]] : complex +! CMPLX-FAST: %[[RESULT32_OUTLINE:.*]] = fir.convert %[[E]] : (complex) -> !fir.complex<4> +! CMPLX-PRECISE: %[[RESULT32_OUTLINE:.*]] = fir.call @cexpf(%[[ARG32_OUTLINE]]) : (!fir.complex<4>) -> !fir.complex<4> +! CMPLX: return %[[RESULT32_OUTLINE]] : !fir.complex<4> -! CHECK-LABEL: private @fir.exp.z8.z8 -! CHECK-SAME: (%[[ARG64_OUTLINE]]: !fir.complex<8>) -> !fir.complex<8> -! CHECK: %[[RESULT64_OUTLINE]] = fir.call @cexp(%[[ARG64_OUTLINE]]) : (!fir.complex<8>) -> !fir.complex<8> -! CHECK: return %[[RESULT64_OUTLINE]] : !fir.complex<8> +! CMPLX-LABEL: private @fir.exp.z8.z8 +! CMPLX-SAME: (%[[ARG64_OUTLINE:.*]]: !fir.complex<8>) -> !fir.complex<8> +! CMPLX-FAST: %[[C:.*]] = fir.convert %[[ARG64_OUTLINE]] : (!fir.complex<8>) -> complex +! CMPLX-FAST: %[[E:.*]] = complex.exp %[[C]] : complex +! CMPLX-FAST: %[[RESULT64_OUTLINE:.*]] = fir.convert %[[E]] : (complex) -> !fir.complex<8> +! CMPLX-PRECISE: %[[RESULT64_OUTLINE:.*]] = fir.call @cexp(%[[ARG64_OUTLINE]]) : (!fir.complex<8>) -> !fir.complex<8> +! CMPLX: return %[[RESULT64_OUTLINE]] : !fir.complex<8> diff --git a/flang/test/Lower/Intrinsics/log.f90 b/flang/test/Lower/Intrinsics/log.f90 --- a/flang/test/Lower/Intrinsics/log.f90 +++ b/flang/test/Lower/Intrinsics/log.f90 @@ -1,5 +1,9 @@ -! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s -! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s +! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX,CMPLX-FAST" +! RUN: bbc -emit-fir --math-runtime=precise -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: bbc -emit-fir --disable-mlir-complex -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX,CMPLX-FAST" +! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics -mllvm --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics -mllvm --disable-mlir-complex %s -o - | FileCheck %s --check-prefixes="CMPLX,CMPLX-PRECISE" ! CHECK-LABEL: log_testr ! CHECK-SAME: (%[[AREF:.*]]: !fir.ref {{.*}}, %[[BREF:.*]]: !fir.ref {{.*}}) @@ -71,15 +75,21 @@ ! CHECK: %[[RESULT64_OUTLINE:.*]] = math.log %[[ARG64_OUTLINE]] : f64 ! CHECK: return %[[RESULT64_OUTLINE]] : f64 -! CHECK-LABEL: private @fir.log.z4.z4 -! CHECK-SAME: (%[[ARG32_OUTLINE]]: !fir.complex<4>) -> !fir.complex<4> -! CHECK: %[[RESULT32_OUTLINE]] = fir.call @clogf(%[[ARG32_OUTLINE]]) : (!fir.complex<4>) -> !fir.complex<4> -! CHECK: return %[[RESULT32_OUTLINE]] : !fir.complex<4> +! CMPLX-LABEL: private @fir.log.z4.z4 +! CMPLX-SAME: (%[[ARG32_OUTLINE:.*]]: !fir.complex<4>) -> !fir.complex<4> +! CMPLX-FAST: %[[C:.*]] = fir.convert %[[ARG32_OUTLINE]] : (!fir.complex<4>) -> complex +! CMPLX-FAST: %[[E:.*]] = complex.log %[[C]] : complex +! CMPLX-FAST: %[[RESULT32_OUTLINE:.*]] = fir.convert %[[E]] : (complex) -> !fir.complex<4> +! CMPLX-PRECISE: %[[RESULT32_OUTLINE:.*]] = fir.call @clogf(%[[ARG32_OUTLINE]]) : (!fir.complex<4>) -> !fir.complex<4> +! CMPLX: return %[[RESULT32_OUTLINE]] : !fir.complex<4> -! CHECK-LABEL: private @fir.log.z8.z8 -! CHECK-SAME: (%[[ARG64_OUTLINE]]: !fir.complex<8>) -> !fir.complex<8> -! CHECK: %[[RESULT64_OUTLINE]] = fir.call @clog(%[[ARG64_OUTLINE]]) : (!fir.complex<8>) -> !fir.complex<8> -! CHECK: return %[[RESULT64_OUTLINE]] : !fir.complex<8> +! CMPLX-LABEL: private @fir.log.z8.z8 +! CMPLX-SAME: (%[[ARG64_OUTLINE:.*]]: !fir.complex<8>) -> !fir.complex<8> +! CMPLX-FAST: %[[C:.*]] = fir.convert %[[ARG64_OUTLINE]] : (!fir.complex<8>) -> complex +! CMPLX-FAST: %[[E:.*]] = complex.log %[[C]] : complex +! CMPLX-FAST: %[[RESULT64_OUTLINE:.*]] = fir.convert %[[E]] : (complex) -> !fir.complex<8> +! CMPLX-PRECISE: %[[RESULT64_OUTLINE:.*]] = fir.call @clog(%[[ARG64_OUTLINE]]) : (!fir.complex<8>) -> !fir.complex<8> +! CMPLX: return %[[RESULT64_OUTLINE]] : !fir.complex<8> ! CHECK-LABEL: private @fir.log10.f32.f32 ! CHECK-SAME: (%[[ARG32_OUTLINE:.*]]: f32) -> f32 diff --git a/flang/test/Lower/math-lowering.f90 b/flang/test/Lower/math-lowering.f90 --- a/flang/test/Lower/math-lowering.f90 +++ b/flang/test/Lower/math-lowering.f90 @@ -43,7 +43,9 @@ end function ! ALL-LABEL: @_QPtest_complex4 -! ALL: {{%[A-Za-z0-9._]+}} = fir.call @cabsf({{%[A-Za-z0-9._]+}}) : (!fir.complex<4>) -> f32 +! FAST: {{%[A-Za-z0-9._]+}} = complex.abs {{%[A-Za-z0-9._]+}} : complex +! RELAXED: {{%[A-Za-z0-9._]+}} = complex.abs {{%[A-Za-z0-9._]+}} : complex +! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @cabsf({{%[A-Za-z0-9._]+}}) : (!fir.complex<4>) -> f32 function test_complex8(c) complex(8) :: c, test_complex8 @@ -51,7 +53,9 @@ end function ! ALL-LABEL: @_QPtest_complex8 -! ALL: {{%[A-Za-z0-9._]+}} = fir.call @cabs({{%[A-Za-z0-9._]+}}) : (!fir.complex<8>) -> f64 +! FAST: {{%[A-Za-z0-9._]+}} = complex.abs {{%[A-Za-z0-9._]+}} : complex +! RELAXED: {{%[A-Za-z0-9._]+}} = complex.abs {{%[A-Za-z0-9._]+}} : complex +! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @cabs({{%[A-Za-z0-9._]+}}) : (!fir.complex<8>) -> f64 //--- aint.f90 ! RUN: bbc -emit-fir %t/aint.f90 -o - --math-runtime=fast | FileCheck --check-prefixes=ALL %t/aint.f90 diff --git a/flang/test/Lower/power-operator.f90 b/flang/test/Lower/power-operator.f90 --- a/flang/test/Lower/power-operator.f90 +++ b/flang/test/Lower/power-operator.f90 @@ -1,4 +1,9 @@ -! RUN: bbc -emit-fir %s -o - | FileCheck %s +! RUN: bbc -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX-FAST" +! RUN: bbc --math-runtime=precise -emit-fir %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" +! RUN: bbc --disable-mlir-complex -emit-fir %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX-FAST" +! RUN: %flang_fc1 -emit-fir -mllvm --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm --disable-mlir-complex %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" ! Test power operation lowering @@ -121,13 +126,15 @@ subroutine pow_c4_c4(x, y, z) complex :: x, y, z z = x ** y - ! CHECK: call @cpowf + ! CMPLX-FAST: complex.pow %{{.*}}, %{{.*}} : complex + ! CMPLX-PRECISE: call @cpowf end subroutine ! CHECK-LABEL: pow_c8_c8 subroutine pow_c8_c8(x, y, z) complex(8) :: x, y, z z = x ** y - ! CHECK: call @cpow + ! CMPLX-FAST: complex.pow %{{.*}}, %{{.*}} : complex + ! CMPLX-PRECISE: call @cpow end subroutine diff --git a/flang/test/Lower/sqrt.f90 b/flang/test/Lower/sqrt.f90 --- a/flang/test/Lower/sqrt.f90 +++ b/flang/test/Lower/sqrt.f90 @@ -1,5 +1,9 @@ -! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s -! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s +! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX-FAST" +! RUN: bbc --math-runtime=precise -emit-fir -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" +! RUN: bbc --disable-mlir-complex -emit-fir -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX-FAST" +! RUN: %flang_fc1 -emit-fir -mllvm --math-runtime=precise -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" +! RUN: %flang_fc1 -emit-fir -mllvm --disable-mlir-complex -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" ! CHECK-LABEL: sqrt_testr subroutine sqrt_testr(a, b) @@ -36,7 +40,9 @@ ! CHECK: math.sqrt %{{.*}} : f64 ! CHECK-LABEL: func private @fir.sqrt.z4.z4 -! CHECK: fir.call @csqrtf +! CMPLX-FAST: complex.sqrt %{{.*}} : complex +! CMPLX-PRECISE: fir.call @csqrtf ! CHECK-LABEL: @fir.sqrt.z8.z8 -! CHECK: fir.call @csqrt +! CMPLX-FAST: complex.sqrt %{{.*}} : complex +! CMPLX-PRECISE: fir.call @csqrt diff --git a/flang/test/Lower/trigonometric-intrinsics.f90 b/flang/test/Lower/trigonometric-intrinsics.f90 --- a/flang/test/Lower/trigonometric-intrinsics.f90 +++ b/flang/test/Lower/trigonometric-intrinsics.f90 @@ -1,4 +1,5 @@ -! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s +! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX-FAST" +! RUN: bbc --math-runtime=precise -emit-fir -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE" ! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s ! CHECK-LABEL: tan_testr @@ -176,10 +177,12 @@ ! CHECK: math.tan %{{.*}} : f64 ! CHECK-LABEL: @fir.tan.z4.z4 -! CHECK: fir.call @ctanf +! CMPLX-FAST: complex.tan %{{.*}} : complex +! CMPLX-PRECISE: fir.call @ctanf ! CHECK-LABEL: @fir.tan.z8.z8 -! CHECK: fir.call @ctan +! CMPLX-FAST: complex.tan %{{.*}} : complex +! CMPLX-PRECISE: fir.call @ctan ! CHECK-LABEL: @fir.atan.f32.f32 ! CHECK: math.atan %{{.*}} : f32 @@ -200,10 +203,12 @@ ! CHECK: math.cos %{{.*}} : f64 ! CHECK-LABEL: @fir.cos.z4.z4 -! CHECK: fir.call @ccosf +! CMPLX-FAST: complex.cos %{{.*}} : complex +! CMPLX-PRECISE: fir.call @ccosf ! CHECK-LABEL: @fir.cos.z8.z8 -! CHECK: fir.call @ccos +! CMPLX-FAST: complex.cos %{{.*}} : complex +! CMPLX-PRECISE: fir.call @ccos ! CHECK-LABEL: @fir.cosh.f32.f32 ! CHECK: fir.call {{.*}}cosh @@ -224,10 +229,12 @@ ! CHECK: math.sin %{{.*}} : f64 ! CHECK-LABEL: @fir.sin.z4.z4 -! CHECK: fir.call @csinf +! CMPLX-FAST: complex.sin %{{.*}} : complex +! CMPLX-PRECISE: fir.call @csinf ! CHECK-LABEL: @fir.sin.z8.z8 -! CHECK: fir.call @csin +! CMPLX-FAST: complex.sin %{{.*}} : complex +! CMPLX-PRECISE: fir.call @csin ! CHECK-LABEL: @fir.sinh.f32.f32 ! CHECK: fir.call {{.*}}sinh