[cfe-commits] r119344 - in /cfe/trunk: lib/AST/ExprClassification.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CodeGenFunction.h test/CodeGen/assign.c test/CodeGen/volatile-1.c
John McCall
rjmccall at apple.com
Tue Nov 16 02:08:08 PST 2010
Author: rjmccall
Date: Tue Nov 16 04:08:07 2010
New Revision: 119344
URL: http://llvm.org/viewvc/llvm-project?rev=119344&view=rev
Log:
Simplify some complex emission and implement correct semantics for
assignment to volatiles in C. This in effect reverts some of mjs's
work in and around r72572. Basically, the C++ standard is quite
clear, except that it lies about volatile behavior approximating
C's, whereas the C standard is almost actively misleading.
Modified:
cfe/trunk/lib/AST/ExprClassification.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprComplex.cpp
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGen/assign.c
cfe/trunk/test/CodeGen/volatile-1.c
Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=119344&r1=119343&r2=119344&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Tue Nov 16 04:08:07 2010
@@ -171,11 +171,23 @@
return Cl::CL_LValue;
// GNU extensions, simply look through them.
- case UO_Real:
- case UO_Imag:
case UO_Extension:
return ClassifyInternal(Ctx, cast<UnaryOperator>(E)->getSubExpr());
+ // Treat _Real and _Imag basically as if they were member
+ // expressions: l-value only if the operand is a true l-value.
+ case UO_Real:
+ case UO_Imag: {
+ const Expr *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
+ Cl::Kinds K = ClassifyInternal(Ctx, Op);
+ if (K != Cl::CL_LValue) return K;
+
+ if (isa<ObjCPropertyRefExpr>(Op) ||
+ isa<ObjCImplicitSetterGetterRefExpr>(Op))
+ return Cl::CL_SubObjCPropertySetting;
+ return Cl::CL_LValue;
+ }
+
// C++ [expr.pre.incr]p1: The result is the updated operand; it is an
// lvalue, [...]
// Not so in C.
@@ -343,7 +355,7 @@
if (E->isArrow())
return Cl::CL_LValue;
// ObjC property accesses are not lvalues, but get special treatment.
- Expr *Base = E->getBase();
+ Expr *Base = E->getBase()->IgnoreParens();
if (isa<ObjCPropertyRefExpr>(Base) ||
isa<ObjCImplicitSetterGetterRefExpr>(Base))
return Cl::CL_SubObjCPropertySetting;
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=119344&r1=119343&r2=119344&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Nov 16 04:08:07 2010
@@ -87,8 +87,7 @@
if (!hasAggregateLLVMType(E->getType()))
return RValue::get(EmitScalarExpr(E, IgnoreResult));
else if (E->getType()->isAnyComplexType())
- return RValue::getComplex(EmitComplexExpr(E, false, false,
- IgnoreResult, IgnoreResult));
+ return RValue::getComplex(EmitComplexExpr(E, IgnoreResult, IgnoreResult));
EmitAggExpr(E, AggSlot, IgnoreResult);
return AggSlot.asRValue();
Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=119344&r1=119343&r2=119344&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Tue Nov 16 04:08:07 2010
@@ -35,14 +35,9 @@
// True is we should ignore the value of a
bool IgnoreReal;
bool IgnoreImag;
- // True if we should ignore the value of a=b
- bool IgnoreRealAssign;
- bool IgnoreImagAssign;
public:
- ComplexExprEmitter(CodeGenFunction &cgf, bool ir=false, bool ii=false,
- bool irn=false, bool iin=false)
- : CGF(cgf), Builder(CGF.Builder), IgnoreReal(ir), IgnoreImag(ii),
- IgnoreRealAssign(irn), IgnoreImagAssign(iin) {
+ ComplexExprEmitter(CodeGenFunction &cgf, bool ir=false, bool ii=false)
+ : CGF(cgf), Builder(CGF.Builder), IgnoreReal(ir), IgnoreImag(ii) {
}
@@ -60,16 +55,6 @@
IgnoreImag = false;
return I;
}
- bool TestAndClearIgnoreRealAssign() {
- bool I = IgnoreRealAssign;
- IgnoreRealAssign = false;
- return I;
- }
- bool TestAndClearIgnoreImagAssign() {
- bool I = IgnoreImagAssign;
- IgnoreImagAssign = false;
- return I;
- }
/// EmitLoadOfLValue - Given an expression with complex type that represents a
/// value l-value, this method emits the address of the l-value, then loads
@@ -174,8 +159,6 @@
ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
- TestAndClearIgnoreRealAssign();
- TestAndClearIgnoreImagAssign();
return Visit(E->getSubExpr());
}
ComplexPairTy VisitUnaryMinus (const UnaryOperator *E);
@@ -211,6 +194,10 @@
};
BinOpInfo EmitBinOps(const BinaryOperator *E);
+ LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
+ ComplexPairTy (ComplexExprEmitter::*Func)
+ (const BinOpInfo &),
+ ComplexPairTy &Val);
ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
ComplexPairTy (ComplexExprEmitter::*Func)
(const BinOpInfo &));
@@ -220,15 +207,15 @@
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
- ComplexPairTy VisitBinMul(const BinaryOperator *E) {
- return EmitBinMul(EmitBinOps(E));
- }
ComplexPairTy VisitBinAdd(const BinaryOperator *E) {
return EmitBinAdd(EmitBinOps(E));
}
ComplexPairTy VisitBinSub(const BinaryOperator *E) {
return EmitBinSub(EmitBinOps(E));
}
+ ComplexPairTy VisitBinMul(const BinaryOperator *E) {
+ return EmitBinMul(EmitBinOps(E));
+ }
ComplexPairTy VisitBinDiv(const BinaryOperator *E) {
return EmitBinDiv(EmitBinOps(E));
}
@@ -251,6 +238,9 @@
// Logical and/or always return int, never complex.
// No comparisons produce a complex result.
+
+ LValue EmitBinAssignLValue(const BinaryOperator *E,
+ ComplexPairTy &Val);
ComplexPairTy VisitBinAssign (const BinaryOperator *E);
ComplexPairTy VisitBinComma (const BinaryOperator *E);
@@ -383,8 +373,6 @@
ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
- TestAndClearIgnoreRealAssign();
- TestAndClearIgnoreImagAssign();
ComplexPairTy Op = Visit(E->getSubExpr());
llvm::Value *ResR, *ResI;
@@ -401,8 +389,6 @@
ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
- TestAndClearIgnoreRealAssign();
- TestAndClearIgnoreImagAssign();
// ~(a+ib) = a + i*-b
ComplexPairTy Op = Visit(E->getSubExpr());
llvm::Value *ResI;
@@ -516,8 +502,6 @@
ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
- TestAndClearIgnoreRealAssign();
- TestAndClearIgnoreImagAssign();
BinOpInfo Ops;
Ops.LHS = Visit(E->getLHS());
Ops.RHS = Visit(E->getRHS());
@@ -526,14 +510,12 @@
}
-// Compound assignments.
-ComplexPairTy ComplexExprEmitter::
-EmitCompoundAssign(const CompoundAssignOperator *E,
- ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
+LValue ComplexExprEmitter::
+EmitCompoundAssignLValue(const CompoundAssignOperator *E,
+ ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&),
+ ComplexPairTy &Val) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
- bool ignreal = TestAndClearIgnoreRealAssign();
- bool ignimag = TestAndClearIgnoreImagAssign();
QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
BinOpInfo OpInfo;
@@ -569,6 +551,7 @@
// Truncate the result back to the LHS type.
Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
+ Val = Result;
// Store the result value into the LHS lvalue.
if (LHS.isPropertyRef())
@@ -579,30 +562,41 @@
else
EmitStoreOfComplex(Result, LHS.getAddress(), LHS.isVolatileQualified());
- // Restore the Ignore* flags.
- IgnoreReal = ignreal;
- IgnoreImag = ignimag;
- IgnoreRealAssign = ignreal;
- IgnoreImagAssign = ignimag;
-
+ return LHS;
+}
+
+// Compound assignments.
+ComplexPairTy ComplexExprEmitter::
+EmitCompoundAssign(const CompoundAssignOperator *E,
+ ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
+ ComplexPairTy Val;
+ LValue LV = EmitCompoundAssignLValue(E, Func, Val);
+
+ // The result of an assignment in C is the assigned r-value.
+ if (!CGF.getContext().getLangOptions().CPlusPlus)
+ return Val;
+
// Objective-C property assignment never reloads the value following a store.
- if (LHS.isPropertyRef() || LHS.isKVCRef())
- return Result;
+ if (LV.isPropertyRef() || LV.isKVCRef())
+ return Val;
- // Otherwise, reload the value.
- return EmitLoadOfComplex(LHS.getAddress(), LHS.isVolatileQualified());
+ // If the lvalue is non-volatile, return the computed value of the assignment.
+ if (!LV.isVolatileQualified())
+ return Val;
+
+ return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
}
-ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- bool ignreal = TestAndClearIgnoreRealAssign();
- bool ignimag = TestAndClearIgnoreImagAssign();
+LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
+ ComplexPairTy &Val) {
assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
E->getRHS()->getType()) &&
"Invalid assignment");
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+
// Emit the RHS.
- ComplexPairTy Val = Visit(E->getRHS());
+ Val = Visit(E->getRHS());
// Compute the address to store into.
LValue LHS = CGF.EmitLValue(E->getLHS());
@@ -615,13 +609,26 @@
else
EmitStoreOfComplex(Val, LHS.getAddress(), LHS.isVolatileQualified());
- // Restore the Ignore* flags.
- IgnoreReal = ignreal;
- IgnoreImag = ignimag;
- IgnoreRealAssign = ignreal;
- IgnoreImagAssign = ignimag;
+ return LHS;
+}
- return Val;
+ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+ ComplexPairTy Val;
+ LValue LV = EmitBinAssignLValue(E, Val);
+
+ // The result of an assignment in C is the assigned r-value.
+ if (!CGF.getContext().getLangOptions().CPlusPlus)
+ return Val;
+
+ // Objective-C property assignment never reloads the value following a store.
+ if (LV.isPropertyRef() || LV.isKVCRef())
+ return Val;
+
+ // If the lvalue is non-volatile, return the computed value of the assignment.
+ if (!LV.isVolatileQualified())
+ return Val;
+
+ return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
}
ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
@@ -632,11 +639,8 @@
ComplexPairTy ComplexExprEmitter::
VisitConditionalOperator(const ConditionalOperator *E) {
-
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
- TestAndClearIgnoreRealAssign();
- TestAndClearIgnoreImagAssign();
llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
@@ -724,12 +728,11 @@
/// EmitComplexExpr - Emit the computation of the specified expression of
/// complex type, ignoring the result.
ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
- bool IgnoreImag, bool IgnoreRealAssign, bool IgnoreImagAssign) {
+ bool IgnoreImag) {
assert(E && E->getType()->isAnyComplexType() &&
"Invalid complex expression to emit");
- return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag, IgnoreRealAssign,
- IgnoreImagAssign)
+ return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag)
.Visit(const_cast<Expr*>(E));
}
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=119344&r1=119343&r2=119344&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Nov 16 04:08:07 2010
@@ -1176,12 +1176,11 @@
case CK_FloatingComplexToReal:
case CK_IntegralComplexToReal:
- return CGF.EmitComplexExpr(E, false, true, false, true).first;
+ return CGF.EmitComplexExpr(E, false, true).first;
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToBoolean: {
- CodeGenFunction::ComplexPairTy V
- = CGF.EmitComplexExpr(E, false, false, false, false);
+ CodeGenFunction::ComplexPairTy V = CGF.EmitComplexExpr(E);
// TODO: kill this function off, inline appropriate case here
return EmitComplexToScalarConversion(V, E->getType(), DestTy);
@@ -1471,21 +1470,38 @@
Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
Expr *Op = E->getSubExpr();
- if (Op->getType()->isAnyComplexType())
- return CGF.EmitComplexExpr(Op, false, true, false, true).first;
+ if (Op->getType()->isAnyComplexType()) {
+ // If it's an l-value, load through the appropriate subobject l-value.
+ // Note that we have to ask E because Op might be an l-value that
+ // this won't work for, e.g. an Obj-C property.
+ if (E->isLvalue(CGF.getContext()) == Expr::LV_Valid)
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType())
+ .getScalarVal();
+
+ // Otherwise, calculate and project.
+ return CGF.EmitComplexExpr(Op, false, true).first;
+ }
+
return Visit(Op);
}
+
Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
Expr *Op = E->getSubExpr();
- if (Op->getType()->isAnyComplexType())
- return CGF.EmitComplexExpr(Op, true, false, true, false).second;
+ if (Op->getType()->isAnyComplexType()) {
+ // If it's an l-value, load through the appropriate subobject l-value.
+ // Note that we have to ask E because Op might be an l-value that
+ // this won't work for, e.g. an Obj-C property.
+ if (Op->isLvalue(CGF.getContext()) == Expr::LV_Valid)
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType())
+ .getScalarVal();
+
+ // Otherwise, calculate and project.
+ return CGF.EmitComplexExpr(Op, true, false).second;
+ }
// __imag on a scalar returns zero. Emit the subexpr to ensure side
// effects are evaluated, but not the actual value.
- if (E->isLvalue(CGF.getContext()) == Expr::LV_Valid)
- CGF.EmitLValue(Op);
- else
- CGF.EmitScalarExpr(Op, true);
+ CGF.EmitScalarExpr(Op, true);
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
@@ -1562,6 +1578,10 @@
if (Ignore)
return 0;
+ // The result of an assignment in C is the assigned r-value.
+ if (!CGF.getContext().getLangOptions().CPlusPlus)
+ return RHS;
+
// Objective-C property assignment never reloads the value following a store.
if (LHS.isPropertyRef() || LHS.isKVCRef())
return RHS;
@@ -2050,6 +2070,10 @@
if (Ignore)
return 0;
+ // The result of an assignment in C is the assigned r-value.
+ if (!CGF.getContext().getLangOptions().CPlusPlus)
+ return RHS;
+
// Objective-C property assignment never reloads the value following a store.
if (LHS.isPropertyRef() || LHS.isKVCRef())
return RHS;
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=119344&r1=119343&r2=119344&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Nov 16 04:08:07 2010
@@ -1593,10 +1593,9 @@
/// EmitComplexExpr - Emit the computation of the specified expression of
/// complex type, returning the result.
- ComplexPairTy EmitComplexExpr(const Expr *E, bool IgnoreReal = false,
- bool IgnoreImag = false,
- bool IgnoreRealAssign = false,
- bool IgnoreImagAssign = false);
+ ComplexPairTy EmitComplexExpr(const Expr *E,
+ bool IgnoreReal = false,
+ bool IgnoreImag = false);
/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
/// of complex type, storing into the specified Value*.
Modified: cfe/trunk/test/CodeGen/assign.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/assign.c?rev=119344&r1=119343&r2=119344&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/assign.c (original)
+++ cfe/trunk/test/CodeGen/assign.c Tue Nov 16 04:08:07 2010
@@ -15,15 +15,15 @@
y = (x = 1);
}
-// Check that we do generate reloads for volatile access.
+// This used to test that we generate reloads for volatile access,
+// but that does not appear to be correct behavior for C.
//
// CHECK: define void @f1()
// CHECK: [[x_1:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[y_1:%.*]] = alloca i32, align 4
// CHECK-NEXT: volatile store i32 1, i32* [[x_1]]
// CHECK-NEXT: volatile store i32 1, i32* [[x_1]]
-// CHECK-NEXT: [[tmp_1:%.*]] = volatile load i32* [[x_1]]
-// CHECK-NEXT: volatile store i32 [[tmp_1]], i32* [[y_1]]
+// CHECK-NEXT: volatile store i32 1, i32* [[y_1]]
// CHECK: }
void f1() {
volatile int x, y;
Modified: cfe/trunk/test/CodeGen/volatile-1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/volatile-1.c?rev=119344&r1=119343&r2=119344&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/volatile-1.c (original)
+++ cfe/trunk/test/CodeGen/volatile-1.c Tue Nov 16 04:08:07 2010
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -Wno-unused-value -emit-llvm < %s -o %t
-// RUN: grep volatile %t | count 145
-// RUN: grep memcpy %t | count 4
+// RUN: %clang_cc1 -Wno-unused-value -emit-llvm %s -o - | FileCheck %s
+// CHECK: @i = common global [[INT:i[0-9]+]] 0
volatile int i, j, k;
volatile int ar[5];
volatile char c;
+// CHECK: @ci = common global [[CINT:%.*]] zeroinitializer
volatile _Complex int ci;
volatile struct S {
#ifdef __cplusplus
@@ -16,67 +16,190 @@
//void operator =(volatile struct S&o1, volatile struct S&o2) volatile;
int printf(const char *, ...);
-int main() {
- // A use.
+
+// Note that these test results are very much specific to C!
+// Assignments in C++ yield l-values, not r-values, and the situations
+// that do implicit lvalue-to-rvalue conversion are substantially
+// reduced.
+
+// CHECK: define void @test()
+void test() {
+ // CHECK: volatile load [[INT]]* @i
i;
- // A use of the real part
+ // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: sitofp [[INT]]
(float)(ci);
- // A use.
+ // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
(void)ci;
- // A use.
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: memcpy
(void)a;
- // Not a use.
+ // CHECK-NEXT: [[R:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
(void)(ci=ci);
- // Not a use.
+ // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* @j
+ // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* @i
(void)(i=j);
+ // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // Not sure why they're ordered this way.
+ // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
+ // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
+ // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
ci+=ci;
+
+ // CHECK-NEXT: [[R1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I1:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]]
+ // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]]
+ // CHECK-NEXT: volatile store [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: volatile store [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: [[R2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0)
+ // CHECK-NEXT: [[I2:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // These additions can be elided
+ // CHECK-NEXT: add [[INT]] [[R]], [[R2]]
+ // CHECK-NEXT: add [[INT]] [[I]], [[I2]]
(ci += ci) + ci;
+ // CHECK-NEXT: call void asm
asm("nop");
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: add nsw [[INT]]
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: add nsw [[INT]]
(i += j) + k;
+ // CHECK-NEXT: call void asm
asm("nop");
- // A use
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: add nsw [[INT]]
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: add nsw [[INT]]
(i += j) + 1;
+ // CHECK-NEXT: call void asm
asm("nop");
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: add [[INT]]
+ // CHECK-NEXT: add [[INT]]
ci+ci;
- // A use.
+
+ // CHECK-NEXT: volatile load
__real i;
- // A use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ci;
+ // CHECK-NEXT: call void asm
asm("nop");
- // Not a use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
(void)(i=i);
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: sitofp
(float)(i=i);
- // A use.
+ // CHECK-NEXT: volatile load
(void)i;
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
i=i;
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
i=i=i;
#ifndef __cplusplus
- // Not a use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
(void)__builtin_choose_expr(0, i=i, j=j);
#endif
- // A use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: icmp
+ // CHECK-NEXT: br i1
+ // CHECK: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: br label
+ // CHECK: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: br label
k ? (i=i) : (j=j);
+ // CHECK: phi
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
(void)(i,(i=i));
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile load
i=i,i;
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
(i=j,k=j);
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile load
(i=j,k);
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
(i,j);
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: trunc
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: sext
+ // CHECK-NEXT: volatile store
i=c=k;
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: add nsw [[INT]]
+ // CHECK-NEXT: volatile store
i+=k;
- // A use of both.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
ci;
#ifndef __cplusplus
- // A use of _real.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
(int)ci;
- // A use of both.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: icmp ne
+ // CHECK-NEXT: icmp ne
+ // CHECK-NEXT: or i1
(_Bool)ci;
#endif
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
ci=ci;
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
ci=ci=ci;
+ // CHECK-NEXT: [[T:%.*]] = volatile load [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
+ // CHECK-NEXT: volatile store [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1)
__imag ci = __imag ci = __imag ci;
- // Not a use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
__real (i = j);
- // Not a use.
+ // CHECK-NEXT: volatile load
__imag i;
// ============================================================
@@ -91,6 +214,9 @@
// gcc.
// Not a use. gcc forgets to do the assignment.
+ // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true
((a=a),a);
// Not a use. gcc gets this wrong, it doesn't emit the copy!
@@ -98,38 +224,72 @@
// Not a use. gcc got this wrong in 4.2 and omitted the side effects
// entirely, but it is fixed in 4.4.0.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
__imag (i = j);
#ifndef __cplusplus
// A use of the real part
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: sitofp
(float)(ci=ci);
// Not a use, bug? gcc treats this as not a use, that's probably a bug due to
// tree folding ignoring volatile.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
(int)(ci=ci);
#endif
// A use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: sitofp
(float)(i=i);
// A use. gcc treats this as not a use, that's probably a bug due to tree
// folding ignoring volatile.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
(int)(i=i);
// A use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: sub
-(i=j);
// A use. gcc treats this a not a use, that's probably a bug due to tree
// folding ignoring volatile.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+(i=k);
// A use. gcc treats this a not a use, that's probably a bug due to tree
// folding ignoring volatile.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile store
__real (ci=ci);
// A use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: add
i + 0;
// A use.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: add
(i=j) + i;
// A use. gcc treats this as not a use, that's probably a bug due to tree
// folding ignoring volatile.
+ // CHECK-NEXT: volatile load
+ // CHECK-NEXT: volatile store
+ // CHECK-NEXT: add
(i=j) + 0;
#ifdef __cplusplus
More information about the cfe-commits
mailing list