[cfe-commits] r124277 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CGTemporaries.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/volatile-1.cpp

John McCall rjmccall at apple.com
Tue Jan 25 20:00:11 PST 2011


Author: rjmccall
Date: Tue Jan 25 22:00:11 2011
New Revision: 124277

URL: http://llvm.org/viewvc/llvm-project?rev=124277&view=rev
Log:
Better framework for conditional cleanups;  untested as yet.
I'm separately committing this because it incidentally changes some
block orderings and minor IR issues, like using a phi instead of
an unnecessary alloca.


Modified:
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprComplex.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/lib/CodeGen/CGTemporaries.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGenCXX/volatile-1.cpp

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Jan 25 22:00:11 2011
@@ -172,6 +172,22 @@
     BranchFixups.pop_back();
 }
 
+llvm::Value *CodeGenFunction::initFullExprCleanup() {
+  // Create a variable to decide whether the cleanup needs to be run.
+  llvm::AllocaInst *run = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond");
+
+  // Initialize it to false at a site that's guaranteed to be run
+  // before each evaluation.
+  llvm::BasicBlock *block = OutermostConditional->getStartingBlock();
+  new llvm::StoreInst(Builder.getFalse(), run,
+                      block->getFirstNonPHIOrDbg());
+
+  // Initialize it to true at the current location.
+  Builder.CreateStore(Builder.getTrue(), run);
+
+  return run;
+}
+
 static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
   // void *__cxa_allocate_exception(size_t thrown_size);
   const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
@@ -1656,3 +1672,23 @@
 EHScopeStack::Cleanup::~Cleanup() {
   llvm_unreachable("Cleanup is indestructable");
 }
+
+void EHScopeStack::ConditionalCleanup::Emit(CodeGenFunction &CGF,
+                                            bool IsForEHCleanup) {
+  // Determine whether we should run the cleanup.
+  llvm::Value *condVal = CGF.Builder.CreateLoad(cond, "cond.should-run");
+
+  llvm::BasicBlock *cleanup = CGF.createBasicBlock("cond-cleanup.run");
+  llvm::BasicBlock *cont = CGF.createBasicBlock("cond-cleanup.cont");
+
+  // If we shouldn't run the cleanup, jump directly to the continuation block.
+  CGF.Builder.CreateCondBr(condVal, cleanup, cont);
+  CGF.EmitBlock(cleanup);
+
+  // Emit the core of the cleanup.
+  EmitImpl(CGF, IsForEHCleanup);
+  assert(CGF.HaveInsertPoint() && "cleanup didn't end with valid IP!");
+
+  // Fall into the continuation block.
+  CGF.EmitBlock(cont);
+}

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Jan 25 22:00:11 2011
@@ -1692,6 +1692,8 @@
     llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
     llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
     llvm::BasicBlock *ContBlock = createBasicBlock("cond.end");
+
+    ConditionalEvaluation eval(*this);
     
     if (E->getLHS())
       EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
@@ -1705,35 +1707,34 @@
     }
     
     // Any temporaries created here are conditional.
-    BeginConditionalBranch();
     EmitBlock(LHSBlock);
+    eval.begin(*this);
     LValue LHS = EmitLValue(E->getTrueExpr());
-
-    EndConditionalBranch();
+    eval.end(*this);
     
     if (!LHS.isSimple())
       return EmitUnsupportedLValue(E, "conditional operator");
 
-    // FIXME: We shouldn't need an alloca for this.
-    llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),"condtmp");
-    Builder.CreateStore(LHS.getAddress(), Temp);
-    EmitBranch(ContBlock);
+    LHSBlock = Builder.GetInsertBlock();
+    Builder.CreateBr(ContBlock);
     
     // Any temporaries created here are conditional.
-    BeginConditionalBranch();
     EmitBlock(RHSBlock);
+    eval.begin(*this);
     LValue RHS = EmitLValue(E->getRHS());
-    EndConditionalBranch();
+    eval.end(*this);
     if (!RHS.isSimple())
       return EmitUnsupportedLValue(E, "conditional operator");
-
-    Builder.CreateStore(RHS.getAddress(), Temp);
-    EmitBranch(ContBlock);
+    RHSBlock = Builder.GetInsertBlock();
 
     EmitBlock(ContBlock);
