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 /lib | |
parent | 76b39e88e470171292850d8cebc5d54227b43883 (diff) |
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
Diffstat (limited to 'lib')
-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 |
11 files changed, 256 insertions, 38 deletions
diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 4fb7ea9e29..1003907974 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 fa803bb1e9..cf16e42b6a 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 b6877bc7c1..37473a0a19 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 f5072fe52f..a25b6f08c0 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 b392122b77..41803c0eb4 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 aee825ce52..c0f97c1968 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 b220d55f54..73c9c5f57e 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 74705514de..9aca707ecf 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 59ee3757a3..5a92432062 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 def7b3b4ac..4e8922230d 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 02d5af0120..61b8044ead 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; |