]> granicus.if.org Git - clang/commitdiff
Fixup the rest of the trivial cases of the codegen of volatile. If
authorMike Stump <mrs@apple.com>
Fri, 29 May 2009 15:46:01 +0000 (15:46 +0000)
committerMike Stump <mrs@apple.com>
Fri, 29 May 2009 15:46:01 +0000 (15:46 +0000)
any body can spot codegen bugs with volatile, or knows of any in the
bug database, let me know.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72572 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGen/volatile-1.c [new file with mode: 0644]

index e965073c7f610aa88effe5d79c272c81e2a91331..3d07403b07fb12b2cd096db3c05754bf7811a233 100644 (file)
@@ -51,9 +51,10 @@ llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
 RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc, 
                                     bool isAggLocVolatile, bool IgnoreResult) {
   if (!hasAggregateLLVMType(E->getType()))
-    return RValue::get(EmitScalarExpr(E));
+    return RValue::get(EmitScalarExpr(E, IgnoreResult));
   else if (E->getType()->isAnyComplexType())
-    return RValue::getComplex(EmitComplexExpr(E));
+    return RValue::getComplex(EmitComplexExpr(E, false, false,
+                                              IgnoreResult, IgnoreResult));
   
   EmitAggExpr(E, AggLoc, isAggLocVolatile, IgnoreResult);
   return RValue::getAggregate(AggLoc, isAggLocVolatile);
index d90f701758c77e246110ec80b996707c2224992e..9ff8006e8c28bfb7ce62eb8651cac7cfb773c6df 100644 (file)
@@ -210,7 +210,7 @@ void AggExprEmitter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
 }
 
 void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
-  CGF.EmitAnyExpr(E->getLHS());
+  CGF.EmitAnyExpr(E->getLHS(), 0, false, true);
   CGF.EmitAggExpr(E->getRHS(), DestPtr, VolatileDest);
 }
 
@@ -311,6 +311,7 @@ void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
 }
 
 void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+  // FIXME: Ignore result?
   // FIXME: Are initializers affected by volatile?
   if (isa<ImplicitValueInitExpr>(E)) {
     EmitNullInitializationToLValue(LV, E->getType());
index 618e446bf1c3b85afa09bf9f480c041ba603d67d..6f8dc2c8393d3d498ba7feaaf1cbfdf2a46a77c8 100644 (file)
@@ -33,8 +33,17 @@ class VISIBILITY_HIDDEN ComplexExprEmitter
   : public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
   CodeGenFunction &CGF;
   CGBuilderTy &Builder;
+  // 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) : CGF(cgf), Builder(CGF.Builder) {
+  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) {
   }
 
   
@@ -42,6 +51,27 @@ public:
   //                               Utilities
   //===--------------------------------------------------------------------===//
 
+  bool TestAndClearIgnoreReal() {
+    bool I = IgnoreReal;
+    IgnoreReal = false;
+    return I;
+  }
+  bool TestAndClearIgnoreImag() {
+    bool I = IgnoreImag;
+    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
   /// and returns the result.
@@ -111,6 +141,10 @@ public:
   }
   ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
   ComplexPairTy VisitUnaryPlus     (const UnaryOperator *E) {
+    TestAndClearIgnoreReal();
+    TestAndClearIgnoreImag();
+    TestAndClearIgnoreRealAssign();
+    TestAndClearIgnoreImagAssign();
     return Visit(E->getSubExpr());
   }
   ComplexPairTy VisitUnaryMinus    (const UnaryOperator *E);
@@ -206,19 +240,25 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
   llvm::SmallString<64> Name(SrcPtr->getNameStart(),
                              SrcPtr->getNameStart()+SrcPtr->getNameLen());
   
-  Name += ".realp";
-  llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0, Name.c_str());
+  llvm::Value *Real=0, *Imag=0;
 
-  Name.pop_back();  // .realp -> .real
-  llvm::Value *Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str());
+  if (!IgnoreReal) {
+    Name += ".realp";
+    llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0, Name.c_str());
+
+    Name.pop_back();  // .realp -> .real
+    Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str());
+    Name.resize(Name.size()-4); // .real -> .imagp
+  }
   