-    
-    Temp = Builder.CreateLoad(Temp, "lv");
-    return MakeAddrLValue(Temp, E->getType());
+
+    llvm::PHINode *phi = Builder.CreatePHI(LHS.getAddress()->getType(),
+                                           "cond-lvalue");
+    phi->reserveOperandSpace(2);
+    phi->addIncoming(LHS.getAddress(), LHSBlock);
+    phi->addIncoming(RHS.getAddress(), RHSBlock);
+    return MakeAddrLValue(phi, E->getType());
   }
   
   // ?: here should be an aggregate.

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Jan 25 22:00:11 2011
@@ -367,8 +367,8 @@
 }
 
 void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
+  CodeGenFunction::StmtExprEvaluation eval(CGF);
   CGF.EmitCompoundStmt(*E->getSubStmt(), true, Dest);
-  CGF.EnsureInsertPoint();
 }
 
 void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
@@ -423,20 +423,19 @@
   llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
 
+  CodeGenFunction::ConditionalEvaluation eval(CGF);
   CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
 
-  CGF.BeginConditionalBranch();
-  CGF.EmitBlock(LHSBlock);
-
   // Save whether the destination's lifetime is externally managed.
   bool DestLifetimeManaged = Dest.isLifetimeExternallyManaged();
 
+  eval.begin(CGF);
+  CGF.EmitBlock(LHSBlock);
   Visit(E->getLHS());
-  CGF.EndConditionalBranch();
-  CGF.EmitBranch(ContBlock);
+  eval.end(CGF);
 
-  CGF.BeginConditionalBranch();
-  CGF.EmitBlock(RHSBlock);
+  assert(CGF.HaveInsertPoint() && "expression evaluation ended with no IP!");
+  CGF.Builder.CreateBr(ContBlock);
 
   // If the result of an agg expression is unused, then the emission
   // of the LHS might need to create a destination slot.  That's fine
@@ -444,9 +443,10 @@
   // we shouldn't claim that its lifetime is externally managed.
   Dest.setLifetimeExternallyManaged(DestLifetimeManaged);
 
+  eval.begin(CGF);
+  CGF.EmitBlock(RHSBlock);
   Visit(E->getRHS());
-  CGF.EndConditionalBranch();
-  CGF.EmitBranch(ContBlock);
+  eval.end(CGF);
 
   CGF.EmitBlock(ContBlock);
 }

Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Tue Jan 25 22:00:11 2011
@@ -325,9 +325,8 @@
 }
 
 ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) {
-  RValue result = CGF.EmitCompoundStmt(*E->getSubStmt(), true);
-  CGF.EnsureInsertPoint();
-  return result.getComplexVal();
+  CodeGenFunction::StmtExprEvaluation eval(CGF);
+  return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal();
 }
 
 /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
@@ -647,29 +646,32 @@
   llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
 
+  CodeGenFunction::ConditionalEvaluation eval(CGF);
+
   if (E->getLHS())
     CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
   else {
     Expr *save = E->getSAVE();
     assert(save && "VisitConditionalOperator - save is null");
-    // Intentianlly not doing direct assignment to ConditionalSaveExprs[save] !!
+    // Intentionally not doing direct assignment to ConditionalSaveExprs[save] !!
     ComplexPairTy SaveVal = Visit(save);
     CGF.ConditionalSaveComplexExprs[save] = SaveVal;
     CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
   }
 
+  eval.begin(CGF);
   CGF.EmitBlock(LHSBlock);
   ComplexPairTy LHS = Visit(E->getTrueExpr());
   LHSBlock = Builder.GetInsertBlock();
   CGF.EmitBranch(ContBlock);
+  eval.end(CGF);
 
+  eval.begin(CGF);
   CGF.EmitBlock(RHSBlock);
-
   ComplexPairTy RHS = Visit(E->getRHS());
   RHSBlock = Builder.GetInsertBlock();
-  CGF.EmitBranch(ContBlock);
-
   CGF.EmitBlock(ContBlock);
+  eval.end(CGF);
 
   // Create a PHI node for the real part.
   llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r");

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Jan 25 22:00:11 2011
@@ -1204,10 +1204,9 @@
 }
 
 Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
-  RValue value = CGF.EmitCompoundStmt(*E->getSubStmt(),
-                                      !E->getType()->isVoidType());
-  CGF.EnsureInsertPoint();
-  return value.getScalarVal();
+  CodeGenFunction::StmtExprEvaluation eval(CGF);
+  return CGF.EmitCompoundStmt(*E->getSubStmt(), !E->getType()->isVoidType())
+    .getScalarVal();
 }
 
 Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
