Add support for complex compound assignments where the LHS is a scalar.

Fixes <rdar://problem/11224126> and PR12790.

llvm-svn: 183821
This commit is contained in:
Eli Friedman 2013-06-12 01:40:06 +00:00
parent d8cf1a119d
commit f045007f11
5 changed files with 82 additions and 47 deletions

View File

@ -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<ComplexType>()->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<ComplexType>()->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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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;
}