Skip to content

Commit db2aa50

Browse files
authored
[SandboxIR] Implement InvokeInst (#100796)
This patch implements sandboxir::InvokeInst which mirrors llvm::InvokeInst.
1 parent d41f565 commit db2aa50

File tree

4 files changed

+306
-4
lines changed

4 files changed

+306
-4
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
// |
3131
// +- CastInst
3232
// |
33-
// +- CallBase ----- CallInst
34-
// |
35-
// +- CmpInst
33+
// +- CallBase ------+- CallInst
34+
// | |
35+
// +- CmpInst +- InvokeInst
3636
// |
3737
// +- ExtractElementInst
3838
// |
@@ -91,6 +91,7 @@ class User;
9191
class Value;
9292
class CallBase;
9393
class CallInst;
94+
class InvokeInst;
9495

9596
/// Iterator for the `Use` edges of a User's operands.
9697
/// \Returns the operand `Use` when dereferenced.
@@ -204,6 +205,7 @@ class Value {
204205
friend class ReturnInst; // For getting `Val`.
205206
friend class CallBase; // For getting `Val`.
206207
friend class CallInst; // For getting `Val`.
208+
friend class InvokeInst; // For getting `Val`.
207209

208210
/// All values point to the context.
209211
Context &Ctx;
@@ -542,6 +544,7 @@ class Instruction : public sandboxir::User {
542544
friend class StoreInst; // For getTopmostLLVMInstruction().
543545
friend class ReturnInst; // For getTopmostLLVMInstruction().
544546
friend class CallInst; // For getTopmostLLVMInstruction().
547+
friend class InvokeInst; // For getTopmostLLVMInstruction().
545548

546549
/// \Returns the LLVM IR Instructions that this SandboxIR maps to in program
547550
/// order.
@@ -865,7 +868,8 @@ class ReturnInst final : public Instruction {
865868
class CallBase : public Instruction {
866869
CallBase(ClassID ID, Opcode Opc, llvm::Instruction *I, Context &Ctx)
867870
: Instruction(ID, Opc, I, Ctx) {}
868-
friend class CallInst; // For constructor.
871+
friend class CallInst; // For constructor.
872+
friend class InvokeInst; // For constructor.
869873

870874
public:
871875
static bool classof(const Value *From) {
@@ -1033,6 +1037,70 @@ class CallInst final : public CallBase {
10331037
#endif
10341038
};
10351039

1040+
class InvokeInst final : public CallBase {
1041+
/// Use Context::createInvokeInst(). Don't call the
1042+
/// constructor directly.
1043+
InvokeInst(llvm::Instruction *I, Context &Ctx)
1044+
: CallBase(ClassID::Invoke, Opcode::Invoke, I, Ctx) {}
1045+
friend class Context; // For accessing the constructor in
1046+
// create*()
1047+
Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
1048+
return getOperandUseDefault(OpIdx, Verify);
1049+
}
1050+
SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
1051+
return {cast<llvm::Instruction>(Val)};
1052+
}
1053+
1054+
public:
1055+
static InvokeInst *create(FunctionType *FTy, Value *Func,
1056+
BasicBlock *IfNormal, BasicBlock *IfException,
1057+
ArrayRef<Value *> Args, BBIterator WhereIt,
1058+
BasicBlock *WhereBB, Context &Ctx,
1059+
const Twine &NameStr = "");
1060+
static InvokeInst *create(FunctionType *FTy, Value *Func,
1061+
BasicBlock *IfNormal, BasicBlock *IfException,
1062+
ArrayRef<Value *> Args, Instruction *InsertBefore,
1063+
Context &Ctx, const Twine &NameStr = "");
1064+
static InvokeInst *create(FunctionType *FTy, Value *Func,
1065+
BasicBlock *IfNormal, BasicBlock *IfException,
1066+
ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
1067+
Context &Ctx, const Twine &NameStr = "");
1068+
1069+
static bool classof(const Value *From) {
1070+
return From->getSubclassID() == ClassID::Invoke;
1071+
}
1072+
unsigned getUseOperandNo(const Use &Use) const final {
1073+
return getUseOperandNoDefault(Use);
1074+
}
1075+
unsigned getNumOfIRInstrs() const final { return 1u; }
1076+
BasicBlock *getNormalDest() const;
1077+
BasicBlock *getUnwindDest() const;
1078+
void setNormalDest(BasicBlock *BB);
1079+
void setUnwindDest(BasicBlock *BB);
1080+
// TODO: Return a `LandingPadInst` once implemented.
1081+
Instruction *getLandingPadInst() const;
1082+
BasicBlock *getSuccessor(unsigned SuccIdx) const;
1083+
void setSuccessor(unsigned SuccIdx, BasicBlock *NewSucc) {
1084+
assert(SuccIdx < 2 && "Successor # out of range for invoke!");
1085+
if (SuccIdx == 0)
1086+
setNormalDest(NewSucc);
1087+
else
1088+
setUnwindDest(NewSucc);
1089+
}
1090+
unsigned getNumSuccessors() const {
1091+
return cast<llvm::InvokeInst>(Val)->getNumSuccessors();
1092+
}
1093+
#ifndef NDEBUG
1094+
void verify() const final {}
1095+
friend raw_ostream &operator<<(raw_ostream &OS, const InvokeInst &I) {
1096+
I.dump(OS);
1097+
return OS;
1098+
}
1099+
void dump(raw_ostream &OS) const override;
1100+
LLVM_DUMP_METHOD void dump() const override;
1101+
#endif
1102+
};
1103+
10361104
/// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to
10371105
/// an OpaqueInstr.
10381106
class OpaqueInst : public sandboxir::Instruction {
@@ -1183,6 +1251,8 @@ class Context {
11831251
friend ReturnInst; // For createReturnInst()
11841252
CallInst *createCallInst(llvm::CallInst *I);
11851253
friend CallInst; // For createCallInst()
1254+
InvokeInst *createInvokeInst(llvm::InvokeInst *I);
1255+
friend InvokeInst; // For createInvokeInst()
11861256

11871257
public:
11881258
Context(LLVMContext &LLVMCtx)

llvm/lib/SandboxIR/SandboxIR.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,81 @@ void CallInst::dump() const {
809809
dump(dbgs());
810810
dbgs() << "\n";
811811
}
812+
#endif // NDEBUG
813+
814+
InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
815+
BasicBlock *IfNormal, BasicBlock *IfException,
816+
ArrayRef<Value *> Args, BBIterator WhereIt,
817+
BasicBlock *WhereBB, Context &Ctx,
818+
const Twine &NameStr) {
819+
auto &Builder = Ctx.getLLVMIRBuilder();
820+
if (WhereIt != WhereBB->end())
821+
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
822+
else
823+
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
824+
SmallVector<llvm::Value *> LLVMArgs;
825+
LLVMArgs.reserve(Args.size());
826+
for (Value *Arg : Args)
827+
LLVMArgs.push_back(Arg->Val);
828+
llvm::InvokeInst *Invoke = Builder.CreateInvoke(
829+
FTy, Func->Val, cast<llvm::BasicBlock>(IfNormal->Val),
830+
cast<llvm::BasicBlock>(IfException->Val), LLVMArgs, NameStr);
831+
return Ctx.createInvokeInst(Invoke);
832+
}
833+
834+
InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
835+
BasicBlock *IfNormal, BasicBlock *IfException,
836+
ArrayRef<Value *> Args,
837+
Instruction *InsertBefore, Context &Ctx,
838+
const Twine &NameStr) {
839+
return create(FTy, Func, IfNormal, IfException, Args,
840+
InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
841+
NameStr);
842+
}
843+
844+
InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
845+
BasicBlock *IfNormal, BasicBlock *IfException,
846+
ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
847+
Context &Ctx, const Twine &NameStr) {
848+
return create(FTy, Func, IfNormal, IfException, Args, InsertAtEnd->end(),
849+
InsertAtEnd, Ctx, NameStr);
850+
}
851+
852+
BasicBlock *InvokeInst::getNormalDest() const {
853+
return cast<BasicBlock>(
854+
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getNormalDest()));
855+
}
856+
BasicBlock *InvokeInst::getUnwindDest() const {
857+
return cast<BasicBlock>(
858+
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getUnwindDest()));
859+
}
860+
void InvokeInst::setNormalDest(BasicBlock *BB) {
861+
setOperand(1, BB);
862+
assert(getNormalDest() == BB && "LLVM IR uses a different operan index!");
863+
}
864+
void InvokeInst::setUnwindDest(BasicBlock *BB) {
865+
setOperand(2, BB);
866+
assert(getUnwindDest() == BB && "LLVM IR uses a different operan index!");
867+
}
868+
Instruction *InvokeInst::getLandingPadInst() const {
869+
return cast<Instruction>(
870+
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getLandingPadInst()));
871+
;
872+
}
873+
BasicBlock *InvokeInst::getSuccessor(unsigned SuccIdx) const {
874+
return cast<BasicBlock>(
875+
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getSuccessor(SuccIdx)));
876+
}
877+
878+
#ifndef NDEBUG
879+
void InvokeInst::dump(raw_ostream &OS) const {
880+
dumpCommonPrefix(OS);
881+
dumpCommonSuffix(OS);
882+
}
883+
void InvokeInst::dump() const {
884+
dump(dbgs());
885+
dbgs() << "\n";
886+
}
812887

