Skip to content

Commit 1b9d0de

Browse files
[Flang] Change complex divide lowering
Currently complex division is lowered to a fir.divc operation and the fir.divc is later converted to a sequence of llvm operations to perform complex division, however this causes issues for extreme values when the calculations overflow. This patch changes the lowering of complex division to use the Intrinsic Call functionality to lower into library calls (for single, double, extended and quad precisions) or an MLIR complex dialect division operation (for half and bfloat precisions). Note 1: If the Complex To Standard conversion of division operation matures then we can use it for all precisions. Currently it has the same issues as the conversion of fir.divc. Note 2: A previous patch (D145808) did the same but during conversion of the fir.divc operation. But using function calls at that stage leads to ABI issues since the conversion to LLVM is not aware of the complex target rewrite. Note 3: If the patch is accepted, fir.divc can be removed from FIR. Reviewed By: vzakhari, PeteSteinfeld, DavidTruby Differential Revision: https://reviews.llvm.org/D149546
1 parent 560065b commit 1b9d0de

File tree

5 files changed

+118
-10
lines changed

5 files changed

+118
-10
lines changed

flang/include/flang/Optimizer/Builder/IntrinsicCall.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ mlir::Value genMax(fir::FirOpBuilder &, mlir::Location,
9898
mlir::Value genMin(fir::FirOpBuilder &, mlir::Location,
9999
llvm::ArrayRef<mlir::Value> args);
100100

101+
/// Generate Complex divide with the given expected
102+
/// result type.
103+
mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
104+
mlir::Type resultType, mlir::Value x, mlir::Value y);
105+
101106
/// Generate power function x**y with the given expected
102107
/// result type.
103108
mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType,

