Add an unwind_to field to basic blocks, making them Users instead of Values.
authorNick Lewycky <nicholas@mxc.ca>
Sun, 2 Mar 2008 02:48:09 +0000 (02:48 +0000)
committerNick Lewycky <nicholas@mxc.ca>
Sun, 2 Mar 2008 02:48:09 +0000 (02:48 +0000)
This is the first checkin for PR1269, the new EH infrastructure.

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

include/llvm/BasicBlock.h
include/llvm/Bitcode/LLVMBitCodes.h
lib/AsmParser/LLLexer.cpp
lib/AsmParser/llvmAsmParser.y
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/VMCore/AsmWriter.cpp
lib/VMCore/BasicBlock.cpp
test/Feature/unwindto.ll [new file with mode: 0644]
tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp

index d99271b196e150677ab0cf537bbad8a05ee9f87e..5a1c5a45b2b57df82fe33a8788cc569a042bf928 100644 (file)
@@ -49,13 +49,14 @@ template<> struct ilist_traits<Instruction>
 /// modifying a program. However, the verifier will ensure that basic blocks
 /// are "well formed".
 /// @brief LLVM Basic Block Representation
-class BasicBlock : public Value {       // Basic blocks are data objects also
+class BasicBlock : public User {       // Basic blocks are data objects also
 public:
   typedef iplist<Instruction> InstListType;
 private :
   InstListType InstList;
   BasicBlock *Prev, *Next; // Next and Prev links for our intrusive linked list
   Function *Parent;
+  Use unwindDest;
 
   void setParent(Function *parent);
   void setNext(BasicBlock *N) { Next = N; }
@@ -75,9 +76,20 @@ public:
   /// InsertBefore is null), or before the specified basic block.
   ///
   explicit BasicBlock(const std::string &Name = "", Function *Parent = 0,
-                      BasicBlock *InsertBefore = 0);
+                      BasicBlock *InsertBefore = 0, BasicBlock *unwindDest = 0);
   ~BasicBlock();
 
+  /// getUnwindDest - Returns the BasicBlock that flow will enter if an unwind
+  /// instruction occurs in this block. May be null, in which case unwinding
+  /// is undefined in this block.
+  const BasicBlock *getUnwindDest() const;
+  BasicBlock *getUnwindDest();
+
+  /// setUnwindDest - Set which BasicBlock flow will enter if an unwind is
+  /// executed within this block. It may be set to null if unwinding is not
+  /// permitted in this block.
+  void setUnwindDest(BasicBlock *unwindDest);
+
   /// getParent - Return the enclosing method, or null if none
   ///
   const Function *getParent() const { return Parent; }
index 5ef832e187c66e79ac243bc3b546b46a3750a9b5..377ff420fd41d1e6e27e8bc57ea2507d110bd679 100644 (file)
@@ -202,7 +202,9 @@ namespace bitc {
     // this is so information only available in the pointer type (e.g. address
     // spaces) is retained.
     FUNC_CODE_INST_STORE2      = 24, // STORE:      [ptrty,ptr,val, align, vol]
-    FUNC_CODE_INST_GETRESULT   = 25  // GETRESULT:  [ty, opval, n]
+    FUNC_CODE_INST_GETRESULT   = 25, // GETRESULT:  [ty, opval, n]
+
+    FUNC_CODE_INST_BB_UNWINDDEST = 26  // BB_UNWINDDEST: [bb#]
   };
 } // End bitc namespace
 } // End llvm namespace
