diff options
author | Chris Lattner <sabre@nondot.org> | 2009-10-27 19:13:16 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-10-27 19:13:16 +0000 |
commit | f9be95f867745b6754b2402b9b72f9eaeabd637f (patch) | |
tree | 1f51be80a5e575555d713f49a374c10bf298e96c | |
parent | 76b39e88e470171292850d8cebc5d54227b43883 (diff) | |
download | external_llvm-f9be95f867745b6754b2402b9b72f9eaeabd637f.zip external_llvm-f9be95f867745b6754b2402b9b72f9eaeabd637f.tar.gz external_llvm-f9be95f867745b6754b2402b9b72f9eaeabd637f.tar.bz2 |
add enough support for indirect branch for the feature test to pass
(assembler,asmprinter, bc reader+writer) and document it. Codegen
currently aborts on it.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85274 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | docs/LangRef.html | 50 | ||||
-rw-r--r-- | include/llvm/Bitcode/LLVMBitCodes.h | 5 | ||||
-rw-r--r-- | include/llvm/Instruction.def | 121 | ||||
-rw-r--r-- | include/llvm/Instructions.h | 103 | ||||
-rw-r--r-- | include/llvm/Support/InstVisitor.h | 1 | ||||
-rw-r--r-- | lib/AsmParser/LLLexer.cpp | 1 | ||||
-rw-r--r-- | lib/AsmParser/LLParser.cpp | 104 | ||||
-rw-r--r-- | lib/AsmParser/LLParser.h | 9 | ||||
-rw-r--r-- | lib/AsmParser/LLToken.h | 2 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 25 | ||||
-rw-r--r-- | lib/Bitcode/Writer/BitcodeWriter.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuild.h | 2 | ||||
-rw-r--r-- | lib/VMCore/AsmWriter.cpp | 15 | ||||
-rw-r--r-- | lib/VMCore/Instruction.cpp | 1 | ||||
-rw-r--r-- | lib/VMCore/Instructions.cpp | 121 | ||||
-rw-r--r-- | test/Feature/terminators.ll | 11 |
17 files changed, 483 insertions, 102 deletions
diff --git a/docs/LangRef.html b/docs/LangRef.html index 73ee31b..c12bacf 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -110,6 +110,7 @@ <li><a href="#i_ret">'<tt>ret</tt>' Instruction</a></li> <li><a href="#i_br">'<tt>br</tt>' Instruction</a></li> <li><a href="#i_switch">'<tt>switch</tt>' Instruction</a></li> + <li><a href="#i_indbr">'<tt>indbr</tt>' Instruction</a></li> <li><a href="#i_invoke">'<tt>invoke</tt>' Instruction</a></li> <li><a href="#i_unwind">'<tt>unwind</tt>' Instruction</a></li> <li><a href="#i_unreachable">'<tt>unreachable</tt>' Instruction</a></li> @@ -2511,6 +2512,7 @@ Instructions</a> </div> '<a href="#i_ret"><tt>ret</tt></a>' instruction, the '<a href="#i_br"><tt>br</tt></a>' instruction, the '<a href="#i_switch"><tt>switch</tt></a>' instruction, the + '<a href="#i_indbr">'<tt>indbr</tt>' Instruction, the '<a href="#i_invoke"><tt>invoke</tt></a>' instruction, the '<a href="#i_unwind"><tt>unwind</tt></a>' instruction, and the '<a href="#i_unreachable"><tt>unreachable</tt></a>' instruction.</p> @@ -2669,6 +2671,54 @@ IfUnequal: </div> + +<!-- _______________________________________________________________________ --> +<div class="doc_subsubsection"> + <a name="i_indbr">'<tt>indbr</tt>' Instruction</a> +</div> + +<div class="doc_text"> + +<h5>Syntax:</h5> +<pre> + indbr <somety>* <address>, [ label <dest1>, label <dest2>, ... ] +</pre> + +<h5>Overview:</h5> + +<p>The '<tt>indbr</tt>' instruction implements an indirect branch to a label + within the current function, whose address is specified by + "<tt>address</tt>".</p> + +<h5>Arguments:</h5> + +<p>The '<tt>address</tt>' argument is the address of the label to jump to. The + rest of the arguments indicate the full set of possible destinations that the + address may point to. Blocks are allowed to occur multiple times in the + destination list, though this isn't particularly useful.</p> + +<p>This destination list is required so that dataflow analysis has an accurate + understanding of the CFG.</p> + +<h5>Semantics:</h5> + +<p>Control transfers to the block specified in the address argument. All + possible destination blocks must be listed in the label list, otherwise this + instruction has undefined behavior. This implies that jumps to labels + defined in other functions have undefined behavior as well.</p> + +<h5>Implementation:</h5> + +<p>This is typically implemented with a jump through a register.</p> + +<h5>Example:</h5> +<pre> + switch i8* %Addr, [ label %bb1, label %bb2, label %bb3 ] +</pre> + +</div> + + <!-- _______________________________________________________________________ --> <div class="doc_subsubsection"> <a name="i_invoke">'<tt>invoke</tt>' Instruction</a> diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index dccd8e0..55bd256 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -209,7 +209,7 @@ namespace bitc { FUNC_CODE_INST_RET = 10, // RET: [opty,opval<both optional>] FUNC_CODE_INST_BR = 11, // BR: [bb#, bb#, cond] or [bb#] - FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, opval, n, n x ops] + FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, operands...] FUNC_CODE_INST_INVOKE = 13, // INVOKE: [attr, fnty, op0,op1, ...] FUNC_CODE_INST_UNWIND = 14, // UNWIND FUNC_CODE_INST_UNREACHABLE = 15, // UNREACHABLE @@ -236,7 +236,8 @@ namespace bitc { FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred] // new select on i1 or [N x i1] FUNC_CODE_INST_VSELECT = 29, // VSELECT: [ty,opval,opval,predty,pred] - FUNC_CODE_INST_INBOUNDS_GEP = 30 // INBOUNDS_GEP: [n x operands] + FUNC_CODE_INST_INBOUNDS_GEP= 30, // INBOUNDS_GEP: [n x operands] + FUNC_CODE_INST_INDBR = 31 // INDBR: [opty, operands...] }; } // End bitc namespace } // End llvm namespace diff --git a/include/llvm/Instruction.def b/include/llvm/Instruction.def index ec86b35..c0adf40 100644 --- a/include/llvm/Instruction.def +++ b/include/llvm/Instruction.def @@ -97,78 +97,79 @@ HANDLE_TERM_INST ( 1, Ret , ReturnInst) HANDLE_TERM_INST ( 2, Br , BranchInst) HANDLE_TERM_INST ( 3, Switch , SwitchInst) -HANDLE_TERM_INST ( 4, Invoke , InvokeInst) -HANDLE_TERM_INST ( 5, Unwind , UnwindInst) -HANDLE_TERM_INST ( 6, Unreachable, UnreachableInst) - LAST_TERM_INST ( 6) +HANDLE_TERM_INST ( 4, IndBr , IndBrInst) +HANDLE_TERM_INST ( 5, Invoke , InvokeInst) +HANDLE_TERM_INST ( 6, Unwind , UnwindInst) +HANDLE_TERM_INST ( 7, Unreachable, UnreachableInst) + LAST_TERM_INST ( 7) // Standard binary operators... - FIRST_BINARY_INST( 7) -HANDLE_BINARY_INST( 7, Add , BinaryOperator) -HANDLE_BINARY_INST( 8, FAdd , BinaryOperator) -HANDLE_BINARY_INST( 9, Sub , BinaryOperator) -HANDLE_BINARY_INST(10, FSub , BinaryOperator) -HANDLE_BINARY_INST(11, Mul , BinaryOperator) -HANDLE_BINARY_INST(12, FMul , BinaryOperator) -HANDLE_BINARY_INST(13, UDiv , BinaryOperator) -HANDLE_BINARY_INST(14, SDiv , BinaryOperator) -HANDLE_BINARY_INST(15, FDiv , BinaryOperator) -HANDLE_BINARY_INST(16, URem , BinaryOperator) -HANDLE_BINARY_INST(17, SRem , BinaryOperator) -HANDLE_BINARY_INST(18, FRem , BinaryOperator) + FIRST_BINARY_INST( 8) +HANDLE_BINARY_INST( 8, Add , BinaryOperator) +HANDLE_BINARY_INST( 9, FAdd , BinaryOperator) +HANDLE_BINARY_INST(10, Sub , BinaryOperator) +HANDLE_BINARY_INST(11, FSub , BinaryOperator) +HANDLE_BINARY_INST(12, Mul , BinaryOperator) +HANDLE_BINARY_INST(13, FMul , BinaryOperator) +HANDLE_BINARY_INST(14, UDiv , BinaryOperator) +HANDLE_BINARY_INST(15, SDiv , BinaryOperator) +HANDLE_BINARY_INST(16, FDiv , BinaryOperator) +HANDLE_BINARY_INST(17, URem , BinaryOperator) +HANDLE_BINARY_INST(18, SRem , BinaryOperator) +HANDLE_BINARY_INST(19, FRem , BinaryOperator) // Logical operators (integer operands) -HANDLE_BINARY_INST(19, Shl , BinaryOperator) // Shift left (logical) -HANDLE_BINARY_INST(20, LShr , BinaryOperator) // Shift right (logical) -HANDLE_BINARY_INST(21, AShr , BinaryOperator) // Shift right (arithmetic) -HANDLE_BINARY_INST(22, And , BinaryOperator) -HANDLE_BINARY_INST(23, Or , BinaryOperator) -HANDLE_BINARY_INST(24, Xor , BinaryOperator) - LAST_BINARY_INST(24) +HANDLE_BINARY_INST(20, Shl , BinaryOperator) // Shift left (logical) +HANDLE_BINARY_INST(21, LShr , BinaryOperator) // Shift right (logical) +HANDLE_BINARY_INST(22, AShr , BinaryOperator) // Shift right (arithmetic) +HANDLE_BINARY_INST(23, And , BinaryOperator) +HANDLE_BINARY_INST(24, Or , BinaryOperator) +HANDLE_BINARY_INST(25, Xor , BinaryOperator) + LAST_BINARY_INST(25) // Memory operators... - FIRST_MEMORY_INST(25) -HANDLE_MEMORY_INST(25, Alloca, AllocaInst) // Stack management -HANDLE_MEMORY_INST(26, Load , LoadInst ) // Memory manipulation instrs -HANDLE_MEMORY_INST(27, Store , StoreInst ) -HANDLE_MEMORY_INST(28, GetElementPtr, GetElementPtrInst) - LAST_MEMORY_INST(28) + FIRST_MEMORY_INST(26) +HANDLE_MEMORY_INST(26, Alloca, AllocaInst) // Stack management +HANDLE_MEMORY_INST(27, Load , LoadInst ) // Memory manipulation instrs +HANDLE_MEMORY_INST(28, Store , StoreInst ) +HANDLE_MEMORY_INST(29, GetElementPtr, GetElementPtrInst) + LAST_MEMORY_INST(29) // Cast operators ... // NOTE: The order matters here because CastInst::isEliminableCastPair // NOTE: (see Instructions.cpp) encodes a table based on this ordering. - FIRST_CAST_INST(29) -HANDLE_CAST_INST(29, Trunc , TruncInst ) // Truncate integers -HANDLE_CAST_INST(30, ZExt , ZExtInst ) // Zero extend integers -HANDLE_CAST_INST(31, SExt , SExtInst ) // Sign extend integers -HANDLE_CAST_INST(32, FPToUI , FPToUIInst ) // floating point -> UInt -HANDLE_CAST_INST(33, FPToSI , FPToSIInst ) // floating point -> SInt -HANDLE_CAST_INST(34, UIToFP , UIToFPInst ) // UInt -> floating point -HANDLE_CAST_INST(35, SIToFP , SIToFPInst ) // SInt -> floating point -HANDLE_CAST_INST(36, FPTrunc , FPTruncInst ) // Truncate floating point -HANDLE_CAST_INST(37, FPExt , FPExtInst ) // Extend floating point -HANDLE_CAST_INST(38, PtrToInt, PtrToIntInst) // Pointer -> Integer -HANDLE_CAST_INST(39, IntToPtr, IntToPtrInst) // Integer -> Pointer -HANDLE_CAST_INST(40, BitCast , BitCastInst ) // Type cast - LAST_CAST_INST(40) + FIRST_CAST_INST(30) +HANDLE_CAST_INST(30, Trunc , TruncInst ) // Truncate integers +HANDLE_CAST_INST(31, ZExt , ZExtInst ) // Zero extend integers +HANDLE_CAST_INST(32, SExt , SExtInst ) // Sign extend integers +HANDLE_CAST_INST(33, FPToUI , FPToUIInst ) // floating point -> UInt +HANDLE_CAST_INST(34, FPToSI , FPToSIInst ) // floating point -> SInt +HANDLE_CAST_INST(35, UIToFP , UIToFPInst ) // UInt -> floating point +HANDLE_CAST_INST(36, SIToFP , SIToFPInst ) // SInt -> floating point +HANDLE_CAST_INST(37, FPTrunc , FPTruncInst ) // Truncate floating point +HANDLE_CAST_INST(38, FPExt , FPExtInst ) // Extend floating point +HANDLE_CAST_INST(39, PtrToInt, PtrToIntInst) // Pointer -> Integer +HANDLE_CAST_INST(40, IntToPtr, IntToPtrInst) // Integer -> Pointer +HANDLE_CAST_INST(41, BitCast , BitCastInst ) // Type cast + LAST_CAST_INST(41) // Other operators... - FIRST_OTHER_INST(41) -HANDLE_OTHER_INST(41, ICmp , ICmpInst ) // Integer comparison instruction -HANDLE_OTHER_INST(42, FCmp , FCmpInst ) // Floating point comparison instr. -HANDLE_OTHER_INST(43, PHI , PHINode ) // PHI node instruction -HANDLE_OTHER_INST(44, Call , CallInst ) // Call a function -HANDLE_OTHER_INST(45, Select , SelectInst ) // select instruction -HANDLE_OTHER_INST(46, UserOp1, Instruction) // May be used internally in a pass -HANDLE_OTHER_INST(47, UserOp2, Instruction) // Internal to passes only -HANDLE_OTHER_INST(48, VAArg , VAArgInst ) // vaarg instruction -HANDLE_OTHER_INST(49, ExtractElement, ExtractElementInst)// extract from vector -HANDLE_OTHER_INST(50, InsertElement, InsertElementInst) // insert into vector -HANDLE_OTHER_INST(51, ShuffleVector, ShuffleVectorInst) // shuffle two vectors. -HANDLE_OTHER_INST(52, ExtractValue, ExtractValueInst)// extract from aggregate -HANDLE_OTHER_INST(53, InsertValue, InsertValueInst) // insert into aggregate - - LAST_OTHER_INST(53) + FIRST_OTHER_INST(42) +HANDLE_OTHER_INST(42, ICmp , ICmpInst ) // Integer comparison instruction +HANDLE_OTHER_INST(43, FCmp , FCmpInst ) // Floating point comparison instr. +HANDLE_OTHER_INST(44, PHI , PHINode ) // PHI node instruction +HANDLE_OTHER_INST(45, Call , CallInst ) // Call a function +HANDLE_OTHER_INST(46, Select , SelectInst ) // select instruction +HANDLE_OTHER_INST(47, UserOp1, Instruction) // May be used internally in a pass +HANDLE_OTHER_INST(48, UserOp2, Instruction) // Internal to passes only +HANDLE_OTHER_INST(49, VAArg , VAArgInst ) // vaarg instruction +HANDLE_OTHER_INST(50, ExtractElement, ExtractElementInst)// extract from vector +HANDLE_OTHER_INST(51, InsertElement, InsertElementInst) // insert into vector +HANDLE_OTHER_INST(52, ShuffleVector, ShuffleVectorInst) // shuffle two vectors. +HANDLE_OTHER_INST(53, ExtractValue, ExtractValueInst)// extract from aggregate +HANDLE_OTHER_INST(54, InsertValue, InsertValueInst) // insert into aggregate + + LAST_OTHER_INST(54) #undef FIRST_TERM_INST #undef HANDLE_TERM_INST diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index 2f69171..9a9d718 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -2076,7 +2076,7 @@ class SwitchInst : public TerminatorInst { // Operand[1] = Default basic block destination // Operand[2n ] = Value to match // Operand[2n+1] = BasicBlock to go to on match - SwitchInst(const SwitchInst &RI); + SwitchInst(const SwitchInst &SI); void init(Value *Value, BasicBlock *Default, unsigned NumCases); void resizeOperands(unsigned No); // allocate space for exactly zero operands @@ -2088,7 +2088,7 @@ class SwitchInst : public TerminatorInst { /// be specified here to make memory allocation more efficient. This /// constructor can also autoinsert before another instruction. SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, - Instruction *InsertBefore = 0); + Instruction *InsertBefore); /// SwitchInst ctor - Create a new switch instruction, specifying a value to /// switch on and a default destination. The number of additional cases can @@ -2214,6 +2214,105 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SwitchInst, Value) //===----------------------------------------------------------------------===// +// IndBrInst Class +//===----------------------------------------------------------------------===// + +//===--------------------------------------------------------------------------- +/// IndBrInst - Indirect Branch Instruction. +/// +class IndBrInst : public TerminatorInst { + void *operator new(size_t, unsigned); // DO NOT IMPLEMENT + unsigned ReservedSpace; + // Operand[0] = Value to switch on + // Operand[1] = Default basic block destination + // Operand[2n ] = Value to match + // Operand[2n+1] = BasicBlock to go to on match + IndBrInst(const IndBrInst &IBI); + void init(Value *Address, unsigned NumDests); + void resizeOperands(unsigned No); + // allocate space for exactly zero operands + void *operator new(size_t s) { + return User::operator new(s, 0); + } + /// IndBrInst ctor - Create a new indbr instruction, specifying an Address to + /// jump to. The number of expected destinations can be specified here to + /// make memory allocation more efficient. This constructor can also + /// autoinsert before another instruction. + IndBrInst(Value *Address, unsigned NumDests, Instruction *InsertBefore); + + /// IndBrInst ctor - Create a new indbr instruction, specifying an Address to + /// jump to. The number of expected destinations can be specified here to + /// make memory allocation more efficient. This constructor also autoinserts + /// at the end of the specified BasicBlock. + IndBrInst(Value *Address, unsigned NumDests, BasicBlock *InsertAtEnd); +public: + static IndBrInst *Create(Value *Address, unsigned NumDests, + Instruction *InsertBefore = 0) { + return new IndBrInst(Address, NumDests, InsertBefore); + } + static IndBrInst *Create(Value *Address, unsigned NumDests, + BasicBlock *InsertAtEnd) { + return new IndBrInst(Address, NumDests, InsertAtEnd); + } + ~IndBrInst(); + + /// Provide fast operand accessors. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + + // Accessor Methods for IndBr instruction. + Value *getAddress() { return getOperand(0); } + const Value *getAddress() const { return getOperand(0); } + void setAddress(Value *V) { setOperand(0, V); } + + + /// getNumDestinations - return the number of possible destinations in this + /// indbr instruction. + unsigned getNumDestinations() const { return getNumOperands()-1; } + + /// getDestination - Return the specified destination. + BasicBlock *getDestination(unsigned i) { return getSuccessor(i); } + const BasicBlock *getDestination(unsigned i) const { return getSuccessor(i); } + + /// addDestination - Add a destination. + /// + void addDestination(BasicBlock *Dest); + + /// removeDestination - This method removes the specified successor from the + /// indbr instruction. + void removeDestination(unsigned i); + + virtual IndBrInst *clone() const; + + unsigned getNumSuccessors() const { return getNumOperands()-1; } + BasicBlock *getSuccessor(unsigned i) const { + return cast<BasicBlock>(getOperand(i+1)); + } + void setSuccessor(unsigned i, BasicBlock *NewSucc) { + setOperand(i+1, (Value*)NewSucc); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const IndBrInst *) { return true; } + static inline bool classof(const Instruction *I) { + return I->getOpcode() == Instruction::IndBr; + } + static inline bool classof(const Value *V) { + return isa<Instruction>(V) && classof(cast<Instruction>(V)); + } +private: + virtual BasicBlock *getSuccessorV(unsigned idx) const; + virtual unsigned getNumSuccessorsV() const; + virtual void setSuccessorV(unsigned idx, BasicBlock *B); +}; + +template <> +struct OperandTraits<IndBrInst> : public HungoffOperandTraits<1> { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(IndBrInst, Value) + + +//===----------------------------------------------------------------------===// // InvokeInst Class //===----------------------------------------------------------------------===// diff --git a/include/llvm/Support/InstVisitor.h b/include/llvm/Support/InstVisitor.h index ae35a3c..ce97884 100644 --- a/include/llvm/Support/InstVisitor.h +++ b/include/llvm/Support/InstVisitor.h @@ -160,6 +160,7 @@ public: RetTy visitReturnInst(ReturnInst &I) { DELEGATE(TerminatorInst);} RetTy visitBranchInst(BranchInst &I) { DELEGATE(TerminatorInst);} RetTy visitSwitchInst(SwitchInst &I) { DELEGATE(TerminatorInst);} + RetTy visitIndBrInst(IndBrInst &I) { DELEGATE(TerminatorInst);} RetTy visitInvokeInst(InvokeInst &I) { DELEGATE(TerminatorInst);} RetTy visitUnwindInst(UnwindInst &I) { DELEGATE(TerminatorInst);} RetTy visitUnreachableInst(UnreachableInst &I) { DELEGATE(TerminatorInst);} diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 4fb7ea9..1003907 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -645,6 +645,7 @@ lltok::Kind LLLexer::LexIdentifier() { INSTKEYWORD(ret, Ret); INSTKEYWORD(br, Br); INSTKEYWORD(switch, Switch); + INSTKEYWORD(indbr, IndBr); INSTKEYWORD(invoke, Invoke); INSTKEYWORD(unwind, Unwind); INSTKEYWORD(unreachable, Unreachable); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index fa803bb..cf16e42 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -2412,6 +2412,18 @@ bool LLParser::ParseTypeAndValue(Value *&V, PerFunctionState &PFS) { ParseValue(T, V, PFS); } +bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc, + PerFunctionState &PFS) { + Value *V; + Loc = Lex.getLoc(); + if (ParseTypeAndValue(V, PFS)) return true; + if (!isa<BasicBlock>(V)) + return Error(Loc, "expected a basic block"); + BB = cast<BasicBlock>(V); + return false; +} + + /// FunctionHeader /// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs /// Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection @@ -2719,6 +2731,7 @@ bool LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, case lltok::kw_ret: return ParseRet(Inst, BB, PFS); case lltok::kw_br: return ParseBr(Inst, PFS); case lltok::kw_switch: return ParseSwitch(Inst, PFS); + case lltok::kw_indbr: return ParseIndBr(Inst, PFS); case lltok::kw_invoke: return ParseInvoke(Inst, PFS); // Binary Operators. case lltok::kw_add: @@ -2922,7 +2935,8 @@ bool LLParser::ParseRet(Instruction *&Inst, BasicBlock *BB, /// ::= 'br' TypeAndValue ',' TypeAndValue ',' TypeAndValue bool LLParser::ParseBr(Instruction *&Inst, PerFunctionState &PFS) { LocTy Loc, Loc2; - Value *Op0, *Op1, *Op2; + Value *Op0; + BasicBlock *Op1, *Op2; if (ParseTypeAndValue(Op0, Loc, PFS)) return true; if (BasicBlock *BB = dyn_cast<BasicBlock>(Op0)) { @@ -2934,17 +2948,12 @@ bool LLParser::ParseBr(Instruction *&Inst, PerFunctionState &PFS) { return Error(Loc, "branch condition must have 'i1' type"); if (ParseToken(lltok::comma, "expected ',' after branch condition") || - ParseTypeAndValue(Op1, Loc, PFS) || + ParseTypeAndBasicBlock(Op1, Loc, PFS) || ParseToken(lltok::comma, "expected ',' after true destination") || - ParseTypeAndValue(Op2, Loc2, PFS)) + ParseTypeAndBasicBlock(Op2, Loc2, PFS)) return true; - if (!isa<BasicBlock>(Op1)) - return Error(Loc, "true destination of branch must be a basic block"); - if (!isa<BasicBlock>(Op2)) - return Error(Loc2, "true destination of branch must be a basic block"); - - Inst = BranchInst::Create(cast<BasicBlock>(Op1), cast<BasicBlock>(Op2), Op0); + Inst = BranchInst::Create(Op1, Op2, Op0); return false; } @@ -2955,50 +2964,87 @@ bool LLParser::ParseBr(Instruction *&Inst, PerFunctionState &PFS) { /// ::= (TypeAndValue ',' TypeAndValue)* bool LLParser::ParseSwitch(Instruction *&Inst, PerFunctionState &PFS) { LocTy CondLoc, BBLoc; - Value *Cond, *DefaultBB; + Value *Cond; + BasicBlock *DefaultBB; if (ParseTypeAndValue(Cond, CondLoc, PFS) || ParseToken(lltok::comma, "expected ',' after switch condition") || - ParseTypeAndValue(DefaultBB, BBLoc, PFS) || + ParseTypeAndBasicBlock(DefaultBB, BBLoc, PFS) || ParseToken(lltok::lsquare, "expected '[' with switch table")) return true; if (!isa<IntegerType>(Cond->getType())) return Error(CondLoc, "switch condition must have integer type"); - if (!isa<BasicBlock>(DefaultBB)) - return Error(BBLoc, "default destination must be a basic block"); // Parse the jump table pairs. SmallPtrSet<Value*, 32> SeenCases; SmallVector<std::pair<ConstantInt*, BasicBlock*>, 32> Table; while (Lex.getKind() != lltok::rsquare) { - Value *Constant, *DestBB; + Value *Constant; + BasicBlock *DestBB; if (ParseTypeAndValue(Constant, CondLoc, PFS) || ParseToken(lltok::comma, "expected ',' after case value") || - ParseTypeAndValue(DestBB, BBLoc, PFS)) + ParseTypeAndBasicBlock(DestBB, PFS)) return true; - + if (!SeenCases.insert(Constant)) return Error(CondLoc, "duplicate case value in switch"); if (!isa<ConstantInt>(Constant)) return Error(CondLoc, "case value is not a constant integer"); - if (!isa<BasicBlock>(DestBB)) - return Error(BBLoc, "case destination is not a basic block"); - Table.push_back(std::make_pair(cast<ConstantInt>(Constant), - cast<BasicBlock>(DestBB))); + Table.push_back(std::make_pair(cast<ConstantInt>(Constant), DestBB)); } Lex.Lex(); // Eat the ']'. - SwitchInst *SI = SwitchInst::Create(Cond, cast<BasicBlock>(DefaultBB), - Table.size()); + SwitchInst *SI = SwitchInst::Create(Cond, DefaultBB, Table.size()); for (unsigned i = 0, e = Table.size(); i != e; ++i) SI->addCase(Table[i].first, Table[i].second); Inst = SI; return false; } +/// ParseIndBr +/// Instruction +/// ::= 'indbr' TypeAndValue ',' '[' LabelList ']' +bool LLParser::ParseIndBr(Instruction *&Inst, PerFunctionState &PFS) { + LocTy AddrLoc; + Value *Address; + if (ParseTypeAndValue(Address, AddrLoc, PFS) || + ParseToken(lltok::comma, "expected ',' after indbr address") || + ParseToken(lltok::lsquare, "expected '[' with indbr")) + return true; + + if (!isa<PointerType>(Address->getType())) + return Error(AddrLoc, "indbr address must have pointer type"); + + // Parse the destination list. + SmallVector<BasicBlock*, 16> DestList; + + if (Lex.getKind() != lltok::rsquare) { + BasicBlock *DestBB; + if (ParseTypeAndBasicBlock(DestBB, PFS)) + return true; + DestList.push_back(DestBB); + + while (EatIfPresent(lltok::comma)) { + if (ParseTypeAndBasicBlock(DestBB, PFS)) + return true; + DestList.push_back(DestBB); + } + } + + if (ParseToken(lltok::rsquare, "expected ']' at end of block list")) + return true; + + IndBrInst *IBI = IndBrInst::Create(Address, DestList.size()); + for (unsigned i = 0, e = DestList.size(); i != e; ++i) + IBI->addDestination(DestList[i]); + Inst = IBI; + return false; +} + + /// ParseInvoke /// ::= 'invoke' OptionalCallingConv OptionalAttrs Type Value ParamList /// OptionalAttrs 'to' TypeAndValue 'unwind' TypeAndValue @@ -3011,7 +3057,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { ValID CalleeID; SmallVector<ParamInfo, 16> ArgList; - Value *NormalBB, *UnwindBB; + BasicBlock *NormalBB, *UnwindBB; if (ParseOptionalCallingConv(CC) || ParseOptionalAttrs(RetAttrs, 1) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) || @@ -3019,16 +3065,11 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { ParseParameterList(ArgList, PFS) || ParseOptionalAttrs(FnAttrs, 2) || ParseToken(lltok::kw_to, "expected 'to' in invoke") || - ParseTypeAndValue(NormalBB, PFS) || + ParseTypeAndBasicBlock(NormalBB, PFS) || ParseToken(lltok::kw_unwind, "expected 'unwind' in invoke") || - ParseTypeAndValue(UnwindBB, PFS)) + ParseTypeAndBasicBlock(UnwindBB, PFS)) return true; - if (!isa<BasicBlock>(NormalBB)) - return Error(CallLoc, "normal destination is not a basic block"); - if (!isa<BasicBlock>(UnwindBB)) - return Error(CallLoc, "unwind destination is not a basic block"); - // If RetType is a non-function pointer type, then this is the short syntax // for the call, which means that RetType is just the return type. Infer the // rest of the function argument types from the arguments that are present. @@ -3096,8 +3137,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { // Finish off the Attributes and check them AttrListPtr PAL = AttrListPtr::get(Attrs.begin(), Attrs.end()); - InvokeInst *II = InvokeInst::Create(Callee, cast<BasicBlock>(NormalBB), - cast<BasicBlock>(UnwindBB), + InvokeInst *II = InvokeInst::Create(Callee, NormalBB, UnwindBB, Args.begin(), Args.end()); II->setCallingConv(CC); II->setAttributes(PAL); diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index b6877bc..37473a0 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -230,7 +230,13 @@ namespace llvm { Loc = Lex.getLoc(); return ParseTypeAndValue(V, PFS); } - + bool ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc, + PerFunctionState &PFS); + bool ParseTypeAndBasicBlock(BasicBlock *&BB, PerFunctionState &PFS) { + LocTy Loc; + return ParseTypeAndBasicBlock(BB, Loc, PFS); + } + struct ParamInfo { LocTy Loc; Value *V; @@ -264,6 +270,7 @@ namespace llvm { bool ParseRet(Instruction *&Inst, BasicBlock *BB, PerFunctionState &PFS); bool ParseBr(Instruction *&Inst, PerFunctionState &PFS); bool ParseSwitch(Instruction *&Inst, PerFunctionState &PFS); + bool ParseIndBr(Instruction *&Inst, PerFunctionState &PFS); bool ParseInvoke(Instruction *&Inst, PerFunctionState &PFS); bool ParseArithmetic(Instruction *&I, PerFunctionState &PFS, unsigned Opc, diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index f5072fe..a25b6f0 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -111,7 +111,7 @@ namespace lltok { kw_fptoui, kw_fptosi, kw_inttoptr, kw_ptrtoint, kw_bitcast, kw_select, kw_va_arg, - kw_ret, kw_br, kw_switch, kw_invoke, kw_unwind, kw_unreachable, + kw_ret, kw_br, kw_switch, kw_indbr, kw_invoke, kw_unwind, kw_unreachable, kw_malloc, kw_alloca, kw_free, kw_load, kw_store, kw_getelementptr, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index b392122..41803c0 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1951,7 +1951,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } break; } - case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, opval, n, n x ops] + case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] if (Record.size() < 3 || (Record.size() & 1) == 0) return Error("Invalid SWITCH record"); const Type *OpTy = getTypeByID(Record[0]); @@ -1975,7 +1975,28 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { I = SI; break; } - + case bitc::FUNC_CODE_INST_INDBR: { // INDBR: [opty, op0, op1, ...] + if (Record.size() < 2) + return Error("Invalid INDBR record"); + const Type *OpTy = getTypeByID(Record[0]); + Value *Address = getFnValueByID(Record[1], OpTy); + if (OpTy == 0 || Address == 0) + return Error("Invalid INDBR record"); + unsigned NumDests = Record.size()-2; + IndBrInst *IBI = IndBrInst::Create(Address, NumDests); + InstructionList.push_back(IBI); + for (unsigned i = 0, e = NumDests; i != e; ++i) { + if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { + IBI->addDestination(DestBB); + } else { + delete IBI; + return Error("Invalid INDBR record!"); + } + } + I = IBI; + break; + } + case bitc::FUNC_CODE_INST_INVOKE: { // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] if (Record.size() < 4) return Error("Invalid INVOKE record"); diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index aee825c..c0f97c1 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1001,7 +1001,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, case Instruction::Br: { Code = bitc::FUNC_CODE_INST_BR; - BranchInst &II(cast<BranchInst>(I)); + BranchInst &II = cast<BranchInst>(I); Vals.push_back(VE.getValueID(II.getSuccessor(0))); if (II.isConditional()) { Vals.push_back(VE.getValueID(II.getSuccessor(1))); @@ -1015,6 +1015,13 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) Vals.push_back(VE.getValueID(I.getOperand(i))); break; + case Instruction::IndBr: + Code = bitc::FUNC_CODE_INST_INDBR; + Vals.push_back(VE.getTypeID(I.getOperand(0)->getType())); + for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) + Vals.push_back(VE.getValueID(I.getOperand(i))); + break; + case Instruction::Invoke: { const InvokeInst *II = cast<InvokeInst>(&I); const Value *Callee(II->getCalledValue()); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp index b220d55..73c9c5f 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp @@ -2131,6 +2131,11 @@ void SelectionDAGLowering::visitSwitch(SwitchInst &SI) { } } +void SelectionDAGLowering::visitIndBr(IndBrInst &I) { + fprintf(stderr, "indbr codegen not implemented yet"); + abort(); +} + void SelectionDAGLowering::visitFSub(User &I) { // -0.0 - X --> fneg diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h index 7470551..9aca707 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h @@ -49,6 +49,7 @@ class GetElementPtrInst; class GCFunctionInfo; class ICmpInst; class IntToPtrInst; +class IndBrInst; class InvokeInst; class InsertElementInst; class InsertValueInst; @@ -448,6 +449,7 @@ private: void visitRet(ReturnInst &I); void visitBr(BranchInst &I); void visitSwitch(SwitchInst &I); + void visitIndBr(IndBrInst &I); void visitUnreachable(UnreachableInst &I) { /* noop */ } // Helpers for visitSwitch diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 59ee375..5a92432 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -1832,7 +1832,7 @@ void AssemblyWriter::printInstruction(const Instruction &I) { writeOperand(BI.getSuccessor(1), true); } else if (isa<SwitchInst>(I)) { - // Special case switch statement to get formatting nice and correct... + // Special case switch instruction to get formatting nice and correct. Out << ' '; writeOperand(Operand , true); Out << ", "; @@ -1846,6 +1846,19 @@ void AssemblyWriter::printInstruction(const Instruction &I) { writeOperand(I.getOperand(op+1), true); } Out << "\n ]"; + } else if (isa<IndBrInst>(I)) { + // Special case indbr instruction to get formatting nice and correct. + Out << ' '; + writeOperand(Operand, true); + Out << ", "; + Out << " ["; + + for (unsigned i = 1, e = I.getNumOperands(); i != e; ++i) { + if (i != 1) + Out << ", "; + writeOperand(I.getOperand(i), true); + } + Out << ']'; } else if (isa<PHINode>(I)) { Out << ' '; TypePrinter.print(I.getType(), Out); diff --git a/lib/VMCore/Instruction.cpp b/lib/VMCore/Instruction.cpp index def7b3b..4e89222 100644 --- a/lib/VMCore/Instruction.cpp +++ b/lib/VMCore/Instruction.cpp @@ -103,6 +103,7 @@ const char *Instruction::getOpcodeName(unsigned OpCode) { case Ret: return "ret"; case Br: return "br"; case Switch: return "switch"; + case IndBr: return "indbr"; case Invoke: return "invoke"; case Unwind: return "unwind"; case Unreachable: return "unreachable"; diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 02d5af0..61b8044 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -3086,6 +3086,118 @@ void SwitchInst::setSuccessorV(unsigned idx, BasicBlock *B) { setSuccessor(idx, B); } +//===----------------------------------------------------------------------===// +// SwitchInst Implementation +//===----------------------------------------------------------------------===// + +void IndBrInst::init(Value *Address, unsigned NumDests) { + assert(Address); + ReservedSpace = 1+NumDests; + NumOperands = 1; + OperandList = allocHungoffUses(ReservedSpace); + + OperandList[0] = Address; +} + + +/// resizeOperands - resize operands - This adjusts the length of the operands +/// list according to the following behavior: +/// 1. If NumOps == 0, grow the operand list in response to a push_back style +/// of operation. This grows the number of ops by 2 times. +/// 2. If NumOps > NumOperands, reserve space for NumOps operands. +/// 3. If NumOps == NumOperands, trim the reserved space. +/// +void IndBrInst::resizeOperands(unsigned NumOps) { + unsigned e = getNumOperands(); + if (NumOps == 0) { + NumOps = e*2; + } else if (NumOps*2 > NumOperands) { + // No resize needed. + if (ReservedSpace >= NumOps) return; + } else if (NumOps == NumOperands) { + if (ReservedSpace == NumOps) return; + } else { + return; + } + + ReservedSpace = NumOps; + Use *NewOps = allocHungoffUses(NumOps); + Use *OldOps = OperandList; + for (unsigned i = 0; i != e; ++i) + NewOps[i] = OldOps[i]; + OperandList = NewOps; + if (OldOps) Use::zap(OldOps, OldOps + e, true); +} + +IndBrInst::IndBrInst(Value *Address, unsigned NumCases, + Instruction *InsertBefore) +: TerminatorInst(Type::getVoidTy(Address->getContext()), Instruction::IndBr, + 0, 0, InsertBefore) { + init(Address, NumCases); +} + +IndBrInst::IndBrInst(Value *Address, unsigned NumCases, BasicBlock *InsertAtEnd) +: TerminatorInst(Type::getVoidTy(Address->getContext()), Instruction::IndBr, + 0, 0, InsertAtEnd) { + init(Address, NumCases); +} + +IndBrInst::IndBrInst(const IndBrInst &IBI) + : TerminatorInst(Type::getVoidTy(IBI.getContext()), Instruction::IndBr, + allocHungoffUses(IBI.getNumOperands()), + IBI.getNumOperands()) { + Use *OL = OperandList, *InOL = IBI.OperandList; + for (unsigned i = 0, E = IBI.getNumOperands(); i != E; ++i) + OL[i] = InOL[i]; + SubclassOptionalData = IBI.SubclassOptionalData; +} + +IndBrInst::~IndBrInst() { + dropHungoffUses(OperandList); +} + +/// addDestination - Add a destination. +/// +void IndBrInst::addDestination(BasicBlock *DestBB) { + unsigned OpNo = NumOperands; + if (OpNo+1 > ReservedSpace) + resizeOperands(0); // Get more space! + // Initialize some new operands. + assert(OpNo < ReservedSpace && "Growing didn't work!"); + NumOperands = OpNo+1; + OperandList[OpNo] = DestBB; +} + +/// removeDestination - This method removes the specified successor from the +/// indbr instruction. +void IndBrInst::removeDestination(unsigned idx) { + assert(idx < getNumOperands()-1 && "Successor index out of range!"); + + unsigned NumOps = getNumOperands(); + Use *OL = OperandList; + + // Replace this value with the last one. + OL[idx+1] = OL[NumOps-1]; + + // Nuke the last value. + OL[NumOps-1].set(0); + NumOperands = NumOps-1; +} + +BasicBlock *IndBrInst::getSuccessorV(unsigned idx) const { + return getSuccessor(idx); +} +unsigned IndBrInst::getNumSuccessorsV() const { + return getNumSuccessors(); +} +void IndBrInst::setSuccessorV(unsigned idx, BasicBlock *B) { + setSuccessor(idx, B); +} + +//===----------------------------------------------------------------------===// +// clone() implementations +//===----------------------------------------------------------------------===// + // Define these methods here so vtables don't get emitted into every translation // unit that uses these classes. @@ -3410,6 +3522,15 @@ SwitchInst *SwitchInst::clone() const { return New; } +IndBrInst *IndBrInst::clone() const { + IndBrInst *New = new IndBrInst(*this); + New->SubclassOptionalData = SubclassOptionalData; + if (hasMetadata()) + getContext().pImpl->TheMetadata.ValueIsCloned(this, New); + return New; +} + + InvokeInst *InvokeInst::clone() const { InvokeInst *New = new(getNumOperands()) InvokeInst(*this); New->SubclassOptionalData = SubclassOptionalData; diff --git a/test/Feature/terminators.ll b/test/Feature/terminators.ll index 417f56b..d1b9710 100644 --- a/test/Feature/terminators.ll +++ b/test/Feature/terminators.ll @@ -24,3 +24,14 @@ Case4: ; preds = %0 ret i32 16 } + + +define i32 @indbrtest(i8* %P, i32* %Q) { + indbr i8* %P, [label %BB1, label %BB2, label %BB3] +BB1: + indbr i32* %Q, [] +BB2: + indbr i32* %Q, [label %BB1, label %BB2] +BB3: + ret i32 2 +} |