@@ -2226,6 +2225,8 @@
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end");
   llvm::BasicBlock *RHSBlock  = CGF.createBasicBlock("land.rhs");
 
+  CodeGenFunction::ConditionalEvaluation eval(CGF);
+
   // Branch on the LHS first.  If it is false, go to the failure (cont) block.
   CGF.EmitBranchOnBoolExpr(E->getLHS(), RHSBlock, ContBlock);
 
@@ -2239,10 +2240,10 @@
        PI != PE; ++PI)
     PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
 
-  CGF.BeginConditionalBranch();
+  eval.begin(CGF);
   CGF.EmitBlock(RHSBlock);
   Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
-  CGF.EndConditionalBranch();
+  eval.end(CGF);
 
   // Reaquire the RHS block, as there may be subblocks inserted.
   RHSBlock = Builder.GetInsertBlock();
@@ -2276,6 +2277,8 @@
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end");
   llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs");
 
+  CodeGenFunction::ConditionalEvaluation eval(CGF);
+
   // Branch on the LHS first.  If it is true, go to the success (cont) block.
   CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock);
 
@@ -2289,13 +2292,13 @@
        PI != PE; ++PI)
     PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
 
-  CGF.BeginConditionalBranch();
+  eval.begin(CGF);
 
   // Emit the RHS condition as a bool value.
   CGF.EmitBlock(RHSBlock);
   Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
 
-  CGF.EndConditionalBranch();
+  eval.end(CGF);
 
   // Reaquire the RHS block, as there may be subblocks inserted.
   RHSBlock = Builder.GetInsertBlock();
@@ -2425,6 +2428,8 @@
   llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
   llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
+
+  CodeGenFunction::ConditionalEvaluation eval(CGF);
   
   // If we don't have the GNU missing condition extension, emit a branch on bool
   // the normal way.
@@ -2456,24 +2461,20 @@
     Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
   }
 
-  CGF.BeginConditionalBranch();
   CGF.EmitBlock(LHSBlock);
-
-  // Handle the GNU extension for missing LHS.
+  eval.begin(CGF);
   Value *LHS = Visit(E->getTrueExpr());
+  eval.end(CGF);
 
-  CGF.EndConditionalBranch();
   LHSBlock = Builder.GetInsertBlock();
-  CGF.EmitBranch(ContBlock);
+  Builder.CreateBr(ContBlock);
 
-  CGF.BeginConditionalBranch();
   CGF.EmitBlock(RHSBlock);
-
+  eval.begin(CGF);
   Value *RHS = Visit(E->getRHS());
-  CGF.EndConditionalBranch();
-  RHSBlock = Builder.GetInsertBlock();
-  CGF.EmitBranch(ContBlock);
+  eval.end(CGF);
 
+  RHSBlock = Builder.GetInsertBlock();
   CGF.EmitBlock(ContBlock);
 
   // If the LHS or RHS is a throw expression, it will be legitimately null.

Modified: cfe/trunk/lib/CodeGen/CGTemporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGTemporaries.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGTemporaries.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGTemporaries.cpp Tue Jan 25 22:00:11 2011
@@ -60,7 +60,7 @@
 
   // Check if temporaries need to be conditional. If so, we'll create a
   // condition boolean, initialize it to 0 and
-  if (ConditionalBranchLevel != 0) {
+  if (isInConditionalBranch()) {
     CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
 
     // Initialize it to false. This initialization takes place right after

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Tue Jan 25 22:00:11 2011
@@ -41,7 +41,7 @@
     SwitchInsn(0), CaseRangeBlock(0),
     DidCallStackSave(false), UnreachableBlock(0),
     CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
-    ConditionalBranchLevel(0), TerminateLandingPad(0), TerminateHandler(0),
+    OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0),
     TrapBB(0) {
       
   // Get some frequently used types.
@@ -447,13 +447,15 @@
       // Emit the LHS as a conditional.  If the LHS conditional is false, we
       // want to jump to the FalseBlock.
       llvm::BasicBlock *LHSTrue = createBasicBlock("land.lhs.true");
+
+      ConditionalEvaluation eval(*this);
       EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock);
       EmitBlock(LHSTrue);
 
       // Any temporaries created here are conditional.
-      BeginConditionalBranch();
+      eval.begin(*this);
       EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
-      EndConditionalBranch();
+      eval.end(*this);
 
       return;
     } else if (CondBOp->getOpcode() == BO_LOr) {
@@ -474,13 +476,15 @@
       // Emit the LHS as a conditional.  If the LHS conditional is true, we
       // want to jump to the TrueBlock.
       llvm::BasicBlock *LHSFalse = createBasicBlock("lor.lhs.false");
+
+      ConditionalEvaluation eval(*this);
       EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse);
       EmitBlock(LHSFalse);
 
       // Any temporaries created here are conditional.