-  Name.resize(Name.size()-4); // .real -> .imagp
-  Name += "imagp";
+  if (!IgnoreImag) {
+    Name += "imagp";
   
-  llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1, Name.c_str());
+    llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1, Name.c_str());
 
-  Name.pop_back();  // .imagp -> .imag
-  llvm::Value *Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str());
+    Name.pop_back();  // .imagp -> .imag
+    Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str());
+  }
   return ComplexPairTy(Real, Imag);
 }
 
@@ -331,6 +371,10 @@ ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
 }
 
 ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
+  TestAndClearIgnoreReal();
+  TestAndClearIgnoreImag();
+  TestAndClearIgnoreRealAssign();
+  TestAndClearIgnoreImagAssign();
   ComplexPairTy Op = Visit(E->getSubExpr());
   llvm::Value *ResR = Builder.CreateNeg(Op.first,  "neg.r");
   llvm::Value *ResI = Builder.CreateNeg(Op.second, "neg.i");
@@ -338,6 +382,10 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
 }
 
 ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
+  TestAndClearIgnoreReal();
+  TestAndClearIgnoreImag();
+  TestAndClearIgnoreRealAssign();
+  TestAndClearIgnoreImagAssign();
   // ~(a+ib) = a + i*-b
   ComplexPairTy Op = Visit(E->getSubExpr());
   llvm::Value *ResI = Builder.CreateNeg(Op.second, "conj.i");
@@ -404,6 +452,10 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
 
 ComplexExprEmitter::BinOpInfo 
 ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
+  TestAndClearIgnoreReal();
+  TestAndClearIgnoreImag();
+  TestAndClearIgnoreRealAssign();
+  TestAndClearIgnoreImagAssign();
   BinOpInfo Ops;
   Ops.LHS = Visit(E->getLHS());
   Ops.RHS = Visit(E->getRHS());
@@ -416,21 +468,28 @@ ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
 ComplexPairTy ComplexExprEmitter::
 EmitCompoundAssign(const CompoundAssignOperator *E,
                    ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
+  TestAndClearIgnoreReal();
+  TestAndClearIgnoreImag();
+  bool ignreal = TestAndClearIgnoreRealAssign();
+  bool ignimag = TestAndClearIgnoreImagAssign();
   QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
-  
-  // Load the LHS and RHS operands.
-  LValue LHSLV = CGF.EmitLValue(E->getLHS());
 
   BinOpInfo OpInfo;
+  
+  // Load the RHS and LHS operands.
+  // __block variables need to have the rhs evaluated first, plus this should
+  // improve codegen a little.  It is possible for the RHS to be complex or
+  // scalar.
   OpInfo.Ty = E->getComputationResultType();
+  OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
+  
+  LValue LHSLV = CGF.EmitLValue(E->getLHS());
+
 
   // We know the LHS is a complex lvalue.
-  OpInfo.LHS = EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
-  OpInfo.LHS = EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty);
+  OpInfo.LHS=EmitLoadOfComplex(LHSLV.getAddress(),LHSLV.isVolatileQualified());
+  OpInfo.LHS=EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty);
     
-  // It is possible for the RHS to be complex or scalar.
-  OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
-  
   // Expand the binary operator.
   ComplexPairTy Result = (this->*Func)(OpInfo);
   
@@ -439,10 +498,19 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
   
   // Store the result value into the LHS lvalue.
   EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified());
-  return Result;
+  // And now return the LHS
+  IgnoreReal = ignreal;
+  IgnoreImag = ignimag;
+  IgnoreRealAssign = ignreal;
+  IgnoreImagAssign = ignimag;
+  return EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
 }
 
 ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+  TestAndClearIgnoreReal();
+  TestAndClearIgnoreImag();
+  bool ignreal = TestAndClearIgnoreRealAssign();
+  bool ignimag = TestAndClearIgnoreImagAssign();
   assert(CGF.getContext().getCanonicalType(E->getLHS()->getType()) ==
          CGF.getContext().getCanonicalType(E->getRHS()->getType()) &&
          "Invalid assignment");
