Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -761,15 +761,16 @@ 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()) { + llvm::FastMathFlags FMF = Builder.getFastMathFlags(); + // 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. // // 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 && !FMF.isFast()) { BinOpInfo LibCallOp = Op; // If LHS was a real, supply a null imaginary part. if (!LHSi) @@ -791,11 +792,31 @@ 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 - DSTr = Builder.CreateFDiv(LHSr, RHSr); - DSTi = Builder.CreateFDiv(LHSi, RHSr); + 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 + + 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!"); Index: test/CodeGen/complex-math.c =================================================================== --- test/CodeGen/complex-math.c +++ test/CodeGen/complex-math.c @@ -5,6 +5,7 @@ // RUN %clang_cc1 %s -O1 -emit-llvm -triple armv7-none-linux-gnueabi -o - | FileCheck %s --check-prefix=ARM // RUN: %clang_cc1 %s -O1 -emit-llvm -triple armv7-none-linux-gnueabihf -o - | FileCheck %s --check-prefix=ARMHF // RUN: %clang_cc1 %s -O1 -emit-llvm -triple thumbv7k-apple-watchos2.0 -o - -target-abi aapcs16 | FileCheck %s --check-prefix=ARM7K +// RUN %clang_cc1 %s -O1 -ffast-math -emit-llvm -triple x86_64-unknown-unknown | FileCheck %s --check-prefix=FASTMATH float _Complex add_float_rr(float a, float b) { // X86-LABEL: @add_float_rr( @@ -128,6 +129,12 @@ // X86-NOT: fdiv // X86: call {{.*}} @__divsc3( // X86: ret + // FASTMATH-LABEL: @div_float_rc( + // FASTMATH-NOT: @__divsc3 + // FASTMATH: fdiv + // FASTMATH: fdiv + // FASTMATH-NOT: fdiv + // FASTMATH: ret return a / b; } float _Complex div_float_cc(float _Complex a, float _Complex b) { @@ -135,6 +142,12 @@ // X86-NOT: fdiv // X86: call {{.*}} @__divsc3( // X86: ret + // FASTMATH-LABEL: @div_float_cc( + // FASTMATH-NOT: @__divsc3 + // FASTMATH: fdiv + // FASTMATH: fdiv + // FASTMATH-NOT: fdiv + // FASTMATH: ret return a / b; } @@ -260,6 +273,12 @@ // X86-NOT: fdiv // X86: call {{.*}} @__divdc3( // X86: ret + // FASTMATH-LABEL: @div_double_rc( + // FASTMATH-NOT: @__divdc3 + // FASTMATH: fdiv + // FASTMATH: fdiv + // FASTMATH-NOT: fdiv + // FASTMATH: ret return a / b; } double _Complex div_double_cc(double _Complex a, double _Complex b) { @@ -267,6 +286,12 @@ // X86-NOT: fdiv // X86: call {{.*}} @__divdc3( // X86: ret + // FASTMATH-LABEL: @div_double_cc( + // FASTMATH-NOT: @__divdc3 + // FASTMATH: fdiv + // FASTMATH: fdiv + // FASTMATH-NOT: fdiv + // FASTMATH: ret return a / b; } @@ -410,6 +435,12 @@ // PPC-NOT: fdiv // PPC: call {{.*}} @__divtc3( // PPC: ret + // FASTMATH-LABEL: @div_long_double_rc( + // FASTMATH-NOT: @__divxc3 + // FASTMATH: fdiv + // FASTMATH: fdiv + // FASTMATH-NOT: fdiv + // FASTMATH: ret return a / b; } long double _Complex div_long_double_cc(long double _Complex a, long double _Complex b) { @@ -421,6 +452,12 @@ // PPC-NOT: fdiv // PPC: call {{.*}} @__divtc3( // PPC: ret + // FASTMATH-LABEL: @div_double_cc( + // FASTMATH-NOT: @__divxc3 + // FASTMATH: fdiv + // FASTMATH: fdiv + // FASTMATH-NOT: fdiv + // FASTMATH: ret return a / b; }