-      BeginConditionalBranch();
+      eval.begin(*this);
       EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
-      EndConditionalBranch();
+      eval.end(*this);
 
       return;
     }
@@ -500,11 +504,20 @@
       // br(c ? x : y, t, f) -> br(c, br(x, t, f), br(y, t, f))
       llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
       llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
+
+      ConditionalEvaluation cond(*this);
       EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock);
+
+      cond.begin(*this);
       EmitBlock(LHSBlock);
       EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock);
+      cond.end(*this);
+
+      cond.begin(*this);
       EmitBlock(RHSBlock);
       EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock);
+      cond.end(*this);
+
       return;
     }
   }

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jan 25 22:00:11 2011
@@ -97,6 +97,24 @@
   llvm::BranchInst *InitialBranch;
 };
 
+/// A metaprogramming class which decides whether a type is a subclass
+/// of llvm::Value that needs to be saved if it's used in a
+/// conditional cleanup.
+template
+  <class T,
+   bool mustSave =
+     llvm::is_base_of<llvm::Value, llvm::remove_pointer<T> >::value
+     && !llvm::is_base_of<llvm::Constant, llvm::remove_pointer<T> >::value
+     && !llvm::is_base_of<llvm::BasicBlock, llvm::remove_pointer<T> >::value>
+struct SavedValueInCond {
+  typedef T type;
+  typedef T saved_type;
+  static bool needsSaving(type value) { return false; }
+  static saved_type save(CodeGenFunction &CGF, type value) { return value; }
+  static type restore(CodeGenFunction &CGF, saved_type value) { return value; }
+};
+// Partial specialization for true arguments at end of file.
+
 enum CleanupKind {
   EHCleanup = 0x1,
   NormalCleanup = 0x2,
@@ -175,6 +193,52 @@
     virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
   };
 
+  /// A helper class for cleanups that execute conditionally.
+  class ConditionalCleanup : public Cleanup {
+    /// Either an i1 which directly indicates whether the cleanup
+    /// should be run or an i1* from which that should be loaded.
+    llvm::Value *cond;
+
+  public:
+    virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup);
+
+  protected:
+    ConditionalCleanup(llvm::Value *cond) : cond(cond) {}
+
+    /// Emit the non-conditional code for the cleanup.
+    virtual void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
+  };
+
+  /// UnconditionalCleanupN stores its N parameters and just passes
+  /// them to the real cleanup function.
+  template <class T, class A0, class A1>
+  class UnconditionalCleanup2 : public Cleanup {
+    A0 a0; A1 a1;
+    UnconditionalCleanup2(A0 a0, A1 a1) : a0(a0), a1(a1) {}
+    void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+      T::Emit(CGF, IsForEHCleanup, a0, a1);
+    }
+  };
+
+  /// ConditionalCleanupN stores the saved form of its N parameters,
+  /// then restores them and performs the cleanup.
+  template <class T, class A0, class A1>
+  class ConditionalCleanup2 : public ConditionalCleanup {
+    typedef typename SavedValueInCond<A0>::saved_type A0_saved;
+    typedef typename SavedValueInCond<A1>::saved_type A1_saved;
+    A0_saved a0; A1_saved a1;
+
+    void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) {
+      A0 a0 = SavedValueInCond<A0>::restore(CGF, a0);
+      A1 a1 = SavedValueInCond<A1>::restore(CGF, a1);
+      T::Emit(CGF, IsForEHCleanup, a0, a1);
+    }
+
+  public:
+    ConditionalCleanup2(llvm::Value *cond, A0_saved a0, A1_saved a1)
+      : ConditionalCleanup(cond), a0(a0), a1(a1) {}
+  };
+
 private:
   // The implementation for this class is in CGException.h and
   // CGException.cpp; the definition is here because it's used as a
