Cool. I'm happy for you to add any conditional logic you need to for iOS, I wouldn't know where to begin there.
On Tue, Oct 14, 2014 at 10:39 AM, Bob Wilson <[email protected]> wrote: > 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 >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
