[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