813888
void OpaqueInst::dump(raw_ostream &OS) const {
814889
dumpCommonPrefix(OS);
@@ -968,6 +1043,11 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
9681043
It->second = std::unique_ptr<CallInst>(new CallInst(LLVMCall, *this));
9691044
return It->second.get();
9701045
}
1046+
case llvm::Instruction::Invoke: {
1047+
auto *LLVMInvoke = cast<llvm::InvokeInst>(LLVMV);
1048+
It->second = std::unique_ptr<InvokeInst>(new InvokeInst(LLVMInvoke, *this));
1049+
return It->second.get();
1050+
}
9711051
default:
9721052
break;
9731053
}
@@ -1016,6 +1096,11 @@ CallInst *Context::createCallInst(llvm::CallInst *I) {
10161096
return cast<CallInst>(registerValue(std::move(NewPtr)));
10171097
}
10181098

1099+
InvokeInst *Context::createInvokeInst(llvm::InvokeInst *I) {
1100+
auto NewPtr = std::unique_ptr<InvokeInst>(new InvokeInst(I, *this));
1101+
return cast<InvokeInst>(registerValue(std::move(NewPtr)));
1102+
}
1103+
10191104
Value *Context::getValue(llvm::Value *V) const {
10201105
auto It = LLVMValueToValueMap.find(V);
10211106
if (It != LLVMValueToValueMap.end())

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,3 +1042,94 @@ define i8 @foo(i8 %arg) {
10421042
EXPECT_EQ(Call->getArgOperand(0), Arg0);
10431043
}
10441044
}
1045+
1046+
TEST_F(SandboxIRTest, InvokeInst) {
1047+
parseIR(C, R"IR(
1048+
define void @foo(i8 %arg) {
1049+
bb0:
1050+
invoke i8 @foo(i8 %arg) to label %normal_bb
1051+
unwind label %exception_bb
1052+
normal_bb:
1053+
ret void
1054+
exception_bb:
1055+
%lpad = landingpad { ptr, i32}
1056+
cleanup
1057+
ret void
1058+
other_bb:
1059+
ret void
1060+
}
1061+
)IR");
1062+
Function &LLVMF = *M->getFunction("foo");
1063+
sandboxir::Context Ctx(C);
1064+
auto &F = *Ctx.createFunction(&LLVMF);
1065+
auto *Arg = F.getArg(0);
1066+
auto *BB0 = cast<sandboxir::BasicBlock>(
1067+
Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
1068+
auto *NormalBB = cast<sandboxir::BasicBlock>(
1069+
Ctx.getValue(getBasicBlockByName(LLVMF, "normal_bb")));
1070+
auto *ExceptionBB = cast<sandboxir::BasicBlock>(
1071+
Ctx.getValue(getBasicBlockByName(LLVMF, "exception_bb")));
1072+
auto *LandingPad = &*ExceptionBB->begin();
1073+
auto *OtherBB = cast<sandboxir::BasicBlock>(
1074+
Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb")));
1075+
auto It = BB0->begin();
1076+
// Check classof(Instruction *).
1077+
auto *Invoke = cast<sandboxir::InvokeInst>(&*It++);
1078+
1079+
// Check getNormalDest().
1080+
EXPECT_EQ(Invoke->getNormalDest(), NormalBB);
1081+
// Check getUnwindDest().
1082+
EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB);
1083+
// Check getSuccessor().
1084+
EXPECT_EQ(Invoke->getSuccessor(0), NormalBB);
1085+
EXPECT_EQ(Invoke->getSuccessor(1), ExceptionBB);
1086+
// Check setNormalDest().
1087+
Invoke->setNormalDest(OtherBB);
1088+
EXPECT_EQ(Invoke->getNormalDest(), OtherBB);
1089+
EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB);
1090+
// Check setUnwindDest().
1091+
Invoke->setUnwindDest(OtherBB);
1092+
EXPECT_EQ(Invoke->getNormalDest(), OtherBB);
1093+
EXPECT_EQ(Invoke->getUnwindDest(), OtherBB);
1094+
// Check setSuccessor().
1095+
Invoke->setSuccessor(0, NormalBB);
1096+
EXPECT_EQ(Invoke->getNormalDest(), NormalBB);
1097+
Invoke->setSuccessor(1, ExceptionBB);
1098+
EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB);
1099+
// Check getLandingPadInst().
1100+
EXPECT_EQ(Invoke->getLandingPadInst(), LandingPad);
1101+
1102+
{
1103+
// Check create() WhereIt, WhereBB.
1104+
SmallVector<sandboxir::Value *> Args({Arg});
1105+
auto *InsertBefore = &*BB0->begin();
1106+
auto *NewInvoke = cast<sandboxir::InvokeInst>(sandboxir::InvokeInst::create(
1107+
F.getFunctionType(), &F, NormalBB, ExceptionBB, Args,
1108+
/*WhereIt=*/InsertBefore->getIterator(), /*WhereBB=*/BB0, Ctx));
1109+
EXPECT_EQ(NewInvoke->getNormalDest(), NormalBB);
1110+
EXPECT_EQ(NewInvoke->getUnwindDest(), ExceptionBB);
1111+
EXPECT_EQ(NewInvoke->getNextNode(), InsertBefore);
1112+
}
1113+
{
1114+
// Check create() InsertBefore.
1115+
SmallVector<sandboxir::Value *> Args({Arg});
1116+
auto *InsertBefore = &*BB0->begin();
1117+
auto *NewInvoke = cast<sandboxir::InvokeInst>(
1118+
sandboxir::InvokeInst::create(F.getFunctionType(), &F, NormalBB,
1119+
ExceptionBB, Args, InsertBefore, Ctx));
1120+
EXPECT_EQ(NewInvoke->getNormalDest(), NormalBB);
1121+
EXPECT_EQ(NewInvoke->getUnwindDest(), ExceptionBB);
1122+
EXPECT_EQ(NewInvoke->getNextNode(), InsertBefore);
1123+
}
1124+
{
1125+
// Check create() InsertAtEnd.
1126+
SmallVector<sandboxir::Value *> Args({Arg});
1127+
auto *NewInvoke = cast<sandboxir::InvokeInst>(sandboxir::InvokeInst::create(
1128+
F.getFunctionType(), &F, NormalBB, ExceptionBB, Args,
1129+
/*InsertAtEnd=*/BB0, Ctx));
1130+
EXPECT_EQ(NewInvoke->getNormalDest(), NormalBB);
1131+
EXPECT_EQ(NewInvoke->getUnwindDest(), ExceptionBB);
1132+
EXPECT_EQ(NewInvoke->getParent(), BB0);
1133+
EXPECT_EQ(NewInvoke->getNextNode(), nullptr);
1134+
}
1135+
}

