[cfe-commits] r64064 - /cfe/trunk/lib/CodeGen/CodeGenFunction.cpp

Anders Carlsson andersca at mac.com
Sat Feb 7 17:23:05 PST 2009


Author: andersca
Date: Sat Feb  7 19:23:05 2009
New Revision: 64064

URL: http://llvm.org/viewvc/llvm-project?rev=64064&view=rev
Log:
Implement support for branch fixups.

Modified:
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=64064&r1=64063&r2=64064&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Sat Feb  7 19:23:05 2009
@@ -550,7 +550,77 @@
   CleanupEntries.pop_back();
   
   EmitBlock(CleanupBlock);
-  
+
+  if (!CleanupEntries.empty()) {
+    // Check if any branch fixups pointed to the scope we just popped. If so,
+    // we can remove them.
+    for (size_t i = 0, e = BranchFixups.size(); i != e; ++i) {
+      llvm::BasicBlock *Dest = BranchFixups[i]->getSuccessor(0);
+      BlockScopeMap::iterator I = BlockScopes.find(Dest);
+    
+      if (I == BlockScopes.end())
+        continue;
+      
+      assert(I->second <= CleanupEntries.size() && "Invalid branch fixup!");
+
+      if (I->second == CleanupEntries.size()) {
+        // We don't need to do this branch fixup.
+        BranchFixups[i] = BranchFixups.back();
+        BranchFixups.pop_back();
+        i--;
+        e--;
+        continue;
+      }
+    }
+  }
+
+  if (!BranchFixups.empty()) {
+    llvm::BasicBlock *CleanupEnd = createBasicBlock("cleanup.end");
+    
+    llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::Int32Ty, 
+                                                "cleanup.dst");
+    llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp");
+    
+    // Create a switch instruction to determine where to jump next.
+    llvm::SwitchInst *SI = Builder.CreateSwitch(DestCode, CleanupEnd, 
+                                                BranchFixups.size());
+    EmitBlock(CleanupEnd);
+    
+    for (size_t i = 0, e = BranchFixups.size(); i != e; ++i) {
+      llvm::BranchInst *BI = BranchFixups[i];
+      llvm::BasicBlock *Dest = BI->getSuccessor(0);
+      
+      // Store the jump destination before the branch instruction.
+      llvm::ConstantInt *DI = 
+        llvm::ConstantInt::get(llvm::Type::Int32Ty, i + 1);
+      new llvm::StoreInst(DI, DestCodePtr, BI);
+      
+      // Fixup the branch instruction to point to the cleanup block.
+      BI->setSuccessor(0, CleanupBlock);
+
+      if (CleanupEntries.empty()) {
+        SI->addCase(DI, Dest);
+      } else {
+        // We need to jump through another cleanup block. Create a pad block
+        // with a branch instruction that jumps to the final destination and
+        // add it as a branch fixup to the current cleanup scope.
+        
+        // Create the pad block.
+        llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn);
+
+        // Add it as the destination.
+        SI->addCase(DI, CleanupPad);
+        
+        // Create the branch to the final destination.
+        llvm::BranchInst *BI = llvm::BranchInst::Create(Dest);
+        CleanupPad->getInstList().push_back(BI);
+        
+        // And add it as a branch fixup.
+        CleanupEntries.back().BranchFixups.push_back(BI);
+      }
+    }
+  }
+
   // Remove all blocks from the block scope map.
   for (size_t i = 0, e = Blocks.size(); i != e; ++i) {
     assert(BlockScopes.count(Blocks[i]) &&





More information about the cfe-commits mailing list