diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -98,6 +98,11 @@ mlir::Value genMin(fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef args); +/// Generate Complex divide with the given expected +/// result type. +mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type resultType, mlir::Value x, mlir::Value y); + /// Generate power function x**y with the given expected /// result type. mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType, diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -1075,7 +1075,16 @@ GENBIN(Multiply, Complex, fir::MulcOp) GENBIN(Divide, Integer, mlir::arith::DivSIOp) GENBIN(Divide, Real, mlir::arith::DivFOp) - GENBIN(Divide, Complex, fir::DivcOp) + + template + ExtValue genval(const Fortran::evaluate::Divide> &op) { + mlir::Type ty = + converter.genType(Fortran::common::TypeCategory::Complex, KIND); + mlir::Value lhs = genunbox(op.left()); + mlir::Value rhs = genunbox(op.right()); + return fir::genDivC(builder, getLoc(), ty, lhs, rhs); + } template ExtValue genval( @@ -5077,7 +5086,21 @@ GENBIN(Multiply, Complex, fir::MulcOp) GENBIN(Divide, Integer, mlir::arith::DivSIOp) GENBIN(Divide, Real, mlir::arith::DivFOp) - GENBIN(Divide, Complex, fir::DivcOp) + + template + CC genarr(const Fortran::evaluate::Divide> &x) { + mlir::Location loc = getLoc(); + mlir::Type ty = + converter.genType(Fortran::common::TypeCategory::Complex, KIND); + auto lf = genarr(x.left()); + auto rf = genarr(x.right()); + return [=](IterSpace iters) -> ExtValue { + mlir::Value lhs = fir::getBase(lf(iters)); + mlir::Value rhs = fir::getBase(rf(iters)); + return fir::genDivC(builder, loc, ty, lhs, rhs); + }; + } template CC genarr( diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -873,7 +873,22 @@ GENBIN(Multiply, Complex, fir::MulcOp) GENBIN(Divide, Integer, mlir::arith::DivSIOp) GENBIN(Divide, Real, mlir::arith::DivFOp) -GENBIN(Divide, Complex, fir::DivcOp) + +template +struct BinaryOp>> { + using Op = Fortran::evaluate::Divide< + Fortran::evaluate::Type>; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, const Op &, + hlfir::Entity lhs, hlfir::Entity rhs) { + mlir::Type ty = Fortran::lower::getFIRType( + builder.getContext(), Fortran::common::TypeCategory::Complex, KIND, + /*params=*/std::nullopt); + return hlfir::EntityWithAttributes{ + fir::genDivC(builder, loc, ty, lhs, rhs)}; + } +}; template struct BinaryOp>> { diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -1184,6 +1184,54 @@ return libCall.getResult(0); } +static mlir::Value genLibSplitComplexArgsCall( + fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, llvm::ArrayRef args) { + assert(args.size() == 2 && "Incorrect #args to genLibSplitComplexArgsCall"); + + auto getSplitComplexArgsType = [&builder, &args]() -> mlir::FunctionType { + mlir::Type ctype = args[0].getType(); + auto fKind = ctype.cast().getFKind(); + mlir::Type ftype; + + if (fKind == 2) + ftype = builder.getF16Type(); + else if (fKind == 3) + ftype = builder.getBF16Type(); + else if (fKind == 4) + ftype = builder.getF32Type(); + else if (fKind == 8) + ftype = builder.getF64Type(); + else if (fKind == 10) + ftype = builder.getF80Type(); + else if (fKind == 16) + ftype = builder.getF128Type(); + else + assert(0 && "Unsupported Complex Type"); + + return builder.getFunctionType({ftype, ftype, ftype, ftype}, {ctype}); + }; + + llvm::SmallVector splitArgs; + mlir::Value cplx1 = args[0]; + auto real1 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx1, /*isImagPart=*/false); + splitArgs.push_back(real1); + auto imag1 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx1, /*isImagPart=*/true); + splitArgs.push_back(imag1); + mlir::Value cplx2 = args[1]; + auto real2 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx2, /*isImagPart=*/false); + splitArgs.push_back(real2); + auto imag2 = fir::factory::Complex{builder, loc}.extractComplexPart( + cplx2, /*isImagPart=*/true); + splitArgs.push_back(imag2); + + return genLibCall(builder, loc, libFuncName, getSplitComplexArgsType(), + splitArgs); +} + template static mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef mathLibFuncName, @@ -1345,6 +1393,22 @@ {"cosh", "cosh", genF64F64FuncType, genLibCall}, {"cosh", "ccoshf", genComplexComplexFuncType<4>, genLibCall}, {"cosh", "ccosh", genComplexComplexFuncType<8>, genLibCall}, + {"divc", + {}, + genComplexComplexComplexFuncType<2>, + genComplexMathOp}, + {"divc", + {}, + genComplexComplexComplexFuncType<3>, + genComplexMathOp}, + {"divc", "__divsc3", genComplexComplexComplexFuncType<4>, + genLibSplitComplexArgsCall}, + {"divc", "__divdc3", genComplexComplexComplexFuncType<8>, + genLibSplitComplexArgsCall}, + {"divc", "__divxc3", genComplexComplexComplexFuncType<10>, + genLibSplitComplexArgsCall}, + {"divc", "__divtc3", genComplexComplexComplexFuncType<16>, + genLibSplitComplexArgsCall}, {"erf", "erff", genF32F32FuncType, genMathOp}, {"erf", "erf", genF64F64FuncType, genMathOp}, {"erfc", "erfcf", genF32F32FuncType, genLibCall}, @@ -5661,6 +5725,11 @@ args); } +mlir::Value fir::genDivC(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type type, mlir::Value x, mlir::Value y) { + return IntrinsicLibrary{builder, loc}.genRuntimeCall("divc", type, {x, y}); +} + mlir::Value fir::genPow(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type type, mlir::Value x, mlir::Value y) { // TODO: since there is no libm version of pow with integer exponent, diff --git a/flang/test/Lower/HLFIR/binary-ops.f90 b/flang/test/Lower/HLFIR/binary-ops.f90 --- a/flang/test/Lower/HLFIR/binary-ops.f90 +++ b/flang/test/Lower/HLFIR/binary-ops.f90 @@ -131,8 +131,11 @@ ! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref> ! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> -! CHECK: %[[VAL_8:.*]] = fir.divc %[[VAL_6]], %[[VAL_7]] : !fir.complex<4> - +! CHECK: %[[VAL_8:.*]] = fir.extract_value %[[VAL_6]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_9:.*]] = fir.extract_value %[[VAL_6]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_10:.*]] = fir.extract_value %[[VAL_7]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_11:.*]] = fir.extract_value %[[VAL_7]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[VAL_12:.*]] = fir.call @__divsc3(%[[VAL_8]], %[[VAL_9]], %[[VAL_10]], %[[VAL_11]]) fastmath : (f32, f32, f32, f32) -> !fir.complex<4> subroutine int_power(x, y, z) integer :: x, y, z diff --git a/flang/test/Lower/assignment.f90 b/flang/test/Lower/assignment.f90 --- a/flang/test/Lower/assignment.f90 +++ b/flang/test/Lower/assignment.f90 @@ -251,7 +251,11 @@ ! CHECK: %[[FCTRES:.*]] = fir.alloca !fir.complex<4> ! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref> ! CHECK: %[[B_VAL:.*]] = fir.load %[[B]] : !fir.ref> -! CHECK: %[[DIV:.*]] = fir.divc %[[A_VAL]], %[[B_VAL]] : !fir.complex<4> +! CHECK: %[[A_REAL:.*]] = fir.extract_value %[[A_VAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[A_IMAG:.*]] = fir.extract_value %[[A_VAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[B_REAL:.*]] = fir.extract_value %[[B_VAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[B_IMAG:.*]] = fir.extract_value %[[B_VAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[DIV:.*]] = fir.call @__divsc3(%[[A_REAL]], %[[A_IMAG]], %[[B_REAL]], %[[B_IMAG]]) fastmath : (f32, f32, f32, f32) -> !fir.complex<4> ! CHECK: fir.store %[[DIV]] to %[[FCTRES]] : !fir.ref> ! CHECK: %[[RET:.*]] = fir.load %[[FCTRES]] : !fir.ref> ! CHECK: return %[[RET]] : !fir.complex<4> diff --git a/flang/test/Lower/complex-operations.f90 b/flang/test/Lower/complex-operations.f90 --- a/flang/test/Lower/complex-operations.f90 +++ b/flang/test/Lower/complex-operations.f90 @@ -27,11 +27,90 @@ a = b * c end subroutine mul_test -! CHECK-LABEL: @_QPdiv_test -subroutine div_test(a,b,c) - complex :: a, b, c - ! CHECK-NOT: fir.extract_value - ! CHECK-NOT: fir.insert_value - ! CHECK: fir.divc {{.*}}: !fir.complex +! CHECK-LABEL: @_QPdiv_test_half +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BVAL_CVT:.*]] = fir.convert %[[BVAL]] : (!fir.complex<2>) -> complex +! CHECK: %[[CVAL_CVT:.*]] = fir.convert %[[CVAL]] : (!fir.complex<2>) -> complex +! CHECK: %[[AVAL_CVT:.*]] = complex.div %[[BVAL_CVT]], %[[CVAL_CVT]] : complex +! CHECK: %[[AVAL:.*]] = fir.convert %[[AVAL_CVT]] : (complex) -> !fir.complex<2> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_half(a,b,c) + complex(kind=2) :: a, b, c + a = b / c +end subroutine div_test_half + +! CHECK-LABEL: @_QPdiv_test_bfloat +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BVAL_CVT:.*]] = fir.convert %[[BVAL]] : (!fir.complex<3>) -> complex +! CHECK: %[[CVAL_CVT:.*]] = fir.convert %[[CVAL]] : (!fir.complex<3>) -> complex +! CHECK: %[[AVAL_CVT:.*]] = complex.div %[[BVAL_CVT]], %[[CVAL_CVT]] : complex +! CHECK: %[[AVAL:.*]] = fir.convert %[[AVAL_CVT]] : (complex) -> !fir.complex<3> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_bfloat(a,b,c) + complex(kind=3) :: a, b, c + a = b / c +end subroutine div_test_bfloat + +! CHECK-LABEL: @_QPdiv_test_single +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<4>) -> f32 +! CHECK: %[[AVAL:.*]] = fir.call @__divsc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f32, f32, f32, f32) -> !fir.complex<4> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_single(a,b,c) + complex(kind=4) :: a, b, c + a = b / c +end subroutine div_test_single + +! CHECK-LABEL: @_QPdiv_test_double +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<8>) -> f64 +! CHECK: %[[AVAL:.*]] = fir.call @__divdc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f64, f64, f64, f64) -> !fir.complex<8> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_double(a,b,c) + complex(kind=8) :: a, b, c + a = b / c +end subroutine div_test_double + +! CHECK-LABEL: @_QPdiv_test_extended +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<10>) -> f80 +! CHECK: %[[AVAL:.*]] = fir.call @__divxc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f80, f80, f80, f80) -> !fir.complex<10> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_extended(a,b,c) + complex(kind=10) :: a, b, c + a = b / c +end subroutine div_test_extended + +! CHECK-LABEL: @_QPdiv_test_quad +! CHECK-SAME: %[[AREF:.*]]: !fir.ref> {{.*}}, %[[BREF:.*]]: !fir.ref> {{.*}}, %[[CREF:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref> +! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref> +! CHECK: %[[BREAL:.*]] = fir.extract_value %[[BVAL]], [0 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[BIMAG:.*]] = fir.extract_value %[[BVAL]], [1 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[CREAL:.*]] = fir.extract_value %[[CVAL]], [0 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[CIMAG:.*]] = fir.extract_value %[[CVAL]], [1 : index] : (!fir.complex<16>) -> f128 +! CHECK: %[[AVAL:.*]] = fir.call @__divtc3(%[[BREAL]], %[[BIMAG]], %[[CREAL]], %[[CIMAG]]) fastmath : (f128, f128, f128, f128) -> !fir.complex<16> +! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref> +subroutine div_test_quad(a,b,c) + complex(kind=16) :: a, b, c a = b / c -end subroutine div_test +end subroutine div_test_quad