[llvm] [SandboxIR] Implement FuncletPadInst, CatchPadInst and CleanupInst (PR #105294)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 21 16:29:53 PDT 2024
https://github.com/vporpo updated https://github.com/llvm/llvm-project/pull/105294
>From f1479728615f1bbc902ac51e2a0b5dc8b7ed12e7 Mon Sep 17 00:00:00 2001
From: Vasileios Porpodas <vporpodas at google.com>
Date: Wed, 14 Aug 2024 16:45:04 -0700
Subject: [PATCH 1/2] [SandboxIR] Implement FuncletPadInst, CatchPadInst and
CleanupInst
This patch implements sandboxir::FuncletPadInst,CatchInst,CleanupInst
mirroring their llvm:: counterparts.
---
llvm/include/llvm/SandboxIR/SandboxIR.h | 75 ++++++++++++++++
.../llvm/SandboxIR/SandboxIRValues.def | 2 +
llvm/lib/SandboxIR/SandboxIR.cpp | 83 ++++++++++++++++-
llvm/unittests/SandboxIR/SandboxIRTest.cpp | 90 +++++++++++++++++++
4 files changed, 249 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 01ef8013ea42a0..cf08532b5850e3 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -127,6 +127,9 @@ class CallBase;
class CallInst;
class InvokeInst;
class CallBrInst;
+class FuncletPadInst;
+class CatchPadInst;
+class CleanupPadInst;
class GetElementPtrInst;
class CastInst;
class PtrToIntInst;
@@ -256,6 +259,9 @@ class Value {
friend class CallInst; // For getting `Val`.
friend class InvokeInst; // For getting `Val`.
friend class CallBrInst; // For getting `Val`.
+ friend class FuncletPadInst; // For getting `Val`.
+ friend class CatchPadInst; // For getting `Val`.
+ friend class CleanupPadInst; // For getting `Val`.
friend class GetElementPtrInst; // For getting `Val`.
friend class CatchSwitchInst; // For getting `Val`.
friend class SwitchInst; // For getting `Val`.
@@ -679,6 +685,8 @@ class Instruction : public sandboxir::User {
friend class CallInst; // For getTopmostLLVMInstruction().
friend class InvokeInst; // For getTopmostLLVMInstruction().
friend class CallBrInst; // For getTopmostLLVMInstruction().
+ friend class CatchPadInst; // For getTopmostLLVMInstruction().
+ friend class CleanupPadInst; // For getTopmostLLVMInstruction().
friend class GetElementPtrInst; // For getTopmostLLVMInstruction().
friend class CatchSwitchInst; // For getTopmostLLVMInstruction().
friend class SwitchInst; // For getTopmostLLVMInstruction().
@@ -845,6 +853,7 @@ template <typename LLVMT> class SingleLLVMInstructionImpl : public Instruction {
#include "llvm/SandboxIR/SandboxIRValues.def"
friend class UnaryInstruction;
friend class CallBase;
+ friend class FuncletPadInst;
Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
return getOperandUseDefault(OpIdx, Verify);
@@ -1845,6 +1854,68 @@ class CallBrInst final : public CallBase {
}
};
+class FuncletPadInst : public SingleLLVMInstructionImpl<llvm::FuncletPadInst> {
+ FuncletPadInst(ClassID SubclassID, Opcode Opc, llvm::Instruction *I,
+ Context &Ctx)
+ : SingleLLVMInstructionImpl(SubclassID, Opc, I, Ctx) {}
+ friend class CatchPadInst; // For constructor.
+ friend class CleanupPadInst; // For constructor.
+
+public:
+ /// Return the number of funcletpad arguments.
+ unsigned arg_size() const {
+ return cast<llvm::FuncletPadInst>(Val)->arg_size();
+ }
+ /// Return the outer EH-pad this funclet is nested within.
+ ///
+ /// Note: This returns the associated CatchSwitchInst if this FuncletPadInst
+ /// is a CatchPadInst.
+ Value *getParentPad() const;
+ void setParentPad(Value *ParentPad);
+ /// Return the Idx-th funcletpad argument.
+ Value *getArgOperand(unsigned Idx) const;
+ /// Set the Idx-th funcletpad argument.
+ void setArgOperand(unsigned Idx, Value *V);
+
+ // TODO: Implement missing functions: arg_operands().
+ static bool classof(const Value *From) {
+ return From->getSubclassID() == ClassID::CatchPad ||
+ From->getSubclassID() == ClassID::CleanupPad;
+ }
+};
+
+class CatchPadInst : public FuncletPadInst {
+ CatchPadInst(llvm::CatchPadInst *CPI, Context &Ctx)
+ : FuncletPadInst(ClassID::CatchPad, Opcode::CatchPad, CPI, Ctx) {}
+ friend class Context; // For constructor.
+
+public:
+ CatchSwitchInst *getCatchSwitch() const;
+ // TODO: We have not implemented setCatchSwitch() because we can't revert it
+ // for now, as there is no CatchPadInst member function that can undo it.
+
+ static CatchPadInst *create(Value *ParentPad, ArrayRef<Value *> Args,
+ BBIterator WhereIt, BasicBlock *WhereBB,
+ Context &Ctx, const Twine &Name = "");
+ static bool classof(const Value *From) {
+ return From->getSubclassID() == ClassID::CatchPad;
+ }
+};
+
+class CleanupPadInst : public FuncletPadInst {
+ CleanupPadInst(llvm::CleanupPadInst *CPI, Context &Ctx)
+ : FuncletPadInst(ClassID::CleanupPad, Opcode::CleanupPad, CPI, Ctx) {}
+ friend class Context; // For constructor.
+
+public:
+ static CleanupPadInst *create(Value *ParentPad, ArrayRef<Value *> Args,
+ BBIterator WhereIt, BasicBlock *WhereBB,
+ Context &Ctx, const Twine &Name = "");
+ static bool classof(const Value *From) {
+ return From->getSubclassID() == ClassID::CleanupPad;
+ }
+};
+
class GetElementPtrInst final
: public SingleLLVMInstructionImpl<llvm::GetElementPtrInst> {
/// Use Context::createGetElementPtrInst(). Don't call
@@ -2747,6 +2818,10 @@ class Context {
friend InvokeInst; // For createInvokeInst()
CallBrInst *createCallBrInst(llvm::CallBrInst *I);
friend CallBrInst; // For createCallBrInst()
+ CatchPadInst *createCatchPadInst(llvm::CatchPadInst *I);
+ friend CatchPadInst; // For createCatchPadInst()
+ CleanupPadInst *createCleanupPadInst(llvm::CleanupPadInst *I);
+ friend CleanupPadInst; // For createCleanupPadInst()
GetElementPtrInst *createGetElementPtrInst(llvm::GetElementPtrInst *I);
friend GetElementPtrInst; // For createGetElementPtrInst()
CatchSwitchInst *createCatchSwitchInst(llvm::CatchSwitchInst *I);
diff --git a/llvm/include/llvm/SandboxIR/SandboxIRValues.def b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
index 56720f564a7cae..a75f872bc88acb 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIRValues.def
+++ b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
@@ -46,6 +46,8 @@ DEF_INSTR(Ret, OP(Ret), ReturnInst)
DEF_INSTR(Call, OP(Call), CallInst)
DEF_INSTR(Invoke, OP(Invoke), InvokeInst)
DEF_INSTR(CallBr, OP(CallBr), CallBrInst)
+DEF_INSTR(CatchPad, OP(CatchPad), CatchPadInst)
+DEF_INSTR(CleanupPad, OP(CleanupPad), CleanupPadInst)
DEF_INSTR(GetElementPtr, OP(GetElementPtr), GetElementPtrInst)
DEF_INSTR(CatchSwitch, OP(CatchSwitch), CatchSwitchInst)
DEF_INSTR(Switch, OP(Switch), SwitchInst)
diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp
index a62c879b91e8b9..b312712c2ffe84 100644
--- a/llvm/lib/SandboxIR/SandboxIR.cpp
+++ b/llvm/lib/SandboxIR/SandboxIR.cpp
@@ -1043,6 +1043,68 @@ BasicBlock *CallBrInst::getSuccessor(unsigned Idx) const {
Ctx.getValue(cast<llvm::CallBrInst>(Val)->getSuccessor(Idx)));
}
+Value *FuncletPadInst::getParentPad() const {
+ return Ctx.getValue(cast<llvm::FuncletPadInst>(Val)->getParentPad());
+}
+
+void FuncletPadInst::setParentPad(Value *ParentPad) {
+ Ctx.getTracker()
+ .emplaceIfTracking<GenericSetter<&FuncletPadInst::getParentPad,
+ &FuncletPadInst::setParentPad>>(this);
+ cast<llvm::FuncletPadInst>(Val)->setParentPad(ParentPad->Val);
+}
+
+Value *FuncletPadInst::getArgOperand(unsigned Idx) const {
+ return Ctx.getValue(cast<llvm::FuncletPadInst>(Val)->getArgOperand(Idx));
+}
+
+void FuncletPadInst::setArgOperand(unsigned Idx, Value *V) {
+ Ctx.getTracker()
+ .emplaceIfTracking<GenericSetterWithIdx<&FuncletPadInst::getArgOperand,
+ &FuncletPadInst::setArgOperand>>(
+ this, Idx);
+ cast<llvm::FuncletPadInst>(Val)->setArgOperand(Idx, V->Val);
+}
+
+CatchSwitchInst *CatchPadInst::getCatchSwitch() const {
+ return cast<CatchSwitchInst>(
+ Ctx.getValue(cast<llvm::CatchPadInst>(Val)->getCatchSwitch()));
+}
+
+CatchPadInst *CatchPadInst::create(Value *ParentPad, ArrayRef<Value *> Args,
+ BBIterator WhereIt, BasicBlock *WhereBB,
+ Context &Ctx, const Twine &Name) {
+ auto &Builder = Ctx.getLLVMIRBuilder();
+ if (WhereIt != WhereBB->end())
+ Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+ else
+ Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+ SmallVector<llvm::Value *> LLVMArgs;
+ LLVMArgs.reserve(Args.size());
+ for (auto *Arg : Args)
+ LLVMArgs.push_back(Arg->Val);
+ llvm::CatchPadInst *LLVMI =
+ Builder.CreateCatchPad(ParentPad->Val, LLVMArgs, Name);
+ return Ctx.createCatchPadInst(LLVMI);
+}
+
+CleanupPadInst *CleanupPadInst::create(Value *ParentPad, ArrayRef<Value *> Args,
+ BBIterator WhereIt, BasicBlock *WhereBB,
+ Context &Ctx, const Twine &Name) {
+ auto &Builder = Ctx.getLLVMIRBuilder();
+ if (WhereIt != WhereBB->end())
+ Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+ else
+ Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+ SmallVector<llvm::Value *> LLVMArgs;
+ LLVMArgs.reserve(Args.size());
+ for (auto *Arg : Args)
+ LLVMArgs.push_back(Arg->Val);
+ llvm::CleanupPadInst *LLVMI =
+ Builder.CreateCleanupPad(ParentPad->Val, LLVMArgs, Name);
+ return Ctx.createCleanupPadInst(LLVMI);
+}
+
Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
ArrayRef<Value *> IdxList,
BasicBlock::iterator WhereIt,
@@ -2059,6 +2121,18 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
It->second = std::unique_ptr<CallBrInst>(new CallBrInst(LLVMCallBr, *this));
return It->second.get();
}
+ case llvm::Instruction::CatchPad: {
+ auto *LLVMCPI = cast<llvm::CatchPadInst>(LLVMV);
+ It->second =
+ std::unique_ptr<CatchPadInst>(new CatchPadInst(LLVMCPI, *this));
+ return It->second.get();
+ }
+ case llvm::Instruction::CleanupPad: {
+ auto *LLVMCPI = cast<llvm::CleanupPadInst>(LLVMV);
+ It->second =
+ std::unique_ptr<CleanupPadInst>(new CleanupPadInst(LLVMCPI, *this));
+ return It->second.get();
+ }
case llvm::Instruction::GetElementPtr: {
auto *LLVMGEP = cast<llvm::GetElementPtrInst>(LLVMV);
It->second = std::unique_ptr<GetElementPtrInst>(
@@ -2235,7 +2309,14 @@ UnreachableInst *Context::createUnreachableInst(llvm::UnreachableInst *UI) {
std::unique_ptr<UnreachableInst>(new UnreachableInst(UI, *this));
return cast<UnreachableInst>(registerValue(std::move(NewPtr)));
}
-
+CatchPadInst *Context::createCatchPadInst(llvm::CatchPadInst *I) {
+ auto NewPtr = std::unique_ptr<CatchPadInst>(new CatchPadInst(I, *this));
+ return cast<CatchPadInst>(registerValue(std::move(NewPtr)));
+}
+CleanupPadInst *Context::createCleanupPadInst(llvm::CleanupPadInst *I) {
+ auto NewPtr = std::unique_ptr<CleanupPadInst>(new CleanupPadInst(I, *this));
+ return cast<CleanupPadInst>(registerValue(std::move(NewPtr)));
+}
GetElementPtrInst *
Context::createGetElementPtrInst(llvm::GetElementPtrInst *I) {
auto NewPtr =
diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index 94d8ac27be3bc8..be3d537907ef43 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -1870,6 +1870,96 @@ define void @foo(i8 %arg) {
}
}
+TEST_F(SandboxIRTest, FuncletPadInst_CatchPadInst_CleanupPadInst) {
+ parseIR(C, R"IR(
+define void @foo() {
+dispatch:
+ %cs = catchswitch within none [label %handler0] unwind to caller
+handler0:
+ %catchpad = catchpad within %cs [ptr @foo]
+ ret void
+handler1:
+ %cleanuppad = cleanuppad within %cs [ptr @foo]
+ ret void
+bb:
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ BasicBlock *LLVMDispatch = getBasicBlockByName(LLVMF, "dispatch");
+ BasicBlock *LLVMHandler0 = getBasicBlockByName(LLVMF, "handler0");
+ BasicBlock *LLVMHandler1 = getBasicBlockByName(LLVMF, "handler1");
+ auto *LLVMCP = cast<llvm::CatchPadInst>(&*LLVMHandler0->begin());
+ auto *LLVMCLP = cast<llvm::CleanupPadInst>(&*LLVMHandler1->begin());
+
+ sandboxir::Context Ctx(C);
+ [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
+ auto *Dispatch = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMDispatch));
+ auto *Handler0 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMHandler0));
+ auto *Handler1 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMHandler1));
+ auto *BB = cast<sandboxir::BasicBlock>(
+ Ctx.getValue(getBasicBlockByName(LLVMF, "bb")));
+ auto *BBRet = cast<sandboxir::ReturnInst>(&*BB->begin());
+ auto *CS = cast<sandboxir::CatchSwitchInst>(&*Dispatch->begin());
+ [[maybe_unused]] auto *CP =
+ cast<sandboxir::CatchPadInst>(&*Handler0->begin());
+ [[maybe_unused]] auto *CLP =
+ cast<sandboxir::CleanupPadInst>(&*Handler1->begin());
+
+ // Check getCatchSwitch().
+ EXPECT_EQ(CP->getCatchSwitch(), CS);
+ EXPECT_EQ(CP->getCatchSwitch(), Ctx.getValue(LLVMCP->getCatchSwitch()));
+
+ for (llvm::FuncletPadInst *LLVMFPI :
+ {static_cast<llvm::FuncletPadInst *>(LLVMCP),
+ static_cast<llvm::FuncletPadInst *>(LLVMCLP)}) {
+ auto *FPI = cast<sandboxir::FuncletPadInst>(Ctx.getValue(LLVMFPI));
+ // Check arg_size().
+ EXPECT_EQ(FPI->arg_size(), LLVMFPI->arg_size());
+ // Check getParentPad().
+ EXPECT_EQ(FPI->getParentPad(), Ctx.getValue(LLVMFPI->getParentPad()));
+ // Check setParentPad().
+ auto *OrigParentPad = FPI->getParentPad();
+ auto *NewParentPad = Dispatch;
+ EXPECT_NE(NewParentPad, OrigParentPad);
+ FPI->setParentPad(NewParentPad);
+ EXPECT_EQ(FPI->getParentPad(), NewParentPad);
+ FPI->setParentPad(OrigParentPad);
+ EXPECT_EQ(FPI->getParentPad(), OrigParentPad);
+ // Check getArgOperand().
+ for (auto Idx : seq<unsigned>(0, FPI->arg_size()))
+ EXPECT_EQ(FPI->getArgOperand(Idx),
+ Ctx.getValue(LLVMFPI->getArgOperand(Idx)));
+ // Check setArgOperand().
+ auto *OrigArgOperand = FPI->getArgOperand(0);
+ auto *NewArgOperand = Dispatch;
+ EXPECT_NE(NewArgOperand, OrigArgOperand);
+ FPI->setArgOperand(0, NewArgOperand);
+ EXPECT_EQ(FPI->getArgOperand(0), NewArgOperand);
+ FPI->setArgOperand(0, OrigArgOperand);
+ EXPECT_EQ(FPI->getArgOperand(0), OrigArgOperand);
+ }
+ // Check CatchPadInst::create().
+ auto *NewCPI = cast<sandboxir::CatchPadInst>(sandboxir::CatchPadInst::create(
+ CS, {}, BBRet->getIterator(), BB, Ctx, "NewCPI"));
+ EXPECT_EQ(NewCPI->getCatchSwitch(), CS);
+ EXPECT_EQ(NewCPI->arg_size(), 0u);
+ EXPECT_EQ(NewCPI->getNextNode(), BBRet);
+#ifndef NDEBUG
+ EXPECT_EQ(NewCPI->getName(), "NewCPI");
+#endif // NDEBUG
+ // Check CleanupPadInst::create().
+ auto *NewCLPI =
+ cast<sandboxir::CleanupPadInst>(sandboxir::CleanupPadInst::create(
+ CS, {}, BBRet->getIterator(), BB, Ctx, "NewCLPI"));
+ EXPECT_EQ(NewCLPI->getParentPad(), CS);
+ EXPECT_EQ(NewCLPI->arg_size(), 0u);
+ EXPECT_EQ(NewCLPI->getNextNode(), BBRet);
+#ifndef NDEBUG
+ EXPECT_EQ(NewCLPI->getName(), "NewCLPI");
+#endif // NDEBUG
+}
+
TEST_F(SandboxIRTest, GetElementPtrInstruction) {
parseIR(C, R"IR(
define void @foo(ptr %ptr, <2 x ptr> %ptrs) {
>From 023d53a00f31f91967c7e8a37c0527d0c736ead5 Mon Sep 17 00:00:00 2001
From: Vasileios Porpodas <vporpodas at google.com>
Date: Wed, 21 Aug 2024 16:29:19 -0700
Subject: [PATCH 2/2] fixup! [SandboxIR] Implement FuncletPadInst, CatchPadInst
and CleanupInst
---
llvm/unittests/SandboxIR/TrackerTest.cpp | 51 ++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/llvm/unittests/SandboxIR/TrackerTest.cpp b/llvm/unittests/SandboxIR/TrackerTest.cpp
index 9f502375204024..e41e8065e0d98c 100644
--- a/llvm/unittests/SandboxIR/TrackerTest.cpp
+++ b/llvm/unittests/SandboxIR/TrackerTest.cpp
@@ -1007,6 +1007,57 @@ define void @foo(i8 %arg) {
EXPECT_EQ(CallBr->getIndirectDest(0), OrigIndirectDest);
}
+TEST_F(TrackerTest, FuncletPadInstSetters) {
+ parseIR(C, R"IR(
+define void @foo() {
+dispatch:
+ %cs = catchswitch within none [label %handler0] unwind to caller
+handler0:
+ %catchpad = catchpad within %cs [ptr @foo]
+ ret void
+handler1:
+ %cleanuppad = cleanuppad within %cs [ptr @foo]
+ ret void
+bb:
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
+ auto *Dispatch = cast<sandboxir::BasicBlock>(
+ Ctx.getValue(getBasicBlockByName(LLVMF, "dispatch")));
+ auto *Handler0 = cast<sandboxir::BasicBlock>(
+ Ctx.getValue(getBasicBlockByName(LLVMF, "handler0")));
+ auto *Handler1 = cast<sandboxir::BasicBlock>(
+ Ctx.getValue(getBasicBlockByName(LLVMF, "handler1")));
+ auto *CP = cast<sandboxir::CatchPadInst>(&*Handler0->begin());
+ auto *CLP = cast<sandboxir::CleanupPadInst>(&*Handler1->begin());
+
+ for (auto *FPI : {static_cast<sandboxir::FuncletPadInst *>(CP),
+ static_cast<sandboxir::FuncletPadInst *>(CLP)}) {
+ // Check setParentPad().
+ auto *OrigParentPad = FPI->getParentPad();
+ auto *NewParentPad = Dispatch;
+ EXPECT_NE(NewParentPad, OrigParentPad);
+ Ctx.save();
+ FPI->setParentPad(NewParentPad);
+ EXPECT_EQ(FPI->getParentPad(), NewParentPad);
+ Ctx.revert();
+ EXPECT_EQ(FPI->getParentPad(), OrigParentPad);
+
+ // Check setArgOperand().
+ auto *OrigArgOperand = FPI->getArgOperand(0);
+ auto *NewArgOperand = Dispatch;
+ EXPECT_NE(NewArgOperand, OrigArgOperand);
+ Ctx.save();
+ FPI->setArgOperand(0, NewArgOperand);
+ EXPECT_EQ(FPI->getArgOperand(0), NewArgOperand);
+ Ctx.revert();
+ EXPECT_EQ(FPI->getArgOperand(0), OrigArgOperand);
+ }
+}
+
TEST_F(TrackerTest, PHINodeSetters) {
parseIR(C, R"IR(
define void @foo(i8 %arg0, i8 %arg1, i8 %arg2) {
More information about the llvm-commits
mailing list