@@ -454,7 +522,12 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
   
   // Store into it.
   EmitStoreOfComplex(Val, LHS.getAddress(), LHS.isVolatileQualified());
-  return Val;
+  // And now return the LHS
+  IgnoreReal = ignreal;
+  IgnoreImag = ignimag;
+  IgnoreRealAssign = ignreal;
+  IgnoreImagAssign = ignimag;
+  return EmitLoadOfComplex(LHS.getAddress(), LHS.isVolatileQualified());
 }
 
 ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
@@ -465,6 +538,10 @@ ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
 
 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");
@@ -509,6 +586,12 @@ ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) {
 }
 
 ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
+    bool Ignore = TestAndClearIgnoreReal();
+    (void)Ignore;
+    assert (Ignore == false && "init list ignored");
+    Ignore = TestAndClearIgnoreImag();
+    (void)Ignore;
+    assert (Ignore == false && "init list ignored");
   if (E->getNumInits())
     return Visit(E->getInit(0));
 
@@ -541,11 +624,14 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
 
 /// EmitComplexExpr - Emit the computation of the specified expression of
 /// complex type, ignoring the result.
-ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E) {
+ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
+                                               bool IgnoreImag, bool IgnoreRealAssign, bool IgnoreImagAssign) {
   assert(E && E->getType()->isAnyComplexType() &&
          "Invalid complex expression to emit");
   
-  return ComplexExprEmitter(*this).Visit(const_cast<Expr*>(E));
+  return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag, IgnoreRealAssign,
+                            IgnoreImagAssign)
+    .Visit(const_cast<Expr*>(E));
 }
 
 /// EmitComplexExprIntoAddr - Emit the computation of the specified expression
index e14d40c3b6d376c97a346cd087b4d19306fc768f..958aa9361cc04c554f182023bca122bb3b12b21a 100644 (file)
@@ -48,17 +48,22 @@ class VISIBILITY_HIDDEN ScalarExprEmitter
   : public StmtVisitor<ScalarExprEmitter, Value*> {
   CodeGenFunction &CGF;
   CGBuilderTy &Builder;
+  bool IgnoreResultAssign;
 
 public:
 
-  ScalarExprEmitter(CodeGenFunction &cgf) : CGF(cgf), 
-    Builder(CGF.Builder) {
+  ScalarExprEmitter(CodeGenFunction &cgf, bool ira=false)
+    : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira) {
   }
   
   //===--------------------------------------------------------------------===//
   //                               Utilities
   //===--------------------------------------------------------------------===//
 
+  bool TestAndClearIgnoreResultAssign() {
+    bool I = IgnoreResultAssign; IgnoreResultAssign = false;
+    return I; }
+
   const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
   LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
 
@@ -172,6 +177,9 @@ public:
   Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); }
 
   Value *VisitInitListExpr(InitListExpr *E) {
+    bool Ignore = TestAndClearIgnoreResultAssign();
+    (void)Ignore;
+    assert (Ignore == false && "init list ignored");
     unsigned NumInitElements = E->getNumInits();
     
     if (E->hadArrayRangeDesignator()) {
@@ -252,6 +260,8 @@ public:
   }
   Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
   Value *VisitUnaryPlus(const UnaryOperator *E) {
+    // This differs from gcc, though, most likely due to a bug in gcc.
+    TestAndClearIgnoreResultAssign();
     return Visit(E->getSubExpr());
   }
   Value *VisitUnaryMinus    (const UnaryOperator *E);
@@ -543,6 +553,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
 }
 
 Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+  TestAndClearIgnoreResultAssign();
+
   // Emit subscript expressions in rvalue context's.  For most cases, this just
   // loads the lvalue formed by the subscript expr.  However, we have to be
   // careful, because the base of a vector subscript is occasionally an rvalue,
