Skip to content

Commit d5f5dc9

Browse files
authored
[SandboxIR] More boilerplate: Function, Argument, Constant, Instruction, OpaqueInst (#97343)
A very basic implementation of sandboxir:: `Fuction` `Argument` `Constant` `Instruction` `OpaqueInst`
1 parent edbc0e3 commit d5f5dc9

File tree

4 files changed

+331
-4
lines changed

4 files changed

+331
-4
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#ifndef LLVM_TRANSFORMS_SANDBOXIR_SANDBOXIR_H
5959
#define LLVM_TRANSFORMS_SANDBOXIR_SANDBOXIR_H
6060

61+
#include "llvm/IR/Function.h"
6162
#include "llvm/IR/User.h"
6263
#include "llvm/IR/Value.h"
6364
#include "llvm/Support/raw_ostream.h"
@@ -129,6 +130,35 @@ class Value {
129130
void dumpCommonPrefix(raw_ostream &OS) const;
130131
void dumpCommonSuffix(raw_ostream &OS) const;
131132
void printAsOperandCommon(raw_ostream &OS) const;
133+
friend raw_ostream &operator<<(raw_ostream &OS, const sandboxir::Value &V) {
134+
V.dump(OS);
135+
return OS;
136+
}
137+
virtual void dump(raw_ostream &OS) const = 0;
138+
LLVM_DUMP_METHOD virtual void dump() const = 0;
139+
#endif
140+
};
141+
142+
/// Argument of a sandboxir::Function.
143+
class Argument : public sandboxir::Value {
144+
public:
145+
Argument(llvm::Argument *Arg, sandboxir::Context &Ctx)
146+
: sandboxir::Value(ClassID::Argument, Arg, Ctx) {}
147+
static bool classof(const sandboxir::Value *From) {
148+
return From->getSubclassID() == ClassID::Argument;
149+
}
150+
#ifndef NDEBUG
151+
void verify() const final {
152+
assert(isa<llvm::Argument>(Val) && "Expected Argument!");
153+
}
154+
friend raw_ostream &operator<<(raw_ostream &OS,
155+
const sandboxir::Argument &TArg) {
156+
TArg.dump(OS);
157+
return OS;
158+
}
159+
void printAsOperand(raw_ostream &OS) const;
160+
void dump(raw_ostream &OS) const final;
161+
LLVM_DUMP_METHOD void dump() const final;
132162
#endif
133163
};
134164

@@ -142,16 +172,136 @@ class User : public Value {
142172
assert(isa<llvm::User>(Val) && "Expected User!");
143173
}
144174
void dumpCommonHeader(raw_ostream &OS) const final;
175+
void dump(raw_ostream &OS) const override {
176+
// TODO: Remove this tmp implementation once we get the Instruction classes.
177+
}
178+
LLVM_DUMP_METHOD void dump() const override {
179+
// TODO: Remove this tmp implementation once we get the Instruction classes.
180+
}
181+
#endif
182+
};
183+
184+
class Constant : public sandboxir::User {
185+
public:
186+
Constant(llvm::Constant *C, sandboxir::Context &SBCtx)
187+
: sandboxir::User(ClassID::Constant, C, SBCtx) {}
188+
/// For isa/dyn_cast.
189+
static bool classof(const sandboxir::Value *From) {
190+
return From->getSubclassID() == ClassID::Constant ||
191+
From->getSubclassID() == ClassID::Function;
192+
}
193+
sandboxir::Context &getParent() const { return getContext(); }
194+
#ifndef NDEBUG
195+
void verify() const final {
196+
assert(isa<llvm::Constant>(Val) && "Expected Constant!");
197+
}
198+
friend raw_ostream &operator<<(raw_ostream &OS,
199+
const sandboxir::Constant &SBC) {
200+
SBC.dump(OS);
201+
return OS;
202+
}
203+
void dump(raw_ostream &OS) const override;
204+
LLVM_DUMP_METHOD void dump() const override;
205+
#endif
206+
};
207+
208+
/// A sandboxir::User with operands and opcode.
209+
class Instruction : public sandboxir::User {
210+
public:
211+
enum class Opcode {
212+
#define DEF_VALUE(ID, CLASS)
213+
#define DEF_USER(ID, CLASS)
214+
#define OP(OPC) OPC,
215+
#define DEF_INSTR(ID, OPC, CLASS) OPC
216+
#include "llvm/SandboxIR/SandboxIRValues.def"
217+
};
218+
219+
Instruction(ClassID ID, Opcode Opc, llvm::Instruction *I,
220+
sandboxir::Context &SBCtx)
221+
: sandboxir::User(ID, I, SBCtx), Opc(Opc) {}
222+
223+
protected:
224+
Opcode Opc;
225+
226+
public:
227+
static const char *getOpcodeName(Opcode Opc);
228+
#ifndef NDEBUG
229+
friend raw_ostream &operator<<(raw_ostream &OS, Opcode Opc) {
230+
OS << getOpcodeName(Opc);
231+
return OS;
232+
}
233+
#endif
234+
/// For isa/dyn_cast.
235+
static bool classof(const sandboxir::Value *From);
236+
237+
#ifndef NDEBUG
238+
friend raw_ostream &operator<<(raw_ostream &OS,
239+
const sandboxir::Instruction &SBI) {
240+
SBI.dump(OS);
241+
return OS;
242+
}
243+
void dump(raw_ostream &OS) const override;
244+
LLVM_DUMP_METHOD void dump() const override;
245+
#endif
246+
};
247+
248+
/// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to
249+
/// an OpaqueInstr.
250+
class OpaqueInst : public sandboxir::Instruction {
251+
public:
252+
OpaqueInst(llvm::Instruction *I, sandboxir::Context &Ctx)
253+
: sandboxir::Instruction(ClassID::Opaque, Opcode::Opaque, I, Ctx) {}
254+
OpaqueInst(ClassID SubclassID, llvm::Instruction *I, sandboxir::Context &Ctx)
255+
: sandboxir::Instruction(SubclassID, Opcode::Opaque, I, Ctx) {}
256+
static bool classof(const sandboxir::Value *From) {
257+
return From->getSubclassID() == ClassID::Opaque;
258+
}
259+
#ifndef NDEBUG
260+
void verify() const final {
261+
// Nothing to do
262+
}
263+
friend raw_ostream &operator<<(raw_ostream &OS,
264+
const sandboxir::OpaqueInst &OI) {
265+
OI.dump(OS);
266+
return OS;
267+
}
268+
void dump(raw_ostream &OS) const override;
269+
LLVM_DUMP_METHOD void dump() const override;
145270
#endif
146271
};
147272