@@ -536,6 +600,14 @@
 
   llvm::BasicBlock *getInvokeDestImpl();
 
+  /// Sets up a condition for a full-expression cleanup.
+  llvm::Value *initFullExprCleanup();
+
+  template <class T>
+  typename SavedValueInCond<T>::saved_type saveValueInCond(T value) {
+    return SavedValueInCond<T>::save(*this, value);
+  }
+
 public:
   /// ObjCEHValueStack - Stack of Objective-C exception values, used for
   /// rethrows.
@@ -552,6 +624,28 @@
                                 llvm::Constant *RethrowFn);
   void ExitFinallyBlock(FinallyInfo &FinallyInfo);
 
+  /// pushFullExprCleanup - Push a cleanup to be run at the end of the
+  /// current full-expression.  Safe against the possibility that
+  /// we're currently inside a conditionally-evaluated expression.
+  template <class T, class A0, class A1>
+  void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1) {
+    // If we're not in a conditional branch, or if none of the
+    // arguments requires saving, then use the unconditional cleanup.
+    if (!(isInConditionalBranch() ||
+          SavedValueInCond<A0>::needsSaving(a0) ||
+          SavedValueInCond<A1>::needsSaving(a1))) {
+      typedef EHScopeStack::UnconditionalCleanup2<T, A0, A1> CleanupType;
+      return EHStack.pushCleanup<CleanupType>(kind, a0, a1);
+    }
+
+    llvm::Value *condVar = initFullExprCleanup();
+    typename SavedValueInCond<A0>::saved_type a0_saved = saveValueInCond(a0);
+    typename SavedValueInCond<A1>::saved_type a1_saved = saveValueInCond(a1);
+
+    typedef EHScopeStack::ConditionalCleanup2<T, A0, A1> CleanupType;
+    EHStack.pushCleanup<CleanupType>(kind, condVar, a0_saved, a1_saved);
+  }
+
   /// PushDestructorCleanup - Push a cleanup to call the
   /// complete-object destructor of an object of the given type at the
   /// given address.  Does nothing if T is not a C++ class type with a
@@ -659,30 +753,58 @@
   /// destination.
   UnwindDest getRethrowDest();
 
-  /// BeginConditionalBranch - Should be called before a conditional part of an
-  /// expression is emitted. For example, before the RHS of the expression below
-  /// is emitted:
-  ///
-  /// b && f(T());
-  ///
-  /// This is used to make sure that any temporaries created in the conditional
-  /// branch are only destroyed if the branch is taken.
-  void BeginConditionalBranch() {
-    ++ConditionalBranchLevel;
-  }
+  /// An object to manage conditionally-evaluated expressions.
+  class ConditionalEvaluation {
+    llvm::BasicBlock *StartBB;
 
-  /// EndConditionalBranch - Should be called after a conditional part of an
-  /// expression has been emitted.
-  void EndConditionalBranch() {
-    assert(ConditionalBranchLevel != 0 &&
-           "Conditional branch mismatch!");
+  public:
+    ConditionalEvaluation(CodeGenFunction &CGF)
+      : StartBB(CGF.Builder.GetInsertBlock()) {}
 
-    --ConditionalBranchLevel;
-  }
+    void begin(CodeGenFunction &CGF) {
+      assert(CGF.OutermostConditional != this);
+      if (!CGF.OutermostConditional)
+        CGF.OutermostConditional = this;
+    }
+
+    void end(CodeGenFunction &CGF) {
+      assert(CGF.OutermostConditional != 0);
+      if (CGF.OutermostConditional == this)
+        CGF.OutermostConditional = 0;
+    }
+
+    /// Returns a block which will be executed prior to each
+    /// evaluation of the conditional code.
+    llvm::BasicBlock *getStartingBlock() const {
+      return StartBB;
+    }
+  };
 
   /// isInConditionalBranch - Return true if we're currently emitting
   /// one branch or the other of a conditional expression.
-  bool isInConditionalBranch() const { return ConditionalBranchLevel != 0; }
+  bool isInConditionalBranch() const { return OutermostConditional != 0; }
+
+  /// An RAII object to record that we're evaluating a statement
+  /// expression.
+  class StmtExprEvaluation {
+    CodeGenFunction &CGF;
+
+    /// We have to save the outermost conditional: cleanups in a
+    /// statement expression aren't conditional just because the
+    /// StmtExpr is.
+    ConditionalEvaluation *SavedOutermostConditional;
+
+  public:
+    StmtExprEvaluation(CodeGenFunction &CGF)
+      : CGF(CGF), SavedOutermostConditional(CGF.OutermostConditional) {
+      CGF.OutermostConditional = 0;
+    }
+
+    ~StmtExprEvaluation() {
+      CGF.OutermostConditional = SavedOutermostConditional;
+      CGF.EnsureInsertPoint();
+    }
+  };
   
   /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
   /// number that holds the value.
@@ -750,10 +872,10 @@
   ImplicitParamDecl *CXXVTTDecl;
   llvm::Value *CXXVTTValue;
 
-  /// ConditionalBranchLevel - Contains the nesting level of the current
-  /// conditional branch. This is used so that we know if a temporary should be
-  /// destroyed conditionally.
-  unsigned ConditionalBranchLevel;
+  /// OutermostConditional - Points to the outermost active
+  /// conditional control.  This is used so that we know if a
+  /// temporary should be destroyed conditionally.
+  ConditionalEvaluation *OutermostConditional;
 
 
   /// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
@@ -1786,6 +1908,48 @@
   void EmitDeclMetadata();
 };
 
+/// Helper class with most of the code for saving a value for a
+/// conditional expression cleanup.
+struct SavedValueInCondImpl {
+  typedef llvm::PointerIntPair<llvm::Value*, 1, bool> saved_type;
+
+  /// Answer whether the given value needs extra work to be saved.
+  static bool needsSaving(llvm::Value *value) {
+    // If it's not an instruction, we don't need to save.
+    if (!isa<llvm::Instruction>(value)) return false;
+
+    // If it's an instruction in the entry block, we don't need to save.
+    llvm::BasicBlock *block = cast<llvm::Instruction>(value)->getParent();
+    return (block != &block->getParent()->getEntryBlock());
+  }
+
+  /// Try to save the given value.
+  static saved_type save(CodeGenFunction &CGF, llvm::Value *value) {
+    if (!needsSaving(value)) return saved_type(value, false);
+
+    // Otherwise we need an alloca.
+    llvm::Value *alloca =
+      CGF.CreateTempAlloca(value->getType(), "cond-cleanup.save");
+    CGF.Builder.CreateStore(value, alloca);
+
+    return saved_type(alloca, true);
+  }
+
+  static llvm::Value *restore(CodeGenFunction &CGF, saved_type value) {
+    if (!value.getInt()) return value.getPointer();
+    return CGF.Builder.CreateLoad(value.getPointer());
+  }
+};
+
+/// Partial specialization of SavedValueInCond for when a value really
+/// requires saving.
+template <class T> struct SavedValueInCond<T,true> : SavedValueInCondImpl {
+  typedef T type;
+  static type restore(CodeGenFunction &CGF, saved_type value) {
+    return static_cast<T>(SavedValueInCondImpl::restore(CGF, value));
+  }
+};
+
 /// CGBlockInfo - Information to generate a block literal.
 class CGBlockInfo {
 public:

Modified: cfe/trunk/test/CodeGenCXX/volatile-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/volatile-1.cpp?rev=124277&r1=124276&r2=124277&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/volatile-1.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/volatile-1.cpp Tue Jan 25 22:00:11 2011
@@ -143,20 +143,17 @@
   // CHECK-NEXT: volatile load
   // CHECK-NEXT: volatile store
 
-  // FIXME: the phi-equivalent is unnecessary
   k ? (i=i) : (j=j);
   // CHECK-NEXT: volatile load
   // CHECK-NEXT: icmp
   // CHECK-NEXT: br i1
   // CHECK: volatile load
   // CHECK-NEXT: volatile store
-  // CHECK-NEXT: store [[INT]]* @i
   // CHECK-NEXT: br label
   // CHECK: volatile load
   // CHECK-NEXT: volatile store
-  // CHECK-NEXT: store [[INT]]* @j
   // CHECK-NEXT: br label
-  // CHECK: load [[INT]]**
+  // CHECK:      phi
 
   (void)(i,(i=i));
   // CHECK-NEXT: volatile load





More information about the cfe-commits mailing list