@@ -603,6 +615,9 @@ Value *ScalarExprEmitter::VisitImplicitCastExpr(const ImplicitCastExpr *E) {
 // have to handle a more broad range of conversions than explicit casts, as they
 // handle things like function to ptr-to-function decay etc.
 Value *ScalarExprEmitter::EmitCastExpr(const Expr *E, QualType DestTy) {
+  if (!DestTy->isVoidType())
+    TestAndClearIgnoreResultAssign();
+
   // Handle cases where the source is an non-complex type.
   
   if (!CGF.hasAggregateLLVMType(E->getType())) {
@@ -614,13 +629,25 @@ Value *ScalarExprEmitter::EmitCastExpr(const Expr *E, QualType DestTy) {
   
   if (E->getType()->isAnyComplexType()) {
     // Handle cases where the source is a complex type.
-    return EmitComplexToScalarConversion(CGF.EmitComplexExpr(E), E->getType(),
-                                         DestTy);
+    bool IgnoreImag = true;
+    bool IgnoreImagAssign = true;
+    bool IgnoreReal = IgnoreResultAssign;
+    bool IgnoreRealAssign = IgnoreResultAssign;
+    if (DestTy->isBooleanType())
+      IgnoreImagAssign = IgnoreImag = false;
+    else if (DestTy->isVoidType()) {
+      IgnoreReal = IgnoreImag = false;
+      IgnoreRealAssign = IgnoreImagAssign = true;
+    }
+    CodeGenFunction::ComplexPairTy V
+      = CGF.EmitComplexExpr(E, IgnoreReal, IgnoreImag, IgnoreRealAssign,
+                            IgnoreImagAssign);
+    return EmitComplexToScalarConversion(V, E->getType(), DestTy);
   }
 
   // Okay, this is a cast from an aggregate.  It must be a cast to void.  Just
   // evaluate the result and return.
-  CGF.EmitAggExpr(E, 0, false);
+  CGF.EmitAggExpr(E, 0, false, true);
   return 0;
 }
 
@@ -704,11 +731,13 @@ Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
 
 
 Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
+  TestAndClearIgnoreResultAssign();
   Value *Op = Visit(E->getSubExpr());
   return Builder.CreateNeg(Op, "neg");
 }
 
 Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
+  TestAndClearIgnoreResultAssign();
   Value *Op = Visit(E->getSubExpr());
   return Builder.CreateNot(Op, "neg");
 }
@@ -757,17 +786,20 @@ ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
 Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
   Expr *Op = E->getSubExpr();
   if (Op->getType()->isAnyComplexType())
-    return CGF.EmitComplexExpr(Op).first;
+    return CGF.EmitComplexExpr(Op, false, true, false, true).first;
   return Visit(Op);
 }
 Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
   Expr *Op = E->getSubExpr();
   if (Op->getType()->isAnyComplexType())
-    return CGF.EmitComplexExpr(Op).second;
+    return CGF.EmitComplexExpr(Op, true, false, true, false).second;
   
-  // __imag on a scalar returns zero.  Emit it the subexpr to ensure side
-  // effects are evaluated.
-  CGF.EmitScalarExpr(Op);
+  // __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);
   return llvm::Constant::getNullValue(ConvertType(E->getType()));
 }
 
@@ -783,6 +815,7 @@ Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E)
 //===----------------------------------------------------------------------===//
 
 BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
+  TestAndClearIgnoreResultAssign();
   BinOpInfo Result;
   Result.LHS = Visit(E->getLHS());
   Result.RHS = Visit(E->getRHS());
@@ -793,6 +826,7 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
 
 Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
                       Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
+  bool Ignore = TestAndClearIgnoreResultAssign();
   QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
 
   BinOpInfo OpInfo;
@@ -827,13 +861,18 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
   // handled specially because the result is altered by the store,
   // i.e., [C99 6.5.16p1] 'An assignment expression has the value of
   // the left operand after the assignment...'.
-  if (LHSLV.isBitfield())
-    CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
-                                       &Result);
-  else
+  if (LHSLV.isBitfield()) {
+    if (!LHSLV.isVolatileQualified()) {
+      CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
+                                         &Result);
+      return Result;
+    } else
+      CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy);
+  } else
     CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
-  
-  return Result;
+  if (Ignore)
+    return 0;
+  return EmitLoadOfLValue(LHSLV, E->getType());
 }
 
 
