From: Eli Friedman Date: Wed, 12 Jun 2013 01:40:06 +0000 (+0000) Subject: Add support for complex compound assignments where the LHS is a scalar. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0934e18b620ecaa6c7ec18ba5c4286b6122d6fb8;p=clang Add support for complex compound assignments where the LHS is a scalar. Fixes and PR12790. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183821 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 643ef91c89..e4b2f3b3fb 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -81,6 +81,9 @@ public: /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType, QualType DestType); + /// EmitComplexToComplexCast - Emit a cast from scalar value Val to DestType. + ComplexPairTy EmitScalarToComplexCast(llvm::Value *Val, QualType SrcType, + QualType DestType); //===--------------------------------------------------------------------===// // Visitor Methods @@ -215,7 +218,7 @@ public: LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func) (const BinOpInfo &), - ComplexPairTy &Val); + RValue &Val); ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func) (const BinOpInfo &)); @@ -379,6 +382,17 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val, return Val; } +ComplexPairTy ComplexExprEmitter::EmitScalarToComplexCast(llvm::Value *Val, + QualType SrcType, + QualType DestType) { + // Convert the input element to the element type of the complex. + DestType = DestType->castAs()->getElementType(); + Val = CGF.EmitScalarConversion(Val, SrcType, DestType); + + // Return (realval, 0). + return ComplexPairTy(Val, llvm::Constant::getNullValue(Val->getType())); +} + ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, QualType DestTy) { switch (CK) { @@ -446,16 +460,9 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: - case CK_IntegralRealToComplex: { - llvm::Value *Elt = CGF.EmitScalarExpr(Op); - - // Convert the input element to the element type of the complex. - DestTy = DestTy->castAs()->getElementType(); - Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy); - - // Return (realval, 0). - return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType())); - } + case CK_IntegralRealToComplex: + return EmitScalarToComplexCast(CGF.EmitScalarExpr(Op), + Op->getType(), DestTy); case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: @@ -610,7 +617,7 @@ ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) { LValue ComplexExprEmitter:: EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&), - ComplexPairTy &Val) { + RValue &Val) { TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); QualType LHSTy = E->getLHS()->getType(); @@ -630,20 +637,29 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E, LValue LHS = CGF.EmitLValue(E->getLHS()); - // Load from the l-value. - ComplexPairTy LHSComplexPair = EmitLoadOfLValue(LHS); - - OpInfo.LHS = EmitComplexToComplexCast(LHSComplexPair, LHSTy, OpInfo.Ty); + // Load from the l-value and convert it. + if (LHSTy->isAnyComplexType()) { + ComplexPairTy LHSVal = EmitLoadOfLValue(LHS); + OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty); + } else { + llvm::Value *LHSVal = CGF.EmitLoadOfScalar(LHS); + OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty); + } // Expand the binary operator. ComplexPairTy Result = (this->*Func)(OpInfo); - // Truncate the result back to the LHS type. - Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); - Val = Result; - - // Store the result value into the LHS lvalue. - EmitStoreOfComplex(Result, LHS, /*isInit*/ false); + // Truncate the result and store it into the LHS lvalue. + if (LHSTy->isAnyComplexType()) { + ComplexPairTy ResVal = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); + EmitStoreOfComplex(ResVal, LHS, /*isInit*/ false); + Val = RValue::getComplex(ResVal); + } else { + llvm::Value *ResVal = + CGF.EmitComplexToScalarConversion(Result, OpInfo.Ty, LHSTy); + CGF.EmitStoreOfScalar(ResVal, LHS, /*isInit*/ false); + Val = RValue::get(ResVal); + } return LHS; } @@ -652,16 +668,16 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E, ComplexPairTy ComplexExprEmitter:: EmitCompoundAssign(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){ - ComplexPairTy Val; + RValue Val; LValue LV = EmitCompoundAssignLValue(E, Func, Val); // The result of an assignment in C is the assigned r-value. if (!CGF.getLangOpts().CPlusPlus) - return Val; + return Val.getComplexVal(); // If the lvalue is non-volatile, return the computed value of the assignment. if (!LV.isVolatileQualified()) - return Val; + return Val.getComplexVal(); return EmitLoadOfLValue(LV); } @@ -832,19 +848,33 @@ LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) { return ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val); } -LValue CodeGenFunction:: -EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) { - ComplexPairTy(ComplexExprEmitter::*Op)(const ComplexExprEmitter::BinOpInfo &); - switch (E->getOpcode()) { - case BO_MulAssign: Op = &ComplexExprEmitter::EmitBinMul; break; - case BO_DivAssign: Op = &ComplexExprEmitter::EmitBinDiv; break; - case BO_SubAssign: Op = &ComplexExprEmitter::EmitBinSub; break; - case BO_AddAssign: Op = &ComplexExprEmitter::EmitBinAdd; break; +typedef ComplexPairTy (ComplexExprEmitter::*CompoundFunc)( + const ComplexExprEmitter::BinOpInfo &); +static CompoundFunc getComplexOp(BinaryOperatorKind Op) { + switch (Op) { + case BO_MulAssign: return &ComplexExprEmitter::EmitBinMul; + case BO_DivAssign: return &ComplexExprEmitter::EmitBinDiv; + case BO_SubAssign: return &ComplexExprEmitter::EmitBinSub; + case BO_AddAssign: return &ComplexExprEmitter::EmitBinAdd; default: llvm_unreachable("unexpected complex compound assignment"); } +} - ComplexPairTy Val; // ignored +LValue CodeGenFunction:: +EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) { + CompoundFunc Op = getComplexOp(E->getOpcode()); + RValue Val; return ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val); } + +LValue CodeGenFunction:: +EmitScalarCompooundAssignWithComplex(const CompoundAssignOperator *E, + llvm::Value *&Result) { + CompoundFunc Op = getComplexOp(E->getOpcode()); + RValue Val; + LValue Ret = ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val); + Result = Val.getScalarVal(); + return Ret; +} diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 7fb8e87cbd..f055c67f0c 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1931,15 +1931,8 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( QualType LHSTy = E->getLHS()->getType(); BinOpInfo OpInfo; - if (E->getComputationResultType()->isAnyComplexType()) { - // This needs to go through the complex expression emitter, but it's a tad - // complicated to do that... I'm leaving it out for now. (Note that we do - // actually need the imaginary part of the RHS for multiplication and - // division.) - CGF.ErrorUnsupported(E, "complex compound assignment"); - Result = llvm::UndefValue::get(CGF.ConvertType(E->getType())); - return LValue(); - } + if (E->getComputationResultType()->isAnyComplexType()) + return CGF.EmitScalarCompooundAssignWithComplex(E, Result); // Emit the RHS first. __block variables need to have the rhs evaluated // first, plus this should improve codegen a little. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 81b5d05cf6..080c471d59 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1928,6 +1928,8 @@ public: /// Emit an l-value for an assignment (simple or compound) of complex type. LValue EmitComplexAssignmentLValue(const BinaryOperator *E); LValue EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E); + LValue EmitScalarCompooundAssignWithComplex(const CompoundAssignOperator *E, + llvm::Value *&Result); // Note: only available for agg return types LValue EmitBinaryOperatorLValue(const BinaryOperator *E); diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c index 1212660e87..e99a715281 100644 --- a/test/CodeGen/complex.c +++ b/test/CodeGen/complex.c @@ -32,8 +32,7 @@ void test3() { double Gr = __real g1; cf += D; - // FIXME: Currently unsupported! - //D += cf; + D += cf; cf /= g1; g1 = g1 + D; g1 = D + g1; @@ -51,8 +50,7 @@ void test3int() { i = __real ci1; cs += i; - // FIXME: Currently unsupported! - //D += cf; + D += cf; cs /= ci1; ci1 = ci1 + i; ci1 = i + ci1; diff --git a/test/CodeGen/volatile-1.c b/test/CodeGen/volatile-1.c index 65511593d3..42e576540f 100644 --- a/test/CodeGen/volatile-1.c +++ b/test/CodeGen/volatile-1.c @@ -313,3 +313,15 @@ void test1() { (void) x; return x; } + +// CHECK: define i32 @test2() +int test2() { + // CHECK: load volatile i32* + // CHECK-NEXT: load volatile i32* + // CHECK-NEXT: load volatile i32* + // CHECK-NEXT: add i32 + // CHECK-NEXT: add i32 + // CHECK-NEXT: store volatile i32 + // CHECK-NEXT: ret i32 + return i += ci; +}