aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp37
1 files changed, 29 insertions, 8 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
index e860b3045f0e..9094d3f8a91c 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
@@ -761,15 +761,16 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
-
llvm::Value *DSTr, *DSTi;
if (LHSr->getType()->isFloatingPointTy()) {
- // If we have a complex operand on the RHS, we delegate to a libcall to
- // handle all of the complexities and minimize underflow/overflow cases.
+ // If we have a complex operand on the RHS and FastMath is not allowed, we
+ // delegate to a libcall to handle all of the complexities and minimize
+ // underflow/overflow cases. When FastMath is allowed we construct the
+ // divide inline using the same algorithm as for integer operands.
//
// FIXME: We would be able to avoid the libcall in many places if we
// supported imaginary types in addition to complex types.
- if (RHSi) {
+ if (RHSi && !CGF.getLangOpts().FastMath) {
BinOpInfo LibCallOp = Op;
// If LHS was a real, supply a null imaginary part.
if (!LHSi)
@@ -791,11 +792,31 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
case llvm::Type::FP128TyID:
return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
}
- }
- assert(LHSi && "Can have at most one non-complex operand!");
+ } else if (RHSi) {
+ if (!LHSi)
+ LHSi = llvm::Constant::getNullValue(RHSi->getType());
+
+ // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
+ llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
+ llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
+ llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
+
+ llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
+ llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
+ llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
- DSTr = Builder.CreateFDiv(LHSr, RHSr);
- DSTi = Builder.CreateFDiv(LHSi, RHSr);
+ llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
+ llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
+ llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
+
+ DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
+ DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
+ } else {
+ assert(LHSi && "Can have at most one non-complex operand!");
+
+ DSTr = Builder.CreateFDiv(LHSr, RHSr);
+ DSTi = Builder.CreateFDiv(LHSi, RHSr);
+ }
} else {
assert(Op.LHS.second && Op.RHS.second &&
"Both operands of integer complex operators must be complex!");