@@ -1125,6 +1164,7 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
 
 Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
                                       unsigned SICmpOpc, unsigned FCmpOpc) {
+  TestAndClearIgnoreResultAssign();
   Value *Result;
   QualType LHSTy = E->getLHS()->getType();
   if (!LHSTy->isAnyComplexType() && !LHSTy->isVectorType()) {
@@ -1193,8 +1233,10 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
 }
 
 Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
-  // __block variables need to have the rhs evaluated first, plus
-  // this should improve codegen just a little.
+  bool Ignore = TestAndClearIgnoreResultAssign();
+
+  // __block variables need to have the rhs evaluated first, plus this should
+  // improve codegen just a little.
   Value *RHS = Visit(E->getRHS());
   LValue LHS = EmitLValue(E->getLHS());
   
@@ -1202,14 +1244,18 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
   // because the result is altered by the store, i.e., [C99 6.5.16p1]
   // 'An assignment expression has the value of the left operand after
   // the assignment...'.
-  if (LHS.isBitfield())
-    CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
-                                       &RHS);
-  else
+  if (LHS.isBitfield()) {
+    if (!LHS.isVolatileQualified()) {
+      CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
+                                         &RHS);
+      return RHS;
+    } else
+      CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType());
+  } else
     CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
-
-  // Return the RHS.
-  return RHS;
+  if (Ignore)
+    return 0;
+  return EmitLoadOfLValue(LHS, E->getType());
 }
 
 Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
@@ -1339,6 +1385,7 @@ static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E) {
 
 Value *ScalarExprEmitter::
 VisitConditionalOperator(const ConditionalOperator *E) {
+  TestAndClearIgnoreResultAssign();
   // If the condition constant folds and can be elided, try to avoid emitting
   // the condition and the dead arm.
   if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getCond())){
@@ -1443,6 +1490,7 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
   if (!ArgPtr) 
     return Builder.CreateVAArg(ArgValue, ConvertType(VE->getType()));
 
+  // FIXME Volatility.
   return Builder.CreateLoad(ArgPtr);
 }
 