flang/lib/Lower/ConvertExpr.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,16 @@ class ScalarExprLowering {
10751075
GENBIN(Multiply, Complex, fir::MulcOp)
10761076
GENBIN(Divide, Integer, mlir::arith::DivSIOp)
10771077
GENBIN(Divide, Real, mlir::arith::DivFOp)
1078-
GENBIN(Divide, Complex, fir::DivcOp)
1078+
1079+
template <int KIND>
1080+
ExtValue genval(const Fortran::evaluate::Divide<Fortran::evaluate::Type<
1081+
Fortran::common::TypeCategory::Complex, KIND>> &op) {
1082+
mlir::Type ty =
1083+
converter.genType(Fortran::common::TypeCategory::Complex, KIND);
1084+
mlir::Value lhs = genunbox(op.left());
1085+
mlir::Value rhs = genunbox(op.right());
1086+
return fir::genDivC(builder, getLoc(), ty, lhs, rhs);
1087+
}
10791088

10801089
template <Fortran::common::TypeCategory TC, int KIND>
10811090
ExtValue genval(
@@ -5077,7 +5086,21 @@ class ArrayExprLowering {
50775086
GENBIN(Multiply, Complex, fir::MulcOp)
50785087
GENBIN(Divide, Integer, mlir::arith::DivSIOp)
50795088
GENBIN(Divide, Real, mlir::arith::DivFOp)
5080-
GENBIN(Divide, Complex, fir::DivcOp)
5089+
5090+
template <int KIND>
5091+
CC genarr(const Fortran::evaluate::Divide<Fortran::evaluate::Type<
5092+
Fortran::common::TypeCategory::Complex, KIND>> &x) {
5093+
mlir::Location loc = getLoc();
5094+
mlir::Type ty =
5095+
converter.genType(Fortran::common::TypeCategory::Complex, KIND);
5096+
auto lf = genarr(x.left());
5097+
auto rf = genarr(x.right());
5098+
return [=](IterSpace iters) -> ExtValue {
5099+
mlir::Value lhs = fir::getBase(lf(iters));
5100+
mlir::Value rhs = fir::getBase(rf(iters));
5101+
return fir::genDivC(builder, loc, ty, lhs, rhs);
5102+
};
5103+
}
50815104

50825105
template <Fortran::common::TypeCategory TC, int KIND>
50835106
CC genarr(

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,18 @@ static constexpr MathOperation mathOperations[] = {
13451345
{"cosh", "cosh", genF64F64FuncType, genLibCall},
13461346
{"cosh", "ccoshf", genComplexComplexFuncType<4>, genLibCall},
13471347
{"cosh", "ccosh", genComplexComplexFuncType<8>, genLibCall},
1348+
{"divc",
1349+
{},
1350+
genComplexComplexComplexFuncType<2>,
1351+
genComplexMathOp<mlir::complex::DivOp>},
1352+
{"divc",
1353+
{},
1354+
genComplexComplexComplexFuncType<3>,
1355+
genComplexMathOp<mlir::complex::DivOp>},
1356+
{"divc", "__divsc3", genComplexComplexComplexFuncType<4>, genLibCall},
1357+
{"divc", "__divdc3", genComplexComplexComplexFuncType<8>, genLibCall},
1358+
{"divc", "__divxc3", genComplexComplexComplexFuncType<10>, genLibCall},
1359+
{"divc", "__divtc3", genComplexComplexComplexFuncType<16>, genLibCall},
13481360
{"erf", "erff", genF32F32FuncType, genMathOp<mlir::math::ErfOp>},
13491361
{"erf", "erf", genF64F64FuncType, genMathOp<mlir::math::ErfOp>},
13501362
{"erfc", "erfcf", genF32F32FuncType, genLibCall},
@@ -5661,6 +5673,11 @@ mlir::Value fir::genMin(fir::FirOpBuilder &builder, mlir::Location loc,
56615673
args);
56625674
}
56635675

5676+
mlir::Value fir::genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
5677+
mlir::Type type, mlir::Value x, mlir::Value y) {
5678+
return IntrinsicLibrary{builder, loc}.genRuntimeCall("divc", type, {x, y});
5679+
}
5680+
56645681
mlir::Value fir::genPow(fir::FirOpBuilder &builder, mlir::Location loc,
56655682
mlir::Type type, mlir::Value x, mlir::Value y) {
56665683
// TODO: since there is no libm version of pow with integer exponent,

flang/test/Lower/assignment.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ real function divf(a, b)
251251
! CHECK: %[[FCTRES:.*]] = fir.alloca !fir.complex<4>
252252
! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<!fir.complex<4>>
253253
! CHECK: %[[B_VAL:.*]] = fir.load %[[B]] : !fir.ref<!fir.complex<4>>
254-
! CHECK: %[[DIV:.*]] = fir.divc %[[A_VAL]], %[[B_VAL]] : !fir.complex<4>
254+
! CHECK: %[[DIV:.*]] = fir.call @__divsc3(%[[A_VAL]], %[[B_VAL]]) fastmath<contract> : (!fir.complex<4>, !fir.complex<4>) -> !fir.complex<4>
255255
! CHECK: fir.store %[[DIV]] to %[[FCTRES]] : !fir.ref<!fir.complex<4>>
256256
! CHECK: %[[RET:.*]] = fir.load %[[FCTRES]] : !fir.ref<!fir.complex<4>>
257257
! CHECK: return %[[RET]] : !fir.complex<4>

flang/test/Lower/complex-operations.f90

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,74 @@ subroutine mul_test(a,b,c)
2727
a = b * c
2828
end subroutine mul_test
2929

30-
! CHECK-LABEL: @_QPdiv_test
31-
subroutine div_test(a,b,c)
32-
complex :: a, b, c
33-
! CHECK-NOT: fir.extract_value
34-
! CHECK-NOT: fir.insert_value
35-
! CHECK: fir.divc {{.*}}: !fir.complex
30+
! CHECK-LABEL: @_QPdiv_test_half
31+
! CHECK-SAME: %[[AREF:.*]]: !fir.ref<!fir.complex<2>> {{.*}}, %[[BREF:.*]]: !fir.ref<!fir.complex<2>> {{.*}}, %[[CREF:.*]]: !fir.ref<!fir.complex<2>> {{.*}})
32+
! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref<!fir.complex<2>>
33+
! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref<!fir.complex<2>>
34+
! CHECK: %[[BVAL_CVT:.*]] = fir.convert %[[BVAL]] : (!fir.complex<2>) -> complex<f16>
35+
! CHECK: %[[CVAL_CVT:.*]] = fir.convert %[[CVAL]] : (!fir.complex<2>) -> complex<f16>
36+
! CHECK: %[[AVAL_CVT:.*]] = complex.div %[[BVAL_CVT]], %[[CVAL_CVT]] : complex<f16>
37+
! CHECK: %[[AVAL:.*]] = fir.convert %[[AVAL_CVT]] : (complex<f16>) -> !fir.complex<2>
38+
! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref<!fir.complex<2>>
39+
subroutine div_test_half(a,b,c)
40+
complex(kind=2) :: a, b, c
41+
a = b / c
42+
end subroutine div_test_half
43+
44+
! CHECK-LABEL: @_QPdiv_test_bfloat
45+
! CHECK-SAME: %[[AREF:.*]]: !fir.ref<!fir.complex<3>> {{.*}}, %[[BREF:.*]]: !fir.ref<!fir.complex<3>> {{.*}}, %[[CREF:.*]]: !fir.ref<!fir.complex<3>> {{.*}})
46+
! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref<!fir.complex<3>>
47+
! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref<!fir.complex<3>>
48+
! CHECK: %[[BVAL_CVT:.*]] = fir.convert %[[BVAL]] : (!fir.complex<3>) -> complex<bf16>
49+
! CHECK: %[[CVAL_CVT:.*]] = fir.convert %[[CVAL]] : (!fir.complex<3>) -> complex<bf16>
50+
! CHECK: %[[AVAL_CVT:.*]] = complex.div %[[BVAL_CVT]], %[[CVAL_CVT]] : complex<bf16>
51+
! CHECK: %[[AVAL:.*]] = fir.convert %[[AVAL_CVT]] : (complex<bf16>) -> !fir.complex<3>
52+
! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref<!fir.complex<3>>
53+
subroutine div_test_bfloat(a,b,c)
54+
complex(kind=3) :: a, b, c
55+
a = b / c
56+
end subroutine div_test_bfloat
57+
58+
! CHECK-LABEL: @_QPdiv_test_single
59+
! CHECK-SAME: %[[AREF:.*]]: !fir.ref<!fir.complex<4>> {{.*}}, %[[BREF:.*]]: !fir.ref<!fir.complex<4>> {{.*}}, %[[CREF:.*]]: !fir.ref<!fir.complex<4>> {{.*}})
60+
! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref<!fir.complex<4>>
61+
! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref<!fir.complex<4>>
62+
! CHECK: %[[AVAL:.*]] = fir.call @__divsc3(%[[BVAL]], %[[CVAL]]) fastmath<contract> : (!fir.complex<4>, !fir.complex<4>) -> !fir.complex<4>
63+
! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref<!fir.complex<4>>
64+
subroutine div_test_single(a,b,c)
65+
complex(kind=4) :: a, b, c
66+
a = b / c
67+
end subroutine div_test_single
68+
69+
! CHECK-LABEL: @_QPdiv_test_double
70+
! CHECK-SAME: %[[AREF:.*]]: !fir.ref<!fir.complex<8>> {{.*}}, %[[BREF:.*]]: !fir.ref<!fir.complex<8>> {{.*}}, %[[CREF:.*]]: !fir.ref<!fir.complex<8>> {{.*}})
71+
! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref<!fir.complex<8>>
72+
! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref<!fir.complex<8>>
73+
! CHECK: %[[AVAL:.*]] = fir.call @__divdc3(%[[BVAL]], %[[CVAL]]) fastmath<contract> : (!fir.complex<8>, !fir.complex<8>) -> !fir.complex<8>
74+
! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref<!fir.complex<8>>
75+
subroutine div_test_double(a,b,c)
76+
complex(kind=8) :: a, b, c
77+
a = b / c
78+
end subroutine div_test_double
79+
80+
! CHECK-LABEL: @_QPdiv_test_extended
81+
! CHECK-SAME: %[[AREF:.*]]: !fir.ref<!fir.complex<10>> {{.*}}, %[[BREF:.*]]: !fir.ref<!fir.complex<10>> {{.*}}, %[[CREF:.*]]: !fir.ref<!fir.complex<10>> {{.*}})
82+
! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref<!fir.complex<10>>
83+
! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref<!fir.complex<10>>
84+
! CHECK: %[[AVAL:.*]] = fir.call @__divxc3(%[[BVAL]], %[[CVAL]]) fastmath<contract> : (!fir.complex<10>, !fir.complex<10>) -> !fir.complex<10>
85+
! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref<!fir.complex<10>>
86+
subroutine div_test_extended(a,b,c)
87+
complex(kind=10) :: a, b, c
88+
a = b / c
89+
end subroutine div_test_extended
90+
91+
! CHECK-LABEL: @_QPdiv_test_quad
92+
! CHECK-SAME: %[[AREF:.*]]: !fir.ref<!fir.complex<16>> {{.*}}, %[[BREF:.*]]: !fir.ref<!fir.complex<16>> {{.*}}, %[[CREF:.*]]: !fir.ref<!fir.complex<16>> {{.*}})
93+
! CHECK: %[[BVAL:.*]] = fir.load %[[BREF]] : !fir.ref<!fir.complex<16>>
94+
! CHECK: %[[CVAL:.*]] = fir.load %[[CREF]] : !fir.ref<!fir.complex<16>>
95+
! CHECK: %[[AVAL:.*]] = fir.call @__divtc3(%[[BVAL]], %[[CVAL]]) fastmath<contract> : (!fir.complex<16>, !fir.complex<16>) -> !fir.complex<16>
96+
! CHECK: fir.store %[[AVAL]] to %[[AREF]] : !fir.ref<!fir.complex<16>>
97+
subroutine div_test_quad(a,b,c)
98+
complex(kind=16) :: a, b, c
3699
a = b / c
37-
end subroutine div_test
100+
end subroutine div_test_quad

0 commit comments

Comments
 (0)