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

Reply via email to