index f78079b606268c899cd0dc114c0b31817cac7c95..18b774b1820e06ccc8e36e73257464cfb4ee0a9d 100644 (file)
@@ -474,6 +474,7 @@ int LLLexer::LexIdentifier() {
   KEYWORD("asm", ASM_TOK);
   KEYWORD("sideeffect", SIDEEFFECT);
   KEYWORD("gc", GC);
+  KEYWORD("unwind_to", UNWIND_TO);
 
   KEYWORD("cc", CC_TOK);
   KEYWORD("ccc", CCC_TOK);
index 5a824ae8fe44b9b24c9972869946b741ddef3092..c5640698de99810a838e6c8b61cbc48448dcf856 100644 (file)
@@ -518,7 +518,7 @@ static Value *getVal(const Type *Ty, const ValID &ID) {
 
 /// defineBBVal - This is a definition of a new basic block with the specified
 /// identifier which must be the same as CurFun.NextValNum, if its numeric.
-static BasicBlock *defineBBVal(const ValID &ID) {
+static BasicBlock *defineBBVal(const ValID &ID, BasicBlock *unwindDest) {
   assert(inFunctionScope() && "Can't get basic block at global scope!");
 
   BasicBlock *BB = 0;
@@ -548,21 +548,19 @@ static BasicBlock *defineBBVal(const ValID &ID) {
       assert(ID.Num == CurFun.NextValNum && "Invalid new block number");
       InsertValue(BB);
     }
-
-    ID.destroy();
-    return BB;
-  } 
-  
-  // We haven't seen this BB before and its first mention is a definition. 
-  // Just create it and return it.
-  std::string Name (ID.Type == ValID::LocalName ? ID.getName() : "");
-  BB = new BasicBlock(Name, CurFun.CurrentFunction);
-  if (ID.Type == ValID::LocalID) {
-    assert(ID.Num == CurFun.NextValNum && "Invalid new block number");
-    InsertValue(BB);
+  } else { 
+    // We haven't seen this BB before and its first mention is a definition. 
+    // Just create it and return it.
+    std::string Name (ID.Type == ValID::LocalName ? ID.getName() : "");
+    BB = new BasicBlock(Name, CurFun.CurrentFunction);
+    if (ID.Type == ValID::LocalID) {
+      assert(ID.Num == CurFun.NextValNum && "Invalid new block number");
+      InsertValue(BB);
+    }
   }
 
-  ID.destroy(); // Free strdup'd memory
+  ID.destroy();
+  BB->setUnwindDest(unwindDest);
   return BB;
 }
 
@@ -1066,7 +1064,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
 %token OPAQUE EXTERNAL TARGET TRIPLE ALIGN ADDRSPACE
 %token DEPLIBS CALL TAIL ASM_TOK MODULE SIDEEFFECT
 %token CC_TOK CCC_TOK FASTCC_TOK COLDCC_TOK X86_STDCALLCC_TOK X86_FASTCALLCC_TOK
-%token DATALAYOUT
+%token DATALAYOUT UNWIND_TO
 %type <UIntVal> OptCallingConv
 %type <ParamAttrs> OptParamAttrs ParamAttr 
 %type <ParamAttrs> OptFuncAttrs  FuncAttr
@@ -2568,14 +2566,22 @@ InstructionList : InstructionList Inst {
     CHECK_FOR_ERROR
   }
   | /* empty */ {          // Empty space between instruction lists
-    $$ = defineBBVal(ValID::createLocalID(CurFun.NextValNum));
+    $$ = defineBBVal(ValID::createLocalID(CurFun.NextValNum), 0);
+    CHECK_FOR_ERROR
+  }
+  | UNWIND_TO ValueRef {   // Only the unwind to block
+    $$ = defineBBVal(ValID::createLocalID(CurFun.NextValNum), getBBVal($2));
     CHECK_FOR_ERROR
   }
   | LABELSTR {             // Labelled (named) basic block
-    $$ = defineBBVal(ValID::createLocalName(*$1));
+    $$ = defineBBVal(ValID::createLocalName(*$1), 0);
+    delete $1;
+    CHECK_FOR_ERROR
+  }
+  | LABELSTR UNWIND_TO ValueRef {
+    $$ = defineBBVal(ValID::createLocalName(*$1), getBBVal($3));
     delete $1;
     CHECK_FOR_ERROR
-
   };
 
 BBTerminatorInst : 
index 61e0ab9898909bcd0b4448ff6993a7b4cb16eb79..c1cfa975a7159a05475be2087aad55d9b67f2f6d 100644 (file)
@@ -1216,6 +1216,15 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
       CurBB = FunctionBBs[0];
       continue;
       
+    case bitc::FUNC_CODE_INST_BB_UNWINDDEST:   // BB_UNWINDDEST: [bb#]
+      if (CurBB->getUnwindDest())
+        return Error("Only permit one BB_UNWINDDEST per BB");
+      if (Record.size() != 1)
+        return Error("Invalid BB_UNWINDDEST record");
+
+      CurBB->setUnwindDest(getBasicBlock(Record[0]));
+      continue;
+      
     case bitc::FUNC_CODE_INST_BINOP: {    // BINOP: [opval, ty, opval, opcode]
       unsigned OpNum = 0;
       Value *LHS, *RHS;
index 5de38b8215691ead0528f1dff41421161eacdb79..67b13e30bad185a2fd8f7c2ec31f744b65dfae27 100644 (file)
@@ -969,13 +969,20 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE,
   unsigned InstID = CstEnd;
   
   // Finally, emit all the instructions, in order.
-  for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
+  for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
+    if (const BasicBlock *unwindDest = BB->getUnwindDest()) {
+      Vals.push_back(VE.getValueID(unwindDest));
+      Stream.EmitRecord(bitc::FUNC_CODE_INST_BB_UNWINDDEST, Vals);
+      Vals.clear();
+    }   
+
     for (BasicBlock::const_iterator I = BB->begin(), E = BB->end();
          I != E; ++I) {
       WriteInstruction(*I, InstID, VE, Stream, Vals);
       if (I->getType() != Type::VoidTy)
         ++InstID;
     }
+  }
   
   // Emit names for all the instructions etc.
   WriteValueSymbolTable(F.getValueSymbolTable(), VE, Stream);
index 55d037db141db02ae4fe7d1d3d0807bd9255afcb..595f478c72a1d246b0ada820aa49c0410d76af65 100644 (file)
@@ -1130,7 +1130,7 @@ void AssemblyWriter::printFunction(const Function *F) {
   if (F->isDeclaration()) {
     Out << "\n";
   } else {
-    Out << " {";
+    Out << " {\n";
 
     // Output all of its basic blocks... for the function
     for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I)
@@ -1162,10 +1162,19 @@ void AssemblyWriter::printArgument(const Argument *Arg,
 /// printBasicBlock - This member is called for each basic block in a method.
 ///
 void AssemblyWriter::printBasicBlock(const BasicBlock *BB) {
-  if (BB->hasName()) {              // Print out the label if it exists...
-    Out << "\n" << getLLVMName(BB->getName(), LabelPrefix) << ':';
-  } else if (!BB->use_empty()) {      // Don't print block # of no uses...
-    Out << "\n; <label>:";
+  if (BB->hasName())              // Print out the label if it exists...
+    Out << getLLVMName(BB->getName(), LabelPrefix) << ':';
+
+  if (const BasicBlock* unwindDest = BB->getUnwindDest()) {
+    if (BB->hasName())
+      Out << ' ';
+
+    Out << "unwind_to";
+    writeOperand(unwindDest, false);
+  }
+
+  if (!BB->hasName() && !BB->use_empty()) { // Don't print block # of no uses...
+    Out << "; <label>:";
     int Slot = Machine.getLocalSlot(BB);
     if (Slot != -1)
       Out << Slot;
@@ -1194,7 +1203,9 @@ void AssemblyWriter::printBasicBlock(const BasicBlock *BB) {
     }
   }
 
-  Out << "\n";
+  if (BB->hasName() || !BB->use_empty() || BB->getUnwindDest() ||
+      BB != &BB->getParent()->getEntryBlock())
+    Out << "\n";
 
   if (AnnotationWriter) AnnotationWriter->emitBasicBlockStartAnnot(BB, Out);
 
index 3ab5e96157955b6bc60aa5077bb2918f84b3a231..f9bead74d25d9ab05680d08b0d43b1a9ddf48403 100644 (file)
@@ -70,8 +70,8 @@ template class SymbolTableListTraits<Instruction, BasicBlock>;
 
 
 BasicBlock::BasicBlock(const std::string &Name, Function *NewParent,
-                       BasicBlock *InsertBefore)
-  : Value(Type::LabelTy, Value::BasicBlockVal), Parent(0) {
+                       BasicBlock *InsertBefore, BasicBlock *Dest)
+  : User(Type::LabelTy, Value::BasicBlockVal, &unwindDest, 0), Parent(0) {
 
   // Make sure that we get added to a function
   LeakDetector::addGarbageObject(this);
@@ -85,6 +85,8 @@ BasicBlock::BasicBlock(const std::string &Name, Function *NewParent,
   }
   
   setName(Name);
+  unwindDest.init(NULL, this);
+  setUnwindDest(Dest);
 }
 
 
@@ -113,6 +115,19 @@ void BasicBlock::eraseFromParent() {
   getParent()->getBasicBlockList().erase(this);
 }
 
+const BasicBlock *BasicBlock::getUnwindDest() const {
+  return cast_or_null<const BasicBlock>(unwindDest.get());
+}
+
+BasicBlock *BasicBlock::getUnwindDest() {
+  return cast_or_null<BasicBlock>(unwindDest.get());
+}
+
+void BasicBlock::setUnwindDest(BasicBlock *dest) {
+  NumOperands = unwindDest ? 1 : 0;
+  unwindDest.set(dest);
+}
+
 /// moveBefore - Unlink this basic block from its current function and
 /// insert it into the function that MovePos lives in, right before MovePos.
 void BasicBlock::moveBefore(BasicBlock *MovePos) {
@@ -151,6 +166,7 @@ Instruction* BasicBlock::getFirstNonPHI()
 }
 
 void BasicBlock::dropAllReferences() {
+  setUnwindDest(NULL);
   for(iterator I = begin(), E = end(); I != E; ++I)
     I->dropAllReferences();
 }
@@ -177,6 +193,9 @@ void BasicBlock::removePredecessor(BasicBlock *Pred,
           find(pred_begin(this), pred_end(this), Pred) != pred_end(this)) &&
          "removePredecessor: BB is not a predecessor!");
 
+  if (Pred == getUnwindDest())
+    setUnwindDest(NULL);
+
   if (InstList.empty()) return;
   PHINode *APN = dyn_cast<PHINode>(&front());
   if (!APN) return;   // Quick exit.
diff --git a/test/Feature/unwindto.ll b/test/Feature/unwindto.ll
new file mode 100644 (file)
index 0000000..7806143
--- /dev/null
@@ -0,0 +1,48 @@
+; RUN: llvm-as < %s | llvm-dis | llvm-as -disable-output
+; PR1269
+; END
+; http://nondot.org/sabre/LLVMNotes/ExceptionHandlingChanges.txt
+
+define i1 @test1(i8 %i, i8 %j) {
+entry: unwind_to %target
+       %tmp = sub i8 %i, %j            ; <i8> [#uses=1]
+       %b = icmp eq i8 %tmp, 0         ; <i1> [#uses=1]
+       ret i1 %b
+target:
+       ret i1 false
+}
+
+define i1 @test2(i8 %i, i8 %j) {
+unwind_to %1
+       %tmp = sub i8 %i, %j            ; <i8> [#uses=1]
+       %b = icmp eq i8 %tmp, 0         ; <i1> [#uses=1]
+       ret i1 %b
+               ; No predecessors!
+       ret i1 false
+}
+
+define i1 @test3(i8 %i, i8 %j) {
+unwind_to %1
+       %tmp = sub i8 %i, %j            ; <i8> [#uses=1]
+       %b = icmp eq i8 %tmp, 0         ; <i1> [#uses=1]
+       ret i1 %b
+unwind_to %0
+       ret i1 false
+}
+
+define i1 @test4(i8 %i, i8 %j) {
+       %tmp = sub i8 %i, %j            ; <i8> [#uses=1]
+       %b = icmp eq i8 %tmp, 0         ; <i1> [#uses=1]
+       br label %1
+unwind_to %1
+       ret i1 false
+}
+
+define void @test5() {
+  unwind
+}
+
+define void @test6() {
+unwind: unwind_to %unwind
+  unwind
+}
index 993f947f09e473b50729bba09f4fd4ef0d141258..c6518a24f4385c68e032be51910a5e437d6fb9c6 100644 (file)
@@ -172,6 +172,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID) {
     switch (CodeID) {
     default: return 0;
     case bitc::FUNC_CODE_DECLAREBLOCKS: return "DECLAREBLOCKS";
+    case bitc::FUNC_CODE_INST_BB_UNWINDDEST: return "UNWINDDEST";
     
     case bitc::FUNC_CODE_INST_BINOP:       return "INST_BINOP";
     case bitc::FUNC_CODE_INST_CAST:        return "INST_CAST";