148273
class Context {
149274
protected:
150275
LLVMContext &LLVMCtx;
276+
/// Maps LLVM Value to the corresponding sandboxir::Value. Owns all
277+
/// SandboxIR objects.
278+
DenseMap<llvm::Value *, std::unique_ptr<sandboxir::Value>>
279+
LLVMValueToValueMap;
151280

152281
public:
153282
Context(LLVMContext &LLVMCtx) : LLVMCtx(LLVMCtx) {}
283+
sandboxir::Value *getValue(llvm::Value *V) const;
284+
};
285+
286+
class Function : public sandboxir::Value {
287+
public:
288+
Function(llvm::Function *F, sandboxir::Context &Ctx)
289+
: sandboxir::Value(ClassID::Function, F, Ctx) {}
290+
/// For isa/dyn_cast.
291+
static bool classof(const sandboxir::Value *From) {
292+
return From->getSubclassID() == ClassID::Function;
293+
}
294+
295+
#ifndef NDEBUG
296+
void verify() const final {
297+
assert(isa<llvm::Function>(Val) && "Expected Function!");
298+
}
299+
void dumpNameAndArgs(raw_ostream &OS) const;
300+
void dump(raw_ostream &OS) const final;
301+
LLVM_DUMP_METHOD void dump() const final;
302+
#endif
154303
};
304+
155305
} // namespace sandboxir
156306
} // namespace llvm
157307

llvm/include/llvm/SandboxIR/SandboxIRValues.def

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,23 @@
77
//===----------------------------------------------------------------------===//
88