@@ -1454,13 +1502,14 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *BE) {
 //                         Entry Point into this File
 //===----------------------------------------------------------------------===//
 
-/// EmitComplexExpr - Emit the computation of the specified expression of
-/// complex type, ignoring the result.
-Value *CodeGenFunction::EmitScalarExpr(const Expr *E) {
+/// EmitScalarExpr - Emit the computation of the specified expression of
+/// scalar type, ignoring the result.
+Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
   assert(E && !hasAggregateLLVMType(E->getType()) &&
          "Invalid scalar expression to emit");
   
-  return ScalarExprEmitter(*this).Visit(const_cast<Expr*>(E));
+  return ScalarExprEmitter(*this, IgnoreResultAssign)
+    .Visit(const_cast<Expr*>(E));
 }
 
 /// EmitScalarConversion - Emit a conversion from the specified type to the
index 7d13071ece21b54013e920a81ca3d6bc4cc7bfe5..7c54a4da04a18497e446328aa10b5a25b642fa6a 100644 (file)
@@ -727,7 +727,7 @@ public:
 
   /// EmitScalarExpr - Emit the computation of the specified expression of LLVM
   /// scalar type, returning the result.
-  llvm::Value *EmitScalarExpr(const Expr *E);
+  llvm::Value *EmitScalarExpr(const Expr *E , bool IgnoreResultAssign=false);
 
   /// EmitScalarConversion - Emit a conversion from the specified type to the
   /// specified destination type, both of which are LLVM scalar types.
@@ -749,7 +749,10 @@ public:
 
   /// EmitComplexExpr - Emit the computation of the specified expression of
   /// complex type, returning the result.
-  ComplexPairTy EmitComplexExpr(const Expr *E);
+  ComplexPairTy EmitComplexExpr(const Expr *E, bool IgnoreReal = false,
+                                bool IgnoreImag = false,
+                                bool IgnoreRealAssign = false,
+                                bool IgnoreImagAssign = false);
 
   /// EmitComplexExprIntoAddr - Emit the computation of the specified expression
   /// of complex type, storing into the specified Value*.
diff --git a/test/CodeGen/volatile-1.c b/test/CodeGen/volatile-1.c
new file mode 100644 (file)
index 0000000..ea47884
--- /dev/null
@@ -0,0 +1,139 @@
+// RUN: clang-cc -Wno-unused-value -emit-llvm < %s -o %t &&
+// RUN: grep volatile %t | count 145 &&
+// RUN: grep memcpy %t | count 4
+
+volatile int i, j, k;
+volatile int ar[5];
+volatile char c;
+volatile _Complex int ci;
+volatile struct S {
+#ifdef __cplusplus
+  void operator =(volatile struct S&o) volatile;
+#endif
+  int i;
+} a, b;
+
+//void operator =(volatile struct S&o1, volatile struct S&o2) volatile;
+#include <stdio.h>
+
+int main() {
+  // A use.
+  i;
+  // A use of the real part
+  (float)(ci);
+  // A use.
+  (void)ci;
+  // A use.
+  (void)a;
+  // Not a use.
+  (void)(ci=ci);
+  // Not a use.
+  (void)(i=j);
+  ci+=ci;
+  (ci += ci) + ci;
+  asm("nop");
+  (i += j) + k;
+  asm("nop");
+  // A use
+  (i += j) + 1;
+  asm("nop");
+  ci+ci;
+  // A use.
+  __real i;
+  // A use.
+  +ci;
+  asm("nop");
+  // Not a use.
+  (void)(i=i);
+  (float)(i=i);
+  // A use.
+  (void)i;
+  i=i;
+  i=i=i;
+#ifndef __cplusplus
+  // Not a use.
+  (void)__builtin_choose_expr(0, i=i, j=j);
+#endif
+  // A use.
+  k ? (i=i) : (j=j);
+  (void)(i,(i=i));
+  i=i,i;
+  (i=j,k=j);
+  (i=j,k);
+  (i,j);
+  i=c=k;
+  i+=k;
+  // A use of both.
+  ci;
+#ifndef __cplusplus
+  // A use of _real.
+  (int)ci;
+  // A use of both.
+  (_Bool)ci;
+#endif
+  ci=ci;
+  ci=ci=ci;
+  __imag ci = __imag ci = __imag ci;
+  // Not a use.
+  __real (i = j);
+  // Not a use.
+  __imag i;
+  
+  // ============================================================
+  // Test cases we get wrong.
+
+  // ============================================================
+  // Test cases where we intentionally differ from gcc, due to suspected bugs in
+  // gcc.
+
+  // Not a use.  gcc forgets to do the assignment.
+  ((a=a),a);
+
+  // Not a use.  gcc gets this wrong, it doesn't emit the copy!  
+  // (void)(a=a);
+
+  // Not a use.  gcc got this wrong in 4.2 and omitted the side effects
+  // entirely, but it is fixed in 4.4.0.
+  __imag (i = j);
+
+#ifndef __cplusplus
+  // A use of the real part
+  (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.
+  (int)(ci=ci);
+#endif
+
+  // A use.
+  (float)(i=i);
+  // A use.  gcc treats this as not a use, that's probably a bug due to tree
+  // folding ignoring volatile.
+  (int)(i=i);
+
+  // A use.
+  -(i=j);
+  // A use.  gcc treats this a not a use, that's probably a bug due to tree
+  // folding ignoring volatile.
+  +(i=k);
+
+  // A use. gcc treats this a not a use, that's probably a bug due to tree
+  // folding ignoring volatile.
+  __real (ci=ci);
+
+  // A use.
+  i + 0;
+  // A use.
+  (i=j) + i;
+  // A use.  gcc treats this as not a use, that's probably a bug due to tree
+  // folding ignoring volatile.
+  (i=j) + 0;
+
+#ifdef __cplusplus
+  (i,j)=k;
+  (j=k,i)=i;
+  struct { int x; } s, s1;
+  printf("s is at %p\n", &s);
+  printf("s is at %p\n", &(s = s1));
+  printf("s.x is at %p\n", &((s = s1).x));
+#endif
+}