r219557 - [complex] Teach Clang to preserve different-type operands to arithmetic

Chandler Carruth chandlerc at gmail.com
Tue Oct 14 11:15:21 PDT 2014


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 <bob.wilson at apple.com> 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 <bob.wilson at apple.com> 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 <chandlerc at gmail.com>
> 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
> >> cfe-commits at cs.uiuc.edu
> >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
> >
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141014/c4694675/attachment.html>


More information about the cfe-commits mailing list