llvm/unittests/SandboxIR/TrackerTest.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,59 @@ define void @foo(i8 %arg0, i8 %arg1) {
488488
Ctx.revert();
489489
EXPECT_EQ(Call->getCalledFunction(), Bar1F);
490490
}
491+
492+
TEST_F(TrackerTest, InvokeSetters) {
493+
parseIR(C, R"IR(
494+
define void @foo(i8 %arg) {
495+
bb0:
496+
invoke i8 @foo(i8 %arg) to label %normal_bb
497+
unwind label %exception_bb
498+
normal_bb:
499+
ret void
500+
exception_bb:
501+
ret void
502+
other_bb:
503+
ret void
504+
}
505+
)IR");
506+
Function &LLVMF = *M->getFunction("foo");
507+
sandboxir::Context Ctx(C);
508+
[[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
509+
auto *BB0 = cast<sandboxir::BasicBlock>(
510+
Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
511+
auto *NormalBB = cast<sandboxir::BasicBlock>(
512+
Ctx.getValue(getBasicBlockByName(LLVMF, "normal_bb")));
513+
auto *ExceptionBB = cast<sandboxir::BasicBlock>(
514+
Ctx.getValue(getBasicBlockByName(LLVMF, "exception_bb")));
515+
auto *OtherBB = cast<sandboxir::BasicBlock>(
516+
Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb")));
517+
auto It = BB0->begin();
518+
auto *Invoke = cast<sandboxir::InvokeInst>(&*It++);
519+
520+
// Check setNormalDest().
521+
Ctx.save();
522+
Invoke->setNormalDest(OtherBB);
523+
EXPECT_EQ(Invoke->getNormalDest(), OtherBB);
524+
Ctx.revert();
525+
EXPECT_EQ(Invoke->getNormalDest(), NormalBB);
526+
527+
// Check setUnwindDest().
528+
Ctx.save();
529+
Invoke->setUnwindDest(OtherBB);
530+
EXPECT_EQ(Invoke->getUnwindDest(), OtherBB);
531+
Ctx.revert();
532+
EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB);
533+
534+
// Check setSuccessor().
535+
Ctx.save();
536+
Invoke->setSuccessor(0, OtherBB);
537+
EXPECT_EQ(Invoke->getSuccessor(0), OtherBB);
538+
Ctx.revert();
539+
EXPECT_EQ(Invoke->getSuccessor(0), NormalBB);
540+
541+
Ctx.save();
542+
Invoke->setSuccessor(1, OtherBB);
543+
EXPECT_EQ(Invoke->getSuccessor(1), OtherBB);
544+
Ctx.revert();
545+
EXPECT_EQ(Invoke->getSuccessor(1), ExceptionBB);
546+
}

0 commit comments

Comments
 (0)