Index: cfe/trunk/lib/AST/ExprConstant.cpp =================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp +++ cfe/trunk/lib/AST/ExprConstant.cpp @@ -7874,24 +7874,49 @@ 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 @@ 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 @@ 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 @@ 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); Index: cfe/trunk/lib/CodeGen/CGExprComplex.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExprComplex.cpp +++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp @@ -230,6 +230,9 @@ 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 @@ 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::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()->getElementType()); + Args.add(RValue::get(Op.LHS.second), + Op.Ty->castAs()->getElementType()); + Args.add(RValue::get(Op.RHS.first), + Op.Ty->castAs()->getElementType()); + Args.add(RValue::get(Op.RHS.second), + Op.Ty->castAs()->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 @@ 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 @@ // __block variables need to have the rhs evaluated first, plus this should // improve codegen a little. OpInfo.Ty = E->getComputationResultType(); + QualType ComplexElementTy = cast(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 @@ 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. Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -938,68 +938,6 @@ 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(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 @@ // 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(LHSType); + auto *RHSComplexType = dyn_cast(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 Index: cfe/trunk/test/CodeGen/complex-math.c =================================================================== --- cfe/trunk/test/CodeGen/complex-math.c +++ cfe/trunk/test/CodeGen/complex-math.c @@ -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; +} Index: cfe/trunk/test/SemaCXX/complex-folding.cpp =================================================================== --- cfe/trunk/test/SemaCXX/complex-folding.cpp +++ cfe/trunk/test/SemaCXX/complex-folding.cpp @@ -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);