Nevermind. We’ll add those functions to the static library version of compiler-rt that we bundle with clang.
> On Oct 14, 2014, at 10:02 AM, Bob Wilson <[email protected]> wrote: > > Hmm. This is going to be interesting. Those libcalls are not available on iOS > for arm64 devices. We can add them for some future version but there’s > nothing we can do right now. Can you make the use of those libcalls > conditional and keep the old code to be used for iOS? > >> On Oct 10, 2014, at 5:57 PM, Chandler Carruth <[email protected]> wrote: >> >> Author: chandlerc >> Date: Fri Oct 10 19:57:18 2014 >> New Revision: 219557 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=219557&view=rev >> Log: >> [complex] Teach Clang to preserve different-type operands to arithmetic >> operators where one type is a C complex type, and to emit both the >> efficient and correct implementation for complex arithmetic according to >> C11 Annex G using this extra information. >> >> For both multiply and divide the old code was writing a long-hand >> reduced version of the math without any of the special handling of inf >> and NaN recommended by the standard here. Instead of putting more >> complexity here, this change does what GCC does which is to emit >> a libcall for the fully general case. >> >> However, the old code also failed to do the proper minimization of the >> set of operations when there was a mixed complex and real operation. In >> those cases, C provides a spec for much more minimal operations that are >> valid. Clang now emits the exact suggested operations. This change isn't >> *just* about performance though, without minimizing these operations, we >> again lose the correct handling of infinities and NaNs. It is critical >> that this happen in the frontend based on assymetric type operands to >> complex math operations. >> >> The performance implications of this change aren't trivial either. I've >> run a set of benchmarks in Eigen, an open source mathematics library >> that makes heavy use of complex. While a few have slowed down due to the >> libcall being introduce, most sped up and some by a huge amount: up to >> 100% and 140%. >> >> In order to make all of this work, also match the algorithm in the >> constant evaluator to the one in the runtime library. Currently it is >> a broken port of the simplifications from C's Annex G to the long-hand >> formulation of the algorithm. >> >> Splitting this patch up is very hard because none of this works without >> the AST change to preserve non-complex operands. Sorry for the enormous >> change. >> >> Follow-up changes will include support for sinking the libcalls onto >> cold paths in common cases and fastmath improvements to allow more >> aggressive backend folding. >> >> Differential Revision: http://reviews.llvm.org/D5698 >> >> Added: >> cfe/trunk/test/CodeGen/complex-math.c >> cfe/trunk/test/SemaCXX/complex-folding.cpp >> Modified: >> cfe/trunk/lib/AST/ExprConstant.cpp >> cfe/trunk/lib/CodeGen/CGExprComplex.cpp >> cfe/trunk/lib/Sema/SemaExpr.cpp >> >> Modified: cfe/trunk/lib/AST/ExprConstant.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=219557&r1=219556&r2=219557&view=diff >> ============================================================================== >> --- cfe/trunk/lib/AST/ExprConstant.cpp (original) >> +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Oct 10 19:57:18 2014 >> @@ -7874,24 +7874,49 @@ bool ComplexExprEvaluator::VisitBinaryOp >> if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma) >> return ExprEvaluatorBaseTy::VisitBinaryOperator(E); >> >> - bool LHSOK = Visit(E->getLHS()); >> + // Track whether the LHS or RHS is real at the type system level. When >> this is >> + // the case we can simplify our evaluation strategy. >> + bool LHSReal = false, RHSReal = false; >> + >> + bool LHSOK; >> + if (E->getLHS()->getType()->isRealFloatingType()) { >> + LHSReal = true; >> + APFloat &Real = Result.FloatReal; >> + LHSOK = EvaluateFloat(E->getLHS(), Real, Info); >> + if (LHSOK) { >> + Result.makeComplexFloat(); >> + Result.FloatImag = APFloat(Real.getSemantics()); >> + } >> + } else { >> + LHSOK = Visit(E->getLHS()); >> + } >> if (!LHSOK && !Info.keepEvaluatingAfterFailure()) >> return false; >> >> ComplexValue RHS; >> - if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK) >> + if (E->getRHS()->getType()->isRealFloatingType()) { >> + RHSReal = true; >> + APFloat &Real = RHS.FloatReal; >> + if (!EvaluateFloat(E->getRHS(), Real, Info) || !LHSOK) >> + return false; >> + RHS.makeComplexFloat(); >> + RHS.FloatImag = APFloat(Real.getSemantics()); >> + } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK) >> return false; >> >> - assert(Result.isComplexFloat() == RHS.isComplexFloat() && >> - "Invalid operands to binary operator."); >> + assert(!(LHSReal && RHSReal) && >> + "Cannot have both operands of a complex operation be real."); >> switch (E->getOpcode()) { >> default: return Error(E); >> case BO_Add: >> if (Result.isComplexFloat()) { >> Result.getComplexFloatReal().add(RHS.getComplexFloatReal(), >> APFloat::rmNearestTiesToEven); >> - Result.getComplexFloatImag().add(RHS.getComplexFloatImag(), >> - APFloat::rmNearestTiesToEven); >> + if (LHSReal) >> + Result.getComplexFloatImag() = RHS.getComplexFloatImag(); >> + else if (!RHSReal) >> + Result.getComplexFloatImag().add(RHS.getComplexFloatImag(), >> + APFloat::rmNearestTiesToEven); >> } else { >> Result.getComplexIntReal() += RHS.getComplexIntReal(); >> Result.getComplexIntImag() += RHS.getComplexIntImag(); >> @@ -7901,8 +7926,13 @@ bool ComplexExprEvaluator::VisitBinaryOp >> if (Result.isComplexFloat()) { >> Result.getComplexFloatReal().subtract(RHS.getComplexFloatReal(), >> APFloat::rmNearestTiesToEven); >> - Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(), >> - APFloat::rmNearestTiesToEven); >> + if (LHSReal) { >> + Result.getComplexFloatImag() = RHS.getComplexFloatImag(); >> + Result.getComplexFloatImag().changeSign(); >> + } else if (!RHSReal) { >> + Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(), >> + APFloat::rmNearestTiesToEven); >> + } >> } else { >> Result.getComplexIntReal() -= RHS.getComplexIntReal(); >> Result.getComplexIntImag() -= RHS.getComplexIntImag(); >> @@ -7910,25 +7940,75 @@ bool ComplexExprEvaluator::VisitBinaryOp >> break; >> case BO_Mul: >> if (Result.isComplexFloat()) { >> + // This is an implementation of complex multiplication according to >> the >> + // constraints laid out in C11 Annex G. The implemantion uses the >> + // following naming scheme: >> + // (a + ib) * (c + id) >> ComplexValue LHS = Result; >> - APFloat &LHS_r = LHS.getComplexFloatReal(); >> - APFloat &LHS_i = LHS.getComplexFloatImag(); >> - APFloat &RHS_r = RHS.getComplexFloatReal(); >> - APFloat &RHS_i = RHS.getComplexFloatImag(); >> - >> - APFloat Tmp = LHS_r; >> - Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); >> - Result.getComplexFloatReal() = Tmp; >> - Tmp = LHS_i; >> - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); >> - Result.getComplexFloatReal().subtract(Tmp, >> APFloat::rmNearestTiesToEven); >> - >> - Tmp = LHS_r; >> - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); >> - Result.getComplexFloatImag() = Tmp; >> - Tmp = LHS_i; >> - Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); >> - Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven); >> + APFloat &A = LHS.getComplexFloatReal(); >> + APFloat &B = LHS.getComplexFloatImag(); >> + APFloat &C = RHS.getComplexFloatReal(); >> + APFloat &D = RHS.getComplexFloatImag(); >> + APFloat &ResR = Result.getComplexFloatReal(); >> + APFloat &ResI = Result.getComplexFloatImag(); >> + if (LHSReal) { >> + assert(!RHSReal && "Cannot have two real operands for a complex >> op!"); >> + ResR = A * C; >> + ResI = A * D; >> + } else if (RHSReal) { >> + ResR = C * A; >> + ResI = C * B; >> + } else { >> + // In the fully general case, we need to handle NaNs and infinities >> + // robustly. >> + APFloat AC = A * C; >> + APFloat BD = B * D; >> + APFloat AD = A * D; >> + APFloat BC = B * C; >> + ResR = AC - BD; >> + ResI = AD + BC; >> + if (ResR.isNaN() && ResI.isNaN()) { >> + bool Recalc = false; >> + if (A.isInfinity() || B.isInfinity()) { >> + A = APFloat::copySign( >> + APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A); >> + B = APFloat::copySign( >> + APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B); >> + if (C.isNaN()) >> + C = APFloat::copySign(APFloat(C.getSemantics()), C); >> + if (D.isNaN()) >> + D = APFloat::copySign(APFloat(D.getSemantics()), D); >> + Recalc = true; >> + } >> + if (C.isInfinity() || D.isInfinity()) { >> + C = APFloat::copySign( >> + APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C); >> + D = APFloat::copySign( >> + APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D); >> + if (A.isNaN()) >> + A = APFloat::copySign(APFloat(A.getSemantics()), A); >> + if (B.isNaN()) >> + B = APFloat::copySign(APFloat(B.getSemantics()), B); >> + Recalc = true; >> + } >> + if (!Recalc && (AC.isInfinity() || BD.isInfinity() || >> + AD.isInfinity() || BC.isInfinity())) { >> + if (A.isNaN()) >> + A = APFloat::copySign(APFloat(A.getSemantics()), A); >> + if (B.isNaN()) >> + B = APFloat::copySign(APFloat(B.getSemantics()), B); >> + if (C.isNaN()) >> + C = APFloat::copySign(APFloat(C.getSemantics()), C); >> + if (D.isNaN()) >> + D = APFloat::copySign(APFloat(D.getSemantics()), D); >> + Recalc = true; >> + } >> + if (Recalc) { >> + ResR = APFloat::getInf(A.getSemantics()) * (A * C - B * D); >> + ResI = APFloat::getInf(A.getSemantics()) * (A * D + B * C); >> + } >> + } >> + } >> } else { >> ComplexValue LHS = Result; >> Result.getComplexIntReal() = >> @@ -7941,33 +8021,57 @@ bool ComplexExprEvaluator::VisitBinaryOp >> break; >> case BO_Div: >> if (Result.isComplexFloat()) { >> + // This is an implementation of complex division according to the >> + // constraints laid out in C11 Annex G. The implemantion uses the >> + // following naming scheme: >> + // (a + ib) / (c + id) >> ComplexValue LHS = Result; >> - APFloat &LHS_r = LHS.getComplexFloatReal(); >> - APFloat &LHS_i = LHS.getComplexFloatImag(); >> - APFloat &RHS_r = RHS.getComplexFloatReal(); >> - APFloat &RHS_i = RHS.getComplexFloatImag(); >> - APFloat &Res_r = Result.getComplexFloatReal(); >> - APFloat &Res_i = Result.getComplexFloatImag(); >> - >> - APFloat Den = RHS_r; >> - Den.multiply(RHS_r, APFloat::rmNearestTiesToEven); >> - APFloat Tmp = RHS_i; >> - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); >> - Den.add(Tmp, APFloat::rmNearestTiesToEven); >> - >> - Res_r = LHS_r; >> - Res_r.multiply(RHS_r, APFloat::rmNearestTiesToEven); >> - Tmp = LHS_i; >> - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); >> - Res_r.add(Tmp, APFloat::rmNearestTiesToEven); >> - Res_r.divide(Den, APFloat::rmNearestTiesToEven); >> - >> - Res_i = LHS_i; >> - Res_i.multiply(RHS_r, APFloat::rmNearestTiesToEven); >> - Tmp = LHS_r; >> - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); >> - Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven); >> - Res_i.divide(Den, APFloat::rmNearestTiesToEven); >> + APFloat &A = LHS.getComplexFloatReal(); >> + APFloat &B = LHS.getComplexFloatImag(); >> + APFloat &C = RHS.getComplexFloatReal(); >> + APFloat &D = RHS.getComplexFloatImag(); >> + APFloat &ResR = Result.getComplexFloatReal(); >> + APFloat &ResI = Result.getComplexFloatImag(); >> + if (RHSReal) { >> + ResR = A / C; >> + ResI = B / C; >> + } else { >> + if (LHSReal) { >> + // No real optimizations we can do here, stub out with zero. >> + B = APFloat::getZero(A.getSemantics()); >> + } >> + int DenomLogB = 0; >> + APFloat MaxCD = maxnum(abs(C), abs(D)); >> + if (MaxCD.isFinite()) { >> + DenomLogB = ilogb(MaxCD); >> + C = scalbn(C, -DenomLogB); >> + D = scalbn(D, -DenomLogB); >> + } >> + APFloat Denom = C * C + D * D; >> + ResR = scalbn((A * C + B * D) / Denom, -DenomLogB); >> + ResI = scalbn((B * C - A * D) / Denom, -DenomLogB); >> + if (ResR.isNaN() && ResI.isNaN()) { >> + if (Denom.isPosZero() && (!A.isNaN() || !B.isNaN())) { >> + ResR = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * A; >> + ResI = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * B; >> + } else if ((A.isInfinity() || B.isInfinity()) && C.isFinite() && >> + D.isFinite()) { >> + A = APFloat::copySign( >> + APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A); >> + B = APFloat::copySign( >> + APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B); >> + ResR = APFloat::getInf(ResR.getSemantics()) * (A * C + B * D); >> + ResI = APFloat::getInf(ResI.getSemantics()) * (B * C - A * D); >> + } else if (MaxCD.isInfinity() && A.isFinite() && B.isFinite()) { >> + C = APFloat::copySign( >> + APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C); >> + D = APFloat::copySign( >> + APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D); >> + ResR = APFloat::getZero(ResR.getSemantics()) * (A * C + B * D); >> + ResI = APFloat::getZero(ResI.getSemantics()) * (B * C - A * D); >> + } >> + } >> + } >> } else { >> if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0) >> return Error(E, diag::note_expr_divide_by_zero); >> >> Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=219557&r1=219556&r2=219557&view=diff >> ============================================================================== >> --- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original) >> +++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Fri Oct 10 19:57:18 2014 >> @@ -230,6 +230,9 @@ public: >> ComplexPairTy EmitBinMul(const BinOpInfo &Op); >> ComplexPairTy EmitBinDiv(const BinOpInfo &Op); >> >> + ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName, >> + const BinOpInfo &Op); >> + >> ComplexPairTy VisitBinAdd(const BinaryOperator *E) { >> return EmitBinAdd(EmitBinOps(E)); >> } >> @@ -528,9 +531,15 @@ ComplexPairTy ComplexExprEmitter::EmitBi >> >> if (Op.LHS.first->getType()->isFloatingPointTy()) { >> ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r"); >> - ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i"); >> + if (Op.LHS.second && Op.RHS.second) >> + ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i"); >> + else >> + ResI = Op.LHS.second ? Op.LHS.second : Op.RHS.second; >> + assert(ResI && "Only one operand may be real!"); >> } else { >> ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r"); >> + assert(Op.LHS.second && Op.RHS.second && >> + "Both operands of integer complex operators must be complex!"); >> ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i"); >> } >> return ComplexPairTy(ResR, ResI); >> @@ -539,63 +548,159 @@ ComplexPairTy ComplexExprEmitter::EmitBi >> ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) { >> llvm::Value *ResR, *ResI; >> if (Op.LHS.first->getType()->isFloatingPointTy()) { >> - ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r"); >> - ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i"); >> + ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r"); >> + if (Op.LHS.second && Op.RHS.second) >> + ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i"); >> + else >> + ResI = Op.LHS.second ? Op.LHS.second >> + : Builder.CreateFNeg(Op.RHS.second, "sub.i"); >> + assert(ResI && "Only one operand may be real!"); >> } else { >> - ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r"); >> + ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r"); >> + assert(Op.LHS.second && Op.RHS.second && >> + "Both operands of integer complex operators must be complex!"); >> ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i"); >> } >> return ComplexPairTy(ResR, ResI); >> } >> >> +/// \brief Emit a libcall for a binary operation on complex types. >> +ComplexPairTy ComplexExprEmitter::EmitComplexBinOpLibCall(StringRef >> LibCallName, >> + const BinOpInfo >> &Op) { >> + CallArgList Args; >> + Args.add(RValue::get(Op.LHS.first), >> + Op.Ty->castAs<ComplexType>()->getElementType()); >> + Args.add(RValue::get(Op.LHS.second), >> + Op.Ty->castAs<ComplexType>()->getElementType()); >> + Args.add(RValue::get(Op.RHS.first), >> + Op.Ty->castAs<ComplexType>()->getElementType()); >> + Args.add(RValue::get(Op.RHS.second), >> + Op.Ty->castAs<ComplexType>()->getElementType()); >> + >> + // We *must* use the full CG function call building logic here because the >> + // complex type has special ABI handling. >> + const CGFunctionInfo &FuncInfo = >> CGF.CGM.getTypes().arrangeFreeFunctionCall( >> + Op.Ty, Args, FunctionType::ExtInfo(), RequiredArgs::All); >> + llvm::FunctionType *FTy = CGF.CGM.getTypes().GetFunctionType(FuncInfo); >> + llvm::Constant *Func = CGF.CGM.CreateRuntimeFunction(FTy, LibCallName); >> + >> + llvm::Value *ArgVals[] = {Op.LHS.first, Op.LHS.second, Op.RHS.first, >> + Op.RHS.second}; >> + llvm::Value *Result = CGF.EmitRuntimeCall(Func, ArgVals); >> + >> + llvm::Value *ResR, *ResI; >> + if (Result->getType()->isVectorTy()) { >> + ResR = CGF.Builder.CreateExtractElement(Result, >> CGF.Builder.getInt32(0)); >> + ResI = CGF.Builder.CreateExtractElement(Result, >> CGF.Builder.getInt32(1)); >> + } else { >> + assert(Result->getType()->isAggregateType() && >> + "Only vector and aggregate libcall returns are supported!"); >> + unsigned ResRIndices[] = {0}; >> + ResR = CGF.Builder.CreateExtractValue(Result, ResRIndices); >> + unsigned ResIIndices[] = {1}; >> + ResI = CGF.Builder.CreateExtractValue(Result, ResIIndices); >> + } >> + return ComplexPairTy(ResR, ResI); >> +} >> >> +// See C11 Annex G.5.1 for the semantics of multiplicative operators on >> complex >> +// typed values. >> ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { >> using llvm::Value; >> Value *ResR, *ResI; >> >> if (Op.LHS.first->getType()->isFloatingPointTy()) { >> - Value *ResRl = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl"); >> - Value *ResRr = Builder.CreateFMul(Op.LHS.second, >> Op.RHS.second,"mul.rr"); >> - ResR = Builder.CreateFSub(ResRl, ResRr, "mul.r"); >> - >> - Value *ResIl = Builder.CreateFMul(Op.LHS.second, Op.RHS.first, >> "mul.il"); >> - Value *ResIr = Builder.CreateFMul(Op.LHS.first, Op.RHS.second, >> "mul.ir"); >> - ResI = Builder.CreateFAdd(ResIl, ResIr, "mul.i"); >> + // The general formulation is: >> + // (a + ib) * (c + id) = (a * c - b * d) + i(a * d + b * c) >> + // >> + // But we can fold away components which would be zero due to a real >> + // operand according to C11 Annex G.5.1p2. >> + // FIXME: C11 also provides for imaginary types which would allow >> folding >> + // still more of this within the type system. >> + >> + if (Op.LHS.second && Op.RHS.second) { >> + // If both operands are complex, delegate to a libcall which works to >> + // prevent underflow and overflow. >> + StringRef LibCallName; >> + switch (Op.LHS.first->getType()->getTypeID()) { >> + default: >> + llvm_unreachable("Unsupported floating point type!"); >> + case llvm::Type::HalfTyID: >> + return EmitComplexBinOpLibCall("__mulhc3", Op); >> + case llvm::Type::FloatTyID: >> + return EmitComplexBinOpLibCall("__mulsc3", Op); >> + case llvm::Type::DoubleTyID: >> + return EmitComplexBinOpLibCall("__muldc3", Op); >> + case llvm::Type::X86_FP80TyID: >> + return EmitComplexBinOpLibCall("__mulxc3", Op); >> + } >> + } >> + assert((Op.LHS.second || Op.RHS.second) && >> + "At least one operand must be complex!"); >> + >> + // If either of the operands is a real rather than a complex, the >> + // imaginary component is ignored when computing the real component of >> the >> + // result. >> + ResR = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl"); >> + >> + ResI = Op.LHS.second >> + ? Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul.il") >> + : Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul.ir"); >> } else { >> + assert(Op.LHS.second && Op.RHS.second && >> + "Both operands of integer complex operators must be complex!"); >> Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl"); >> - Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr"); >> - ResR = Builder.CreateSub(ResRl, ResRr, "mul.r"); >> + Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second, >> "mul.rr"); >> + ResR = Builder.CreateSub(ResRl, ResRr, "mul.r"); >> >> Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il"); >> Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir"); >> - ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i"); >> + ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i"); >> } >> return ComplexPairTy(ResR, ResI); >> } >> >> +// See C11 Annex G.5.1 for the semantics of multiplicative operators on >> complex >> +// typed values. >> 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 (Op.LHS.first->getType()->isFloatingPointTy()) { >> - // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) >> - llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr); // a*c >> - llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi); // b*d >> - llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2); // ac+bd >> - >> - llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr); // c*c >> - llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi); // d*d >> - llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5); // cc+dd >> - >> - llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr); // b*c >> - llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi); // a*d >> - llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8); // bc-ad >> + 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. >> + // >> + // FIXME: We would be able to avoid the libcall in many places if we >> + // supported imaginary types in addition to complex types. >> + if (RHSi) { >> + BinOpInfo LibCallOp = Op; >> + // If LHS was a real, supply a null imaginary part. >> + if (!LHSi) >> + LibCallOp.LHS.second = >> llvm::Constant::getNullValue(LHSr->getType()); >> + >> + StringRef LibCallName; >> + switch (LHSr->getType()->getTypeID()) { >> + default: >> + llvm_unreachable("Unsupported floating point type!"); >> + case llvm::Type::HalfTyID: >> + return EmitComplexBinOpLibCall("__divhc3", LibCallOp); >> + case llvm::Type::FloatTyID: >> + return EmitComplexBinOpLibCall("__divsc3", LibCallOp); >> + case llvm::Type::DoubleTyID: >> + return EmitComplexBinOpLibCall("__divdc3", LibCallOp); >> + case llvm::Type::X86_FP80TyID: >> + return EmitComplexBinOpLibCall("__divxc3", LibCallOp); >> + } >> + } >> + assert(LHSi && "Can have at most one non-complex operand!"); >> >> - DSTr = Builder.CreateFDiv(Tmp3, Tmp6); >> - DSTi = Builder.CreateFDiv(Tmp9, Tmp6); >> + 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!"); >> // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) >> llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr); // a*c >> llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi); // b*d >> @@ -626,8 +731,15 @@ ComplexExprEmitter::EmitBinOps(const Bin >> TestAndClearIgnoreReal(); >> TestAndClearIgnoreImag(); >> BinOpInfo Ops; >> - Ops.LHS = Visit(E->getLHS()); >> - Ops.RHS = Visit(E->getRHS()); >> + if (E->getLHS()->getType()->isRealFloatingType()) >> + Ops.LHS = ComplexPairTy(CGF.EmitScalarExpr(E->getLHS()), nullptr); >> + else >> + Ops.LHS = Visit(E->getLHS()); >> + if (E->getRHS()->getType()->isRealFloatingType()) >> + Ops.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr); >> + else >> + Ops.RHS = Visit(E->getRHS()); >> + >> Ops.Ty = E->getType(); >> return Ops; >> } >> @@ -647,12 +759,19 @@ EmitCompoundAssignLValue(const CompoundA >> // __block variables need to have the rhs evaluated first, plus this should >> // improve codegen a little. >> OpInfo.Ty = E->getComputationResultType(); >> + QualType ComplexElementTy = >> cast<ComplexType>(OpInfo.Ty)->getElementType(); >> >> // The RHS should have been converted to the computation type. >> - assert(OpInfo.Ty->isAnyComplexType()); >> - assert(CGF.getContext().hasSameUnqualifiedType(OpInfo.Ty, >> - E->getRHS()->getType())); >> - OpInfo.RHS = Visit(E->getRHS()); >> + if (E->getRHS()->getType()->isRealFloatingType()) { >> + assert( >> + CGF.getContext() >> + .hasSameUnqualifiedType(ComplexElementTy, >> E->getRHS()->getType())); >> + OpInfo.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr); >> + } else { >> + assert(CGF.getContext() >> + .hasSameUnqualifiedType(OpInfo.Ty, E->getRHS()->getType())); >> + OpInfo.RHS = Visit(E->getRHS()); >> + } >> >> LValue LHS = CGF.EmitLValue(E->getLHS()); >> >> @@ -662,7 +781,15 @@ EmitCompoundAssignLValue(const CompoundA >> OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty); >> } else { >> llvm::Value *LHSVal = CGF.EmitLoadOfScalar(LHS, E->getExprLoc()); >> - OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty); >> + // For floating point real operands we can directly pass the scalar form >> + // to the binary operator emission and potentially get more efficient >> code. >> + if (LHSTy->isRealFloatingType()) { >> + if (!CGF.getContext().hasSameUnqualifiedType(ComplexElementTy, LHSTy)) >> + LHSVal = CGF.EmitScalarConversion(LHSVal, LHSTy, ComplexElementTy); >> + OpInfo.LHS = ComplexPairTy(LHSVal, nullptr); >> + } else { >> + OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty); >> + } >> } >> >> // Expand the binary operator. >> >> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=219557&r1=219556&r2=219557&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Oct 10 19:57:18 2014 >> @@ -938,68 +938,6 @@ static bool handleIntegerToComplexFloatC >> return false; >> } >> >> -/// \brief Takes two complex float types and converts them to the same type. >> -/// Helper function of UsualArithmeticConversions() >> -static QualType >> -handleComplexFloatToComplexFloatConverstion(Sema &S, ExprResult &LHS, >> - ExprResult &RHS, QualType >> LHSType, >> - QualType RHSType, >> - bool IsCompAssign) { >> - int order = S.Context.getFloatingTypeOrder(LHSType, RHSType); >> - >> - if (order < 0) { >> - // _Complex float -> _Complex double >> - if (!IsCompAssign) >> - LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingComplexCast); >> - return RHSType; >> - } >> - if (order > 0) >> - // _Complex float -> _Complex double >> - RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FloatingComplexCast); >> - return LHSType; >> -} >> - >> -/// \brief Converts otherExpr to complex float and promotes complexExpr if >> -/// necessary. Helper function of UsualArithmeticConversions() >> -static QualType handleOtherComplexFloatConversion(Sema &S, >> - ExprResult &ComplexExpr, >> - ExprResult &OtherExpr, >> - QualType ComplexTy, >> - QualType OtherTy, >> - bool ConvertComplexExpr, >> - bool ConvertOtherExpr) { >> - int order = S.Context.getFloatingTypeOrder(ComplexTy, OtherTy); >> - >> - // If just the complexExpr is complex, the otherExpr needs to be >> converted, >> - // and the complexExpr might need to be promoted. >> - if (order > 0) { // complexExpr is wider >> - // float -> _Complex double >> - if (ConvertOtherExpr) { >> - QualType fp = cast<ComplexType>(ComplexTy)->getElementType(); >> - OtherExpr = S.ImpCastExprToType(OtherExpr.get(), fp, CK_FloatingCast); >> - OtherExpr = S.ImpCastExprToType(OtherExpr.get(), ComplexTy, >> - CK_FloatingRealToComplex); >> - } >> - return ComplexTy; >> - } >> - >> - // otherTy is at least as wide. Find its corresponding complex type. >> - QualType result = (order == 0 ? ComplexTy : >> - S.Context.getComplexType(OtherTy)); >> - >> - // double -> _Complex double >> - if (ConvertOtherExpr) >> - OtherExpr = S.ImpCastExprToType(OtherExpr.get(), result, >> - CK_FloatingRealToComplex); >> - >> - // _Complex float -> _Complex double >> - if (ConvertComplexExpr && order < 0) >> - ComplexExpr = S.ImpCastExprToType(ComplexExpr.get(), result, >> - CK_FloatingComplexCast); >> - >> - return result; >> -} >> - >> /// \brief Handle arithmetic conversion with complex types. Helper function >> of >> /// UsualArithmeticConversions() >> static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, >> @@ -1025,26 +963,35 @@ static QualType handleComplexFloatConver >> // when combining a "long double" with a "double _Complex", the >> // "double _Complex" is promoted to "long double _Complex". >> >> - bool LHSComplexFloat = LHSType->isComplexType(); >> - bool RHSComplexFloat = RHSType->isComplexType(); >> + // Compute the rank of the two types, regardless of whether they are >> complex. >> + int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType); >> >> - // If both are complex, just cast to the more precise type. >> - if (LHSComplexFloat && RHSComplexFloat) >> - return handleComplexFloatToComplexFloatConverstion(S, LHS, RHS, >> - LHSType, RHSType, >> - IsCompAssign); >> - >> - // If only one operand is complex, promote it if necessary and convert the >> - // other operand to complex. >> - if (LHSComplexFloat) >> - return handleOtherComplexFloatConversion( >> - S, LHS, RHS, LHSType, RHSType, /*convertComplexExpr*/!IsCompAssign, >> - /*convertOtherExpr*/ true); >> - >> - assert(RHSComplexFloat); >> - return handleOtherComplexFloatConversion( >> - S, RHS, LHS, RHSType, LHSType, /*convertComplexExpr*/true, >> - /*convertOtherExpr*/ !IsCompAssign); >> + auto *LHSComplexType = dyn_cast<ComplexType>(LHSType); >> + auto *RHSComplexType = dyn_cast<ComplexType>(RHSType); >> + QualType LHSElementType = >> + LHSComplexType ? LHSComplexType->getElementType() : LHSType; >> + QualType RHSElementType = >> + RHSComplexType ? RHSComplexType->getElementType() : RHSType; >> + >> + QualType ResultType = S.Context.getComplexType(LHSElementType); >> + if (Order < 0) { >> + // Promote the precision of the LHS if not an assignment. >> + ResultType = S.Context.getComplexType(RHSElementType); >> + if (!IsCompAssign) { >> + if (LHSComplexType) >> + LHS = >> + S.ImpCastExprToType(LHS.get(), ResultType, >> CK_FloatingComplexCast); >> + else >> + LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, >> CK_FloatingCast); >> + } >> + } else if (Order > 0) { >> + // Promote the precision of the RHS. >> + if (RHSComplexType) >> + RHS = S.ImpCastExprToType(RHS.get(), ResultType, >> CK_FloatingComplexCast); >> + else >> + RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast); >> + } >> + return ResultType; >> } >> >> /// \brief Hande arithmetic conversion from integer to float. Helper >> function >> >> Added: cfe/trunk/test/CodeGen/complex-math.c >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/complex-math.c?rev=219557&view=auto >> ============================================================================== >> --- cfe/trunk/test/CodeGen/complex-math.c (added) >> +++ cfe/trunk/test/CodeGen/complex-math.c Fri Oct 10 19:57:18 2014 >> @@ -0,0 +1,367 @@ >> +// RUN: %clang_cc1 %s -O1 -emit-llvm -triple x86_64-unknown-unknown -o - | >> FileCheck %s --check-prefix=X86 >> + >> +float _Complex add_float_rr(float a, float b) { >> + // X86-LABEL: @add_float_rr( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +float _Complex add_float_cr(float _Complex a, float b) { >> + // X86-LABEL: @add_float_cr( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +float _Complex add_float_rc(float a, float _Complex b) { >> + // X86-LABEL: @add_float_rc( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +float _Complex add_float_cc(float _Complex a, float _Complex b) { >> + // X86-LABEL: @add_float_cc( >> + // X86: fadd >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> + >> +float _Complex sub_float_rr(float a, float b) { >> + // X86-LABEL: @sub_float_rr( >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +float _Complex sub_float_cr(float _Complex a, float b) { >> + // X86-LABEL: @sub_float_cr( >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +float _Complex sub_float_rc(float a, float _Complex b) { >> + // X86-LABEL: @sub_float_rc( >> + // X86: fsub >> + // X86: fsub float -0.{{0+}}e+00, >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +float _Complex sub_float_cc(float _Complex a, float _Complex b) { >> + // X86-LABEL: @sub_float_cc( >> + // X86: fsub >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> + >> +float _Complex mul_float_rr(float a, float b) { >> + // X86-LABEL: @mul_float_rr( >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +float _Complex mul_float_cr(float _Complex a, float b) { >> + // X86-LABEL: @mul_float_cr( >> + // X86: fmul >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +float _Complex mul_float_rc(float a, float _Complex b) { >> + // X86-LABEL: @mul_float_rc( >> + // X86: fmul >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +float _Complex mul_float_cc(float _Complex a, float _Complex b) { >> + // X86-LABEL: @mul_float_cc( >> + // X86-NOT: fmul >> + // X86: call <2 x float> @__mulsc3( >> + // X86: ret >> + return a * b; >> +} >> + >> +float _Complex div_float_rr(float a, float b) { >> + // X86-LABEL: @div_float_rr( >> + // X86: fdiv >> + // X86-NOT: fdiv >> + // X86: ret >> + return a / b; >> +} >> +float _Complex div_float_cr(float _Complex a, float b) { >> + // X86-LABEL: @div_float_cr( >> + // X86: fdiv >> + // X86: fdiv >> + // X86-NOT: fdiv >> + // X86: ret >> + return a / b; >> +} >> +float _Complex div_float_rc(float a, float _Complex b) { >> + // X86-LABEL: @div_float_rc( >> + // X86-NOT: fdiv >> + // X86: call <2 x float> @__divsc3( >> + // X86: ret >> + return a / b; >> +} >> +float _Complex div_float_cc(float _Complex a, float _Complex b) { >> + // X86-LABEL: @div_float_cc( >> + // X86-NOT: fdiv >> + // X86: call <2 x float> @__divsc3( >> + // X86: ret >> + return a / b; >> +} >> + >> +double _Complex add_double_rr(double a, double b) { >> + // X86-LABEL: @add_double_rr( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +double _Complex add_double_cr(double _Complex a, double b) { >> + // X86-LABEL: @add_double_cr( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +double _Complex add_double_rc(double a, double _Complex b) { >> + // X86-LABEL: @add_double_rc( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +double _Complex add_double_cc(double _Complex a, double _Complex b) { >> + // X86-LABEL: @add_double_cc( >> + // X86: fadd >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> + >> +double _Complex sub_double_rr(double a, double b) { >> + // X86-LABEL: @sub_double_rr( >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +double _Complex sub_double_cr(double _Complex a, double b) { >> + // X86-LABEL: @sub_double_cr( >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +double _Complex sub_double_rc(double a, double _Complex b) { >> + // X86-LABEL: @sub_double_rc( >> + // X86: fsub >> + // X86: fsub double -0.{{0+}}e+00, >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +double _Complex sub_double_cc(double _Complex a, double _Complex b) { >> + // X86-LABEL: @sub_double_cc( >> + // X86: fsub >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> + >> +double _Complex mul_double_rr(double a, double b) { >> + // X86-LABEL: @mul_double_rr( >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +double _Complex mul_double_cr(double _Complex a, double b) { >> + // X86-LABEL: @mul_double_cr( >> + // X86: fmul >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +double _Complex mul_double_rc(double a, double _Complex b) { >> + // X86-LABEL: @mul_double_rc( >> + // X86: fmul >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +double _Complex mul_double_cc(double _Complex a, double _Complex b) { >> + // X86-LABEL: @mul_double_cc( >> + // X86-NOT: fmul >> + // X86: call { double, double } @__muldc3( >> + // X86: ret >> + return a * b; >> +} >> + >> +double _Complex div_double_rr(double a, double b) { >> + // X86-LABEL: @div_double_rr( >> + // X86: fdiv >> + // X86-NOT: fdiv >> + // X86: ret >> + return a / b; >> +} >> +double _Complex div_double_cr(double _Complex a, double b) { >> + // X86-LABEL: @div_double_cr( >> + // X86: fdiv >> + // X86: fdiv >> + // X86-NOT: fdiv >> + // X86: ret >> + return a / b; >> +} >> +double _Complex div_double_rc(double a, double _Complex b) { >> + // X86-LABEL: @div_double_rc( >> + // X86-NOT: fdiv >> + // X86: call { double, double } @__divdc3( >> + // X86: ret >> + return a / b; >> +} >> +double _Complex div_double_cc(double _Complex a, double _Complex b) { >> + // X86-LABEL: @div_double_cc( >> + // X86-NOT: fdiv >> + // X86: call { double, double } @__divdc3( >> + // X86: ret >> + return a / b; >> +} >> + >> +long double _Complex add_long_double_rr(long double a, long double b) { >> + // X86-LABEL: @add_long_double_rr( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +long double _Complex add_long_double_cr(long double _Complex a, long double >> b) { >> + // X86-LABEL: @add_long_double_cr( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +long double _Complex add_long_double_rc(long double a, long double _Complex >> b) { >> + // X86-LABEL: @add_long_double_rc( >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> +long double _Complex add_long_double_cc(long double _Complex a, long double >> _Complex b) { >> + // X86-LABEL: @add_long_double_cc( >> + // X86: fadd >> + // X86: fadd >> + // X86-NOT: fadd >> + // X86: ret >> + return a + b; >> +} >> + >> +long double _Complex sub_long_double_rr(long double a, long double b) { >> + // X86-LABEL: @sub_long_double_rr( >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +long double _Complex sub_long_double_cr(long double _Complex a, long double >> b) { >> + // X86-LABEL: @sub_long_double_cr( >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +long double _Complex sub_long_double_rc(long double a, long double _Complex >> b) { >> + // X86-LABEL: @sub_long_double_rc( >> + // X86: fsub >> + // X86: fsub x86_fp80 0xK8{{0+}}, >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> +long double _Complex sub_long_double_cc(long double _Complex a, long double >> _Complex b) { >> + // X86-LABEL: @sub_long_double_cc( >> + // X86: fsub >> + // X86: fsub >> + // X86-NOT: fsub >> + // X86: ret >> + return a - b; >> +} >> + >> +long double _Complex mul_long_double_rr(long double a, long double b) { >> + // X86-LABEL: @mul_long_double_rr( >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +long double _Complex mul_long_double_cr(long double _Complex a, long double >> b) { >> + // X86-LABEL: @mul_long_double_cr( >> + // X86: fmul >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +long double _Complex mul_long_double_rc(long double a, long double _Complex >> b) { >> + // X86-LABEL: @mul_long_double_rc( >> + // X86: fmul >> + // X86: fmul >> + // X86-NOT: fmul >> + // X86: ret >> + return a * b; >> +} >> +long double _Complex mul_long_double_cc(long double _Complex a, long double >> _Complex b) { >> + // X86-LABEL: @mul_long_double_cc( >> + // X86-NOT: fmul >> + // X86: call { x86_fp80, x86_fp80 } @__mulxc3( >> + // X86: ret >> + return a * b; >> +} >> + >> +long double _Complex div_long_double_rr(long double a, long double b) { >> + // X86-LABEL: @div_long_double_rr( >> + // X86: fdiv >> + // X86-NOT: fdiv >> + // X86: ret >> + return a / b; >> +} >> +long double _Complex div_long_double_cr(long double _Complex a, long double >> b) { >> + // X86-LABEL: @div_long_double_cr( >> + // X86: fdiv >> + // X86: fdiv >> + // X86-NOT: fdiv >> + // X86: ret >> + return a / b; >> +} >> +long double _Complex div_long_double_rc(long double a, long double _Complex >> b) { >> + // X86-LABEL: @div_long_double_rc( >> + // X86-NOT: fdiv >> + // X86: call { x86_fp80, x86_fp80 } @__divxc3( >> + // X86: ret >> + return a / b; >> +} >> +long double _Complex div_long_double_cc(long double _Complex a, long double >> _Complex b) { >> + // X86-LABEL: @div_long_double_cc( >> + // X86-NOT: fdiv >> + // X86: call { x86_fp80, x86_fp80 } @__divxc3( >> + // X86: ret >> + return a / b; >> +} >> >> Added: cfe/trunk/test/SemaCXX/complex-folding.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/complex-folding.cpp?rev=219557&view=auto >> ============================================================================== >> --- cfe/trunk/test/SemaCXX/complex-folding.cpp (added) >> +++ cfe/trunk/test/SemaCXX/complex-folding.cpp Fri Oct 10 19:57:18 2014 >> @@ -0,0 +1,82 @@ >> +// RUN: %clang_cc1 %s -std=c++1z -fsyntax-only -verify >> +// >> +// Test the constant folding of builtin complex numbers. >> + >> +static_assert((0.0 + 0.0j) == (0.0 + 0.0j)); >> + >> +// Walk around the complex plane stepping between angular differences and >> +// equality. >> +static_assert((1.0 + 0.0j) == (0.0 + 0.0j)); // expected-error >> {{static_assert}} >> +static_assert((1.0 + 0.0j) == (1.0 + 0.0j)); >> +static_assert((1.0 + 1.0j) == (1.0 + 0.0j)); // expected-error >> {{static_assert}} >> +static_assert((1.0 + 1.0j) == (1.0 + 1.0j)); >> +static_assert((0.0 + 1.0j) == (1.0 + 1.0j)); // expected-error >> {{static_assert}} >> +static_assert((0.0 + 1.0j) == (0.0 + 1.0j)); >> +static_assert((-1.0 + 1.0j) == (0.0 + 1.0j)); // expected-error >> {{static_assert}} >> +static_assert((-1.0 + 1.0j) == (-1.0 + 1.0j)); >> +static_assert((-1.0 + 0.0j) == (-1.0 + 1.0j)); // expected-error >> {{static_assert}} >> +static_assert((-1.0 + 0.0j) == (-1.0 + 0.0j)); >> +static_assert((-1.0 - 1.0j) == (-1.0 + 0.0j)); // expected-error >> {{static_assert}} >> +static_assert((-1.0 - 1.0j) == (-1.0 - 1.0j)); >> +static_assert((0.0 - 1.0j) == (-1.0 - 1.0j)); // expected-error >> {{static_assert}} >> +static_assert((0.0 - 1.0j) == (0.0 - 1.0j)); >> +static_assert((1.0 - 1.0j) == (0.0 - 1.0j)); // expected-error >> {{static_assert}} >> +static_assert((1.0 - 1.0j) == (1.0 - 1.0j)); >> + >> +// Test basic mathematical folding of both complex and real operands. >> +static_assert(((1.0 + 0.5j) + (0.25 - 0.75j)) == (1.25 - 0.25j)); >> +static_assert(((1.0 + 0.5j) + 0.25) == (1.25 + 0.5j)); >> +static_assert((1.0 + (0.25 - 0.75j)) == (1.25 - 0.75j)); >> + >> +static_assert(((1.0 + 0.5j) - (0.25 - 0.75j)) == (0.75 + 1.25j)); >> +static_assert(((1.0 + 0.5j) - 0.25) == (0.75 + 0.5j)); >> +static_assert((1.0 - (0.25 - 0.75j)) == (0.75 + 0.75j)); >> + >> +static_assert(((1.25 + 0.5j) * (0.25 - 0.75j)) == (0.6875 - 0.8125j)); >> +static_assert(((1.25 + 0.5j) * 0.25) == (0.3125 + 0.125j)); >> +static_assert((1.25 * (0.25 - 0.75j)) == (0.3125 - 0.9375j)); >> + >> +static_assert(((1.25 + 0.5j) / (0.25 - 0.75j)) == (-0.1 + 1.7j)); >> +static_assert(((1.25 + 0.5j) / 0.25) == (5.0 + 2.0j)); >> +static_assert((1.25 / (0.25 - 0.75j)) == (0.5 + 1.5j)); >> + >> +// Test that infinities are preserved, don't turn into NaNs, and do form >> zeros >> +// when the divisor. >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * >> 1.0)) == 1); >> +static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) >> * 1.0)) == 1); >> +static_assert(__builtin_isinf_sign(__real__(1.0 * (__builtin_inf() + >> 1.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + __builtin_inf() * >> 1.0j))) == 1); >> + >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (1.0 >> + 1.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (__builtin_inf() >> + 1.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * >> (__builtin_inf() + 1.0j))) == 1); >> + >> +static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) >> * (1.0 + 1.0j))) == -1); >> +static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) >> * (1.0 + 1.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + >> __builtin_inf() * 1.0j))) == -1); >> +static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + >> __builtin_inf() * 1.0j))) == 1); >> + >> +static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) >> * (1.0 + __builtin_inf() * 1.0j))) == -1); >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + >> __builtin_inf() * 1.0j) * (__builtin_inf() + __builtin_inf() * 1.0j))) == >> -1); >> + >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (1.0 >> + 1.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) >> / (1.0 + 1.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + >> __builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / >> 1.0)) == 1); >> +static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) >> / 1.0)) == 1); >> +static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + >> __builtin_inf() * 1.0j) / 1.0)) == 1); >> + >> +static_assert(((1.0 + 1.0j) / (__builtin_inf() + 1.0j)) == (0.0 + 0.0j)); >> +static_assert(((1.0 + 1.0j) / (1.0 + __builtin_inf() * 1.0j)) == (0.0 + >> 0.0j)); >> +static_assert(((1.0 + 1.0j) / (__builtin_inf() + __builtin_inf() * 1.0j)) >> == (0.0 + 0.0j)); >> +static_assert(((1.0 + 1.0j) / __builtin_inf()) == (0.0 + 0.0j)); >> + >> +static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / (0.0 + 0.0j))) >> == 1); >> +static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1); >> + >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (0.0 >> + 0.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) >> / (0.0 + 0.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + >> __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1); >> +static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / >> 0.0)) == 1); >> +static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) >> / 0.0)) == 1); >> +static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + >> __builtin_inf() * 1.0j) / 0.0)) == 1); >> >> >> _______________________________________________ >> cfe-commits mailing list >> [email protected] >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
