mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-18 22:38:56 +00:00
Add an unwind_to field to basic blocks, making them Users instead of Values.
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
This commit is contained in:
parent
fe0753efba
commit
fc82fabe00
@ -49,13 +49,14 @@ template<> struct ilist_traits<Instruction>
|
|||||||
/// modifying a program. However, the verifier will ensure that basic blocks
|
/// modifying a program. However, the verifier will ensure that basic blocks
|
||||||
/// are "well formed".
|
/// are "well formed".
|
||||||
/// @brief LLVM Basic Block Representation
|
/// @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:
|
public:
|
||||||
typedef iplist<Instruction> InstListType;
|
typedef iplist<Instruction> InstListType;
|
||||||
private :
|
private :
|
||||||
InstListType InstList;
|
InstListType InstList;
|
||||||
BasicBlock *Prev, *Next; // Next and Prev links for our intrusive linked list
|
BasicBlock *Prev, *Next; // Next and Prev links for our intrusive linked list
|
||||||
Function *Parent;
|
Function *Parent;
|
||||||
|
Use unwindDest;
|
||||||
|
|
||||||
void setParent(Function *parent);
|
void setParent(Function *parent);
|
||||||
void setNext(BasicBlock *N) { Next = N; }
|
void setNext(BasicBlock *N) { Next = N; }
|
||||||
@ -75,9 +76,20 @@ public:
|
|||||||
/// InsertBefore is null), or before the specified basic block.
|
/// InsertBefore is null), or before the specified basic block.
|
||||||
///
|
///
|
||||||
explicit BasicBlock(const std::string &Name = "", Function *Parent = 0,
|
explicit BasicBlock(const std::string &Name = "", Function *Parent = 0,
|
||||||
BasicBlock *InsertBefore = 0);
|
BasicBlock *InsertBefore = 0, BasicBlock *unwindDest = 0);
|
||||||
~BasicBlock();
|
~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
|
/// getParent - Return the enclosing method, or null if none
|
||||||
///
|
///
|
||||||
const Function *getParent() const { return Parent; }
|
const Function *getParent() const { return Parent; }
|
||||||
|
@ -202,7 +202,9 @@ namespace bitc {
|
|||||||
// this is so information only available in the pointer type (e.g. address
|
// this is so information only available in the pointer type (e.g. address
|
||||||
// spaces) is retained.
|
// spaces) is retained.
|
||||||
FUNC_CODE_INST_STORE2 = 24, // STORE: [ptrty,ptr,val, align, vol]
|
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 bitc namespace
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
@ -474,6 +474,7 @@ int LLLexer::LexIdentifier() {
|
|||||||
KEYWORD("asm", ASM_TOK);
|
KEYWORD("asm", ASM_TOK);
|
||||||
KEYWORD("sideeffect", SIDEEFFECT);
|
KEYWORD("sideeffect", SIDEEFFECT);
|
||||||
KEYWORD("gc", GC);
|
KEYWORD("gc", GC);
|
||||||
|
KEYWORD("unwind_to", UNWIND_TO);
|
||||||
|
|
||||||
KEYWORD("cc", CC_TOK);
|
KEYWORD("cc", CC_TOK);
|
||||||
KEYWORD("ccc", CCC_TOK);
|
KEYWORD("ccc", CCC_TOK);
|
||||||
|
@ -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
|
/// 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.
|
/// 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!");
|
assert(inFunctionScope() && "Can't get basic block at global scope!");
|
||||||
|
|
||||||
BasicBlock *BB = 0;
|
BasicBlock *BB = 0;
|
||||||
@ -548,21 +548,19 @@ static BasicBlock *defineBBVal(const ValID &ID) {
|
|||||||
assert(ID.Num == CurFun.NextValNum && "Invalid new block number");
|
assert(ID.Num == CurFun.NextValNum && "Invalid new block number");
|
||||||
InsertValue(BB);
|
InsertValue(BB);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
ID.destroy();
|
// We haven't seen this BB before and its first mention is a definition.
|
||||||
return BB;
|
// Just create it and return it.
|
||||||
}
|
std::string Name (ID.Type == ValID::LocalName ? ID.getName() : "");
|
||||||
|
BB = new BasicBlock(Name, CurFun.CurrentFunction);
|
||||||
// We haven't seen this BB before and its first mention is a definition.
|
if (ID.Type == ValID::LocalID) {
|
||||||
// Just create it and return it.
|
assert(ID.Num == CurFun.NextValNum && "Invalid new block number");
|
||||||
std::string Name (ID.Type == ValID::LocalName ? ID.getName() : "");
|
InsertValue(BB);
|
||||||
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;
|
return BB;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1066,7 +1064,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
|
|||||||
%token OPAQUE EXTERNAL TARGET TRIPLE ALIGN ADDRSPACE
|
%token OPAQUE EXTERNAL TARGET TRIPLE ALIGN ADDRSPACE
|
||||||
%token DEPLIBS CALL TAIL ASM_TOK MODULE SIDEEFFECT
|
%token DEPLIBS CALL TAIL ASM_TOK MODULE SIDEEFFECT
|
||||||
%token CC_TOK CCC_TOK FASTCC_TOK COLDCC_TOK X86_STDCALLCC_TOK X86_FASTCALLCC_TOK
|
%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 <UIntVal> OptCallingConv
|
||||||
%type <ParamAttrs> OptParamAttrs ParamAttr
|
%type <ParamAttrs> OptParamAttrs ParamAttr
|
||||||
%type <ParamAttrs> OptFuncAttrs FuncAttr
|
%type <ParamAttrs> OptFuncAttrs FuncAttr
|
||||||
@ -2568,14 +2566,22 @@ InstructionList : InstructionList Inst {
|
|||||||
CHECK_FOR_ERROR
|
CHECK_FOR_ERROR
|
||||||
}
|
}
|
||||||
| /* empty */ { // Empty space between instruction lists
|
| /* 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
|
CHECK_FOR_ERROR
|
||||||
}
|
}
|
||||||
| LABELSTR { // Labelled (named) basic block
|
| 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;
|
delete $1;
|
||||||
CHECK_FOR_ERROR
|
CHECK_FOR_ERROR
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BBTerminatorInst :
|
BBTerminatorInst :
|
||||||
|
@ -1216,6 +1216,15 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
|
|||||||
CurBB = FunctionBBs[0];
|
CurBB = FunctionBBs[0];
|
||||||
continue;
|
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]
|
case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode]
|
||||||
unsigned OpNum = 0;
|
unsigned OpNum = 0;
|
||||||
Value *LHS, *RHS;
|
Value *LHS, *RHS;
|
||||||
|
@ -969,13 +969,20 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE,
|
|||||||
unsigned InstID = CstEnd;
|
unsigned InstID = CstEnd;
|
||||||
|
|
||||||
// Finally, emit all the instructions, in order.
|
// 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();
|
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
WriteInstruction(*I, InstID, VE, Stream, Vals);
|
WriteInstruction(*I, InstID, VE, Stream, Vals);
|
||||||
if (I->getType() != Type::VoidTy)
|
if (I->getType() != Type::VoidTy)
|
||||||
++InstID;
|
++InstID;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Emit names for all the instructions etc.
|
// Emit names for all the instructions etc.
|
||||||
WriteValueSymbolTable(F.getValueSymbolTable(), VE, Stream);
|
WriteValueSymbolTable(F.getValueSymbolTable(), VE, Stream);
|
||||||
|
@ -1130,7 +1130,7 @@ void AssemblyWriter::printFunction(const Function *F) {
|
|||||||
if (F->isDeclaration()) {
|
if (F->isDeclaration()) {
|
||||||
Out << "\n";
|
Out << "\n";
|
||||||
} else {
|
} else {
|
||||||
Out << " {";
|
Out << " {\n";
|
||||||
|
|
||||||
// Output all of its basic blocks... for the function
|
// Output all of its basic blocks... for the function
|
||||||
for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I)
|
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.
|
/// printBasicBlock - This member is called for each basic block in a method.
|
||||||
///
|
///
|
||||||
void AssemblyWriter::printBasicBlock(const BasicBlock *BB) {
|
void AssemblyWriter::printBasicBlock(const BasicBlock *BB) {
|
||||||
if (BB->hasName()) { // Print out the label if it exists...
|
if (BB->hasName()) // Print out the label if it exists...
|
||||||
Out << "\n" << getLLVMName(BB->getName(), LabelPrefix) << ':';
|
Out << getLLVMName(BB->getName(), LabelPrefix) << ':';
|
||||||
} else if (!BB->use_empty()) { // Don't print block # of no uses...
|
|
||||||
Out << "\n; <label>:";
|
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);
|
int Slot = Machine.getLocalSlot(BB);
|
||||||
if (Slot != -1)
|
if (Slot != -1)
|
||||||
Out << Slot;
|
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);
|
if (AnnotationWriter) AnnotationWriter->emitBasicBlockStartAnnot(BB, Out);
|
||||||
|
|
||||||
|
@ -70,8 +70,8 @@ template class SymbolTableListTraits<Instruction, BasicBlock>;
|
|||||||
|
|
||||||
|
|
||||||
BasicBlock::BasicBlock(const std::string &Name, Function *NewParent,
|
BasicBlock::BasicBlock(const std::string &Name, Function *NewParent,
|
||||||
BasicBlock *InsertBefore)
|
BasicBlock *InsertBefore, BasicBlock *Dest)
|
||||||
: Value(Type::LabelTy, Value::BasicBlockVal), Parent(0) {
|
: User(Type::LabelTy, Value::BasicBlockVal, &unwindDest, 0), Parent(0) {
|
||||||
|
|
||||||
// Make sure that we get added to a function
|
// Make sure that we get added to a function
|
||||||
LeakDetector::addGarbageObject(this);
|
LeakDetector::addGarbageObject(this);
|
||||||
@ -85,6 +85,8 @@ BasicBlock::BasicBlock(const std::string &Name, Function *NewParent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
setName(Name);
|
setName(Name);
|
||||||
|
unwindDest.init(NULL, this);
|
||||||
|
setUnwindDest(Dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -113,6 +115,19 @@ void BasicBlock::eraseFromParent() {
|
|||||||
getParent()->getBasicBlockList().erase(this);
|
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
|
/// moveBefore - Unlink this basic block from its current function and
|
||||||
/// insert it into the function that MovePos lives in, right before MovePos.
|
/// insert it into the function that MovePos lives in, right before MovePos.
|
||||||
void BasicBlock::moveBefore(BasicBlock *MovePos) {
|
void BasicBlock::moveBefore(BasicBlock *MovePos) {
|
||||||
@ -151,6 +166,7 @@ Instruction* BasicBlock::getFirstNonPHI()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BasicBlock::dropAllReferences() {
|
void BasicBlock::dropAllReferences() {
|
||||||
|
setUnwindDest(NULL);
|
||||||
for(iterator I = begin(), E = end(); I != E; ++I)
|
for(iterator I = begin(), E = end(); I != E; ++I)
|
||||||
I->dropAllReferences();
|
I->dropAllReferences();
|
||||||
}
|
}
|
||||||
@ -177,6 +193,9 @@ void BasicBlock::removePredecessor(BasicBlock *Pred,
|
|||||||
find(pred_begin(this), pred_end(this), Pred) != pred_end(this)) &&
|
find(pred_begin(this), pred_end(this), Pred) != pred_end(this)) &&
|
||||||
"removePredecessor: BB is not a predecessor!");
|
"removePredecessor: BB is not a predecessor!");
|
||||||
|
|
||||||
|
if (Pred == getUnwindDest())
|
||||||
|
setUnwindDest(NULL);
|
||||||
|
|
||||||
if (InstList.empty()) return;
|
if (InstList.empty()) return;
|
||||||
PHINode *APN = dyn_cast<PHINode>(&front());
|
PHINode *APN = dyn_cast<PHINode>(&front());
|
||||||
if (!APN) return; // Quick exit.
|
if (!APN) return; // Quick exit.
|
||||||
|
48
test/Feature/unwindto.ll
Normal file
48
test/Feature/unwindto.ll
Normal file
@ -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
|
||||||
|
}
|
@ -172,6 +172,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID) {
|
|||||||
switch (CodeID) {
|
switch (CodeID) {
|
||||||
default: return 0;
|
default: return 0;
|
||||||
case bitc::FUNC_CODE_DECLAREBLOCKS: return "DECLAREBLOCKS";
|
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_BINOP: return "INST_BINOP";
|
||||||
case bitc::FUNC_CODE_INST_CAST: return "INST_CAST";
|
case bitc::FUNC_CODE_INST_CAST: return "INST_CAST";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user