diff options
-rw-r--r-- | include/llvm/BasicBlock.h | 16 | ||||
-rw-r--r-- | include/llvm/Bitcode/LLVMBitCodes.h | 4 | ||||
-rw-r--r-- | lib/AsmParser/LLLexer.cpp | 1 | ||||
-rw-r--r-- | lib/AsmParser/llvmAsmParser.y | 42 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 9 | ||||
-rw-r--r-- | lib/Bitcode/Writer/BitcodeWriter.cpp | 9 | ||||
-rw-r--r-- | lib/VMCore/AsmWriter.cpp | 23 | ||||
-rw-r--r-- | lib/VMCore/BasicBlock.cpp | 23 | ||||
-rw-r--r-- | test/Feature/unwindto.ll | 48 | ||||
-rw-r--r-- | tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 1 |
10 files changed, 146 insertions, 30 deletions
diff --git a/include/llvm/BasicBlock.h b/include/llvm/BasicBlock.h index d99271b196..5a1c5a45b2 100644 --- a/include/llvm/BasicBlock.h +++ b/include/llvm/BasicBlock.h @@ -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; } diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 5ef832e187..377ff420fd 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -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 diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index f78079b606..18b774b182 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -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); diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y index 5a824ae8fe..c5640698de 100644 --- a/lib/AsmParser/llvmAsmParser.y +++ b/lib/AsmParser/llvmAsmParser.y @@ -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 : diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 61e0ab9898..c1cfa975a7 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -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; diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 5de38b8215..67b13e30ba 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -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); diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 55d037db14..595f478c72 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -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); diff --git a/lib/VMCore/BasicBlock.cpp b/lib/VMCore/BasicBlock.cpp index 3ab5e96157..f9bead74d2 100644 --- a/lib/VMCore/BasicBlock.cpp +++ b/lib/VMCore/BasicBlock.cpp @@ -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 index 0000000000..7806143759 --- /dev/null +++ b/test/Feature/unwindto.ll @@ -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 +} diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 993f947f09..c6518a24f4 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -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"; |