mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-23 02:29:18 +00:00
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
This commit is contained in:
parent
76b39e88e4
commit
f9be95f867
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
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(53)
|
||||
LAST_OTHER_INST(54)
|
||||
|
||||
#undef FIRST_TERM_INST
|
||||
#undef HANDLE_TERM_INST
|
||||
|
@ -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
|
||||
@ -2213,6 +2213,105 @@ struct OperandTraits<SwitchInst> : public HungoffOperandTraits<2> {
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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);}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user