99
// ClassID, Class
10-
DEF_USER(User, sandboxir::User)
10+
#ifndef DEF_VALUE
11+
#define DEF_VALUE(ID, CLASS)
12+
#endif
13+
DEF_VALUE(Function, Function)
14+
DEF_VALUE(Argument, Argument)
15+
16+
#ifndef DEF_USER
17+
#define DEF_USER(ID, CLASS)
18+
#endif
19+
DEF_USER(User, User)
20+
DEF_USER(Constant, Constant)
21+
22+
#ifndef DEF_INSTR
23+
#define DEF_INSTR(ID, OPCODE, CLASS)
24+
#endif
25+
// ClassID, Opcode(s), Class
26+
DEF_INSTR(Opaque, OP(Opaque), OpaqueInst)
1127

1228
#ifdef DEF_VALUE
1329
#undef DEF_VALUE
@@ -18,9 +34,6 @@ DEF_USER(User, sandboxir::User)
1834
#ifdef DEF_INSTR
1935
#undef DEF_INSTR
2036
#endif
21-
#ifdef OPCODES
22-
#undef OPCODES
23-
#endif
2437
#ifdef OP
2538
#undef OP
2639
#endif

llvm/lib/SandboxIR/SandboxIR.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,122 @@ void Value::printAsOperandCommon(raw_ostream &OS) const {
5858
OS << "NULL ";
5959
}
6060

61+
void Argument::printAsOperand(raw_ostream &OS) const {
62+
printAsOperandCommon(OS);
63+
}
64+
void Argument::dump(raw_ostream &OS) const {
65+
dumpCommonPrefix(OS);
66+
dumpCommonSuffix(OS);
67+
}
68+
void Argument::dump() const {
69+
dump(dbgs());
70+
dbgs() << "\n";
71+
}
72+
#endif // NDEBUG
73+
74+
bool User::classof(const Value *From) {
75+
switch (From->getSubclassID()) {
76+
#define DEF_VALUE(ID, CLASS)
77+
#define DEF_USER(ID, CLASS) \
78+
case ClassID::ID: \
79+
return true;
80+
#define DEF_INSTR(ID, OPC, CLASS) \
81+
case ClassID::ID: \
82+
return true;
83+
#include "llvm/SandboxIR/SandboxIRValues.def"
84+
default:
85+
return false;
86+
}
87+
}
88+
89+
#ifndef NDEBUG
6190
void User::dumpCommonHeader(raw_ostream &OS) const {
6291
Value::dumpCommonHeader(OS);
6392
// TODO: This is incomplete
6493
}
6594
#endif // NDEBUG
95+
96+
const char *Instruction::getOpcodeName(Opcode Opc) {
97+
switch (Opc) {
98+
#define DEF_VALUE(ID, CLASS)
99+
#define DEF_USER(ID, CLASS)
100+
#define OP(OPC) \
101+
case Opcode::OPC: \
102+
return #OPC;
103+
#define DEF_INSTR(ID, OPC, CLASS) OPC
104+
#include "llvm/SandboxIR/SandboxIRValues.def"
105+
}
106+
}
107+
108+
bool Instruction::classof(const sandboxir::Value *From) {
109+
switch (From->getSubclassID()) {
110+
#define DEF_INSTR(ID, OPC, CLASS) \
111+
case ClassID::ID: \
112+
return true;
113+
#include "llvm/SandboxIR/SandboxIRValues.def"
114+
default:
115+
return false;
116+
}
117+
}
118+
119+
#ifndef NDEBUG
120+
void Instruction::dump(raw_ostream &OS) const {
121+
OS << "Unimplemented! Please override dump().";
122+
}
123+
void Instruction::dump() const {
124+
dump(dbgs());
125+
dbgs() << "\n";
126+
}
127+
128+
void OpaqueInst::dump(raw_ostream &OS) const {
129+
dumpCommonPrefix(OS);
130+
dumpCommonSuffix(OS);
131+
}
132+
133+
void OpaqueInst::dump() const {
134+
dump(dbgs());
135+
dbgs() << "\n";
136+
}
137+
138+
void Constant::dump(raw_ostream &OS) const {
139+
dumpCommonPrefix(OS);
140+
dumpCommonSuffix(OS);
141+
}
142+
143+
void Constant::dump() const {
144+
dump(dbgs());
145+
dbgs() << "\n";
146+
}
147+
148+
void Function::dumpNameAndArgs(raw_ostream &OS) const {
149+
auto *F = cast<llvm::Function>(Val);
150+
OS << *getType() << " @" << F->getName() << "(";
151+
auto NumArgs = F->arg_size();
152+
for (auto [Idx, Arg] : enumerate(F->args())) {
153+
auto *SBArg = cast_or_null<Argument>(Ctx.getValue(&Arg));
154+
if (SBArg == nullptr)
155+
OS << "NULL";
156+
else
157+
SBArg->printAsOperand(OS);
158+
if (Idx + 1 < NumArgs)
159+
OS << ", ";
160+
}
161+
OS << ")";
162+
}
163+
void Function::dump(raw_ostream &OS) const {
164+
dumpNameAndArgs(OS);
165+
OS << " {\n";
166+
OS << "}\n";
167+
}
168+
void Function::dump() const {
169+
dump(dbgs());
170+
dbgs() << "\n";
171+
}
172+
#endif // NDEBUG
173+
174+
Value *Context::getValue(llvm::Value *V) const {
175+
auto It = LLVMValueToValueMap.find(V);
176+
if (It != LLVMValueToValueMap.end())
177+
return It->second.get();
178+
return nullptr;
179+
}

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,53 @@ define void @foo(i32 %v1) {
4040
sandboxir::Context Ctx(C);
4141
[[maybe_unused]] sandboxir::User U(sandboxir::Value::ClassID::User, Ret, Ctx);
4242
}
43+
44+
TEST_F(SandboxIRTest, FunctionArgumentConstantAndOpaqueInstInstantiation) {
45+
parseIR(C, R"IR(
46+
define void @foo(i32 %v1) {
47+
%add = add i32 %v1, 42
48+
ret void
49+
}
50+
)IR");
51+
llvm::Function *LLVMF = &*M->getFunction("foo");
52+
llvm::BasicBlock *LLVMBB = &*LLVMF->begin();
53+
llvm::Instruction *LLVMAdd = &*LLVMBB->begin();
54+
auto *LLVMC = cast<llvm::Constant>(LLVMAdd->getOperand(1));
55+
auto *LLVMArg0 = LLVMF->getArg(0);
56+
57+
sandboxir::Context Ctx(C);
58+
sandboxir::Function F(LLVMF, Ctx);
59+
sandboxir::Argument Arg0(LLVMArg0, Ctx);
60+
sandboxir::Constant Const0(LLVMC, Ctx);
61+
sandboxir::OpaqueInst OpaqueI(LLVMAdd, Ctx);
62+
63+
EXPECT_TRUE(isa<sandboxir::Function>(F));
64+
EXPECT_FALSE(isa<sandboxir::Function>(Arg0));
65+
EXPECT_FALSE(isa<sandboxir::Function>(Const0));
66+
EXPECT_FALSE(isa<sandboxir::Function>(OpaqueI));
67+
68+
EXPECT_FALSE(isa<sandboxir::Argument>(F));
69+
EXPECT_TRUE(isa<sandboxir::Argument>(Arg0));
70+
EXPECT_FALSE(isa<sandboxir::Argument>(Const0));
71+
EXPECT_FALSE(isa<sandboxir::Argument>(OpaqueI));
72+
73+
EXPECT_TRUE(isa<sandboxir::Constant>(F));
74+
EXPECT_FALSE(isa<sandboxir::Constant>(Arg0));
75+
EXPECT_TRUE(isa<sandboxir::Constant>(Const0));
76+
EXPECT_FALSE(isa<sandboxir::Constant>(OpaqueI));
77+
78+
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(F));
79+
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Arg0));
80+
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Const0));
81+
EXPECT_TRUE(isa<sandboxir::OpaqueInst>(OpaqueI));
82+
83+
EXPECT_FALSE(isa<sandboxir::Instruction>(F));
84+
EXPECT_FALSE(isa<sandboxir::Instruction>(Arg0));
85+
EXPECT_FALSE(isa<sandboxir::Instruction>(Const0));
86+
EXPECT_TRUE(isa<sandboxir::Instruction>(OpaqueI));
87+
88+
EXPECT_FALSE(isa<sandboxir::User>(F));
89+
EXPECT_FALSE(isa<sandboxir::User>(Arg0));
90+
EXPECT_TRUE(isa<sandboxir::User>(Const0));
91+
EXPECT_TRUE(isa<sandboxir::User>(OpaqueI));
92+
}

0 commit comments

Comments
 (0)