]> granicus.if.org Git - clang/commitdiff
Sketch out a framework for delaying the activation of a cleanup.
authorJohn McCall <rjmccall@apple.com>
Fri, 13 Aug 2010 21:20:51 +0000 (21:20 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 13 Aug 2010 21:20:51 +0000 (21:20 +0000)
Not yet complete or used.

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

lib/CodeGen/CGException.cpp
lib/CodeGen/CGException.h
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h

index dd518cf5efd753c6bd2c545b55231f544827c500..d4a702a255f82035cb445a58c8219da0b594feab 100644 (file)
@@ -73,11 +73,13 @@ EHScopeStack::getEnclosingEHCleanup(iterator it) const {
 void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
   assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned");
   char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size));
-  bool IsNormalCleanup = Kind != EHCleanup;
-  bool IsEHCleanup = Kind != NormalCleanup;
+  bool IsNormalCleanup = Kind & NormalCleanup;
+  bool IsEHCleanup = Kind & EHCleanup;
+  bool IsActive = !(Kind & InactiveCleanup);
   EHCleanupScope *Scope =
     new (Buffer) EHCleanupScope(IsNormalCleanup,
                                 IsEHCleanup,
+                                IsActive,
                                 Size,
                                 BranchFixups.size(),
                                 InnermostNormalCleanup,
index 01536e35fb935f6dc6efca2d9643467a86b5dcdc..f40e3e32c2081bfdf46f48bdaf4fa9db9c393730 100644 (file)
@@ -160,6 +160,12 @@ class EHCleanupScope : public EHScope {
   /// Whether this cleanup needs to be run along exception edges.
   bool IsEHCleanup : 1;
 
+  /// Whether this cleanup was activated before all normal uses.
+  bool ActivatedBeforeNormalUse : 1;
+
+  /// Whether this cleanup was activated before all EH uses.
+  bool ActivatedBeforeEHUse : 1;
+
   /// The amount of extra storage needed by the Cleanup.
   /// Always a multiple of the scope-stack alignment.
   unsigned CleanupSize : 12;
@@ -167,7 +173,7 @@ class EHCleanupScope : public EHScope {
   /// The number of fixups required by enclosing scopes (not including
   /// this one).  If this is the top cleanup scope, all the fixups
   /// from this index onwards belong to this scope.
-  unsigned FixupDepth : BitsRemaining - 14;
+  unsigned FixupDepth : BitsRemaining - 16;
 
   /// The nearest normal cleanup scope enclosing this one.
   EHScopeStack::stable_iterator EnclosingNormal;
@@ -183,6 +189,14 @@ class EHCleanupScope : public EHScope {
   /// created if needed before the cleanup is popped.
   llvm::BasicBlock *EHBlock;
 
+  /// An optional i1 variable indicating whether this cleanup has been
+  /// activated yet.  This has one of three states:
+  ///   - it is null if the cleanup is inactive
+  ///   - it is activeSentinel() if the cleanup is active and was not
+  ///     required before activation
+  ///   - it points to a valid variable
+  llvm::AllocaInst *ActiveVar;
+
   /// Extra information required for cleanups that have resolved
   /// branches through them.  This has to be allocated on the side
   /// because everything on the cleanup stack has be trivially
@@ -227,15 +241,19 @@ public:
     return sizeof(EHCleanupScope) + CleanupSize;
   }
 
-  EHCleanupScope(bool IsNormal, bool IsEH, unsigned CleanupSize,
-                 unsigned FixupDepth,
+  EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive,
+                 unsigned CleanupSize, unsigned FixupDepth,
                  EHScopeStack::stable_iterator EnclosingNormal,
                  EHScopeStack::stable_iterator EnclosingEH)
     : EHScope(EHScope::Cleanup),
       IsNormalCleanup(IsNormal), IsEHCleanup(IsEH),
+      ActivatedBeforeNormalUse(IsActive),
+      ActivatedBeforeEHUse(IsActive),
       CleanupSize(CleanupSize), FixupDepth(FixupDepth),
       EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
-      NormalBlock(0), EHBlock(0), ExtInfo(0)
+      NormalBlock(0), EHBlock(0),
+      ActiveVar(IsActive ? activeSentinel() : 0),
+      ExtInfo(0)
   {
     assert(this->CleanupSize == CleanupSize && "cleanup size overflow");
   }
@@ -252,6 +270,20 @@ public:
   llvm::BasicBlock *getEHBlock() const { return EHBlock; }
   void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
 
+  static llvm::AllocaInst *activeSentinel() {
+    return reinterpret_cast<llvm::AllocaInst*>(1);
+  }
+
+  bool isActive() const { return ActiveVar != 0; }
+  llvm::AllocaInst *getActiveVar() const { return ActiveVar; }
+  void setActiveVar(llvm::AllocaInst *Var) { ActiveVar = Var; }
+
+  bool wasActivatedBeforeNormalUse() const { return ActivatedBeforeNormalUse; }
+  void setActivatedBeforeNormalUse(bool B) { ActivatedBeforeNormalUse = B; }
+
+  bool wasActivatedBeforeEHUse() const { return ActivatedBeforeEHUse; }
+  void setActivatedBeforeEHUse(bool B) { ActivatedBeforeEHUse = B; }
+
   unsigned getFixupDepth() const { return FixupDepth; }
   EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
     return EnclosingNormal;
index e5cfa624b2cc2e5c6fe836b23b682ca69a6e7ed1..b3ac8f1ddbef02542e3af186b4566baeef065322 100644 (file)
@@ -1275,6 +1275,73 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) {
     EHStack.popNullFixups();
 }
 
+/// Activate a cleanup that was created in an inactivated state.
+void CodeGenFunction::ActivateCleanup(EHScopeStack::stable_iterator C) {
+  assert(C != EHStack.stable_end() && "activating bottom of stack?");
+  EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
+  assert(!Scope.isActive() && "double activation");
+
+  // Calculate whether the cleanup was used:
+  bool Used = false;
+
+  //   - as a normal cleanup
+  if (Scope.isNormalCleanup()) {
+    bool NormalUsed = false;
+    if (Scope.getNormalBlock()) {
+      NormalUsed = true;
+    } else {
+      // Check whether any enclosed cleanups were needed.
+      for (EHScopeStack::stable_iterator
+             I = EHStack.getInnermostNormalCleanup(); I != C; ) {
+        assert(C.strictlyEncloses(I));
+        EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I));
+        if (S.getNormalBlock()) {
+          NormalUsed = true;
+          break;
+        }
+        I = S.getEnclosingNormalCleanup();
+      }
+    }
+
+    if (NormalUsed)
+      Used = true;
+    else
+      Scope.setActivatedBeforeNormalUse(true);
+  }
+
+  //  - as an EH cleanup
+  if (Scope.isEHCleanup()) {
+    bool EHUsed = false;
+    if (Scope.getEHBlock()) {
+      EHUsed = true;
+    } else {
+      // Check whether any enclosed cleanups were needed.
+      for (EHScopeStack::stable_iterator
+             I = EHStack.getInnermostEHCleanup(); I != C; ) {
+        assert(C.strictlyEncloses(I));
+        EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I));
+        if (S.getEHBlock()) {
+          EHUsed = true;
+          break;
+        }
+        I = S.getEnclosingEHCleanup();
+      }
+    }
+
+    if (EHUsed)
+      Used = true;
+    else
+      Scope.setActivatedBeforeEHUse(true);
+  }
+  
+  llvm::AllocaInst *Var = EHCleanupScope::activeSentinel();
+  if (Used) {
+    Var = CreateTempAlloca(Builder.getInt1Ty());
+    InitTempAlloca(Var, Builder.getFalse());
+  }
+  Scope.setActiveVar(Var);
+}
+
 llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() {
   if (!NormalCleanupDest)
     NormalCleanupDest =
index 325940d2452fe4981bc173462ebbf51a0138a961..3d212b5f7824c8acb6a449afe38158dac0657dfe 100644 (file)
@@ -96,7 +96,16 @@ struct BranchFixup {
   llvm::BranchInst *InitialBranch;
 };
 
-enum CleanupKind { NormalAndEHCleanup, EHCleanup, NormalCleanup };
+enum CleanupKind {
+  EHCleanup = 0x1,
+  NormalCleanup = 0x2,
+  NormalAndEHCleanup = EHCleanup | NormalCleanup,
+
+  InactiveCleanup = 0x4,
+  InactiveEHCleanup = EHCleanup | InactiveCleanup,
+  InactiveNormalCleanup = NormalCleanup | InactiveCleanup,
+  InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup
+};
 
 /// A stack of scopes which respond to exceptions, including cleanups
 /// and catch blocks.
@@ -520,6 +529,8 @@ public:
   /// process all branch fixups.
   void PopCleanupBlock(bool FallThroughIsBranchThrough = false);
 
+  void ActivateCleanup(EHScopeStack::stable_iterator Cleanup);
+
   /// \brief Enters a new scope for capturing cleanups, all of which
   /// will be executed once the scope is exited.
   class RunCleanupsScope {