Skip to content

Commit 1d7b348

Browse files
committed
[SandboxIR] More boilerplate: Function, Argument, Constant, Instruction, OpaqueInst
A very basic implementation of sandboxir:: `Fuction` `Argument` `Constant` `Instruction` `OpaqueInst`
1 parent 60cd3eb commit 1d7b348

File tree

4 files changed

+331
-4
lines changed

4 files changed

+331
-4
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 151 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,137 @@ 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 OPCODES(...) __VA_ARGS__
216+
#define DEF_INSTR(ID, OPC, CLASS) OPC
217+
#include "llvm/SandboxIR/SandboxIRValues.def"
218+
};
219+
220+
Instruction(ClassID ID, Opcode Opc, llvm::Instruction *I,
221+
sandboxir::Context &SBCtx)
222+
: sandboxir::User(ID, I, SBCtx), Opc(Opc) {}
223+
224+
protected:
225+
Opcode Opc;
226+
227+
public:
228+
static const char *getOpcodeName(Opcode Opc);
229+
#ifndef NDEBUG
230+
friend raw_ostream &operator<<(raw_ostream &OS, Opcode Opc) {
231+
OS << getOpcodeName(Opc);
232+
return OS;
233+
}
234+
#endif
235+
/// For isa/dyn_cast.
236+
static bool classof(const sandboxir::Value *From);
237+
238+
#ifndef NDEBUG
239+
friend raw_ostream &operator<<(raw_ostream &OS,
240+
const sandboxir::Instruction &SBI) {
241+
SBI.dump(OS);
242+
return OS;
243+
}
244+
void dump(raw_ostream &OS) const override;
245+
LLVM_DUMP_METHOD void dump() const override;
246+
#endif
247+
};
248+
249+
/// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to
250+
/// an OpaqueInstr.
251+
class OpaqueInst : public sandboxir::Instruction {
252+
public:
253+
OpaqueInst(llvm::Instruction *I, sandboxir::Context &Ctx)
254+
: sandboxir::Instruction(ClassID::Opaque, Opcode::Opaque, I, Ctx) {}
255+
OpaqueInst(ClassID SubclassID, llvm::Instruction *I, sandboxir::Context &Ctx)
256+
: sandboxir::Instruction(SubclassID, Opcode::Opaque, I, Ctx) {}
257+
static bool classof(const sandboxir::Value *From) {
258+
return From->getSubclassID() == ClassID::Opaque;
259+
}
260+
#ifndef NDEBUG
261+
void verify() const final {
262+
// Nothing to do
263+
}
264+
friend raw_ostream &operator<<(raw_ostream &OS,
265+
const sandboxir::OpaqueInst &OI) {
266+
OI.dump(OS);
267+
return OS;
268+
}
269+
void dump(raw_ostream &OS) const override;
270+
LLVM_DUMP_METHOD void dump() const override;
145271
#endif
146272
};
147273

148274
class Context {
149275
protected:
150276
LLVMContext &LLVMCtx;
277+
/// Maps LLVM Value to the corresponding sandboxir::Value. Owns all
278+
/// SandboxIR objects.
279+
DenseMap<llvm::Value *, std::unique_ptr<sandboxir::Value>>
280+
LLVMValueToValueMap;
151281

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

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: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,52 @@ 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+
sandboxir::Context Ctx(C);
56+
auto *LLVMArg0 = LLVMF->getArg(0);
57+
sandboxir::Function F(LLVMF, Ctx);
58+
sandboxir::Argument Arg0(LLVMArg0, Ctx);
59+
sandboxir::Constant Const0(LLVMC, Ctx);
60+
sandboxir::OpaqueInst OpaqueI(LLVMAdd, Ctx);
61+
62+
EXPECT_TRUE(isa<sandboxir::Function>(F));
63+
EXPECT_FALSE(isa<sandboxir::Function>(Arg0));
64+
EXPECT_FALSE(isa<sandboxir::Function>(Const0));
65+
EXPECT_FALSE(isa<sandboxir::Function>(OpaqueI));
66+
67+
EXPECT_FALSE(isa<sandboxir::Argument>(F));
68+
EXPECT_TRUE(isa<sandboxir::Argument>(Arg0));
69+
EXPECT_FALSE(isa<sandboxir::Argument>(Const0));
70+
EXPECT_FALSE(isa<sandboxir::Argument>(OpaqueI));
71+
72+
EXPECT_TRUE(isa<sandboxir::Constant>(F));
73+
EXPECT_FALSE(isa<sandboxir::Constant>(Arg0));
74+
EXPECT_TRUE(isa<sandboxir::Constant>(Const0));
75+
EXPECT_FALSE(isa<sandboxir::Constant>(OpaqueI));
76+
77+
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(F));
78+
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Arg0));
79+
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Const0));
80+
EXPECT_TRUE(isa<sandboxir::OpaqueInst>(OpaqueI));
81+
82+
EXPECT_FALSE(isa<sandboxir::Instruction>(F));
83+
EXPECT_FALSE(isa<sandboxir::Instruction>(Arg0));
84+
EXPECT_FALSE(isa<sandboxir::Instruction>(Const0));
85+
EXPECT_TRUE(isa<sandboxir::Instruction>(OpaqueI));
86+
87+
EXPECT_FALSE(isa<sandboxir::User>(F));
88+
EXPECT_FALSE(isa<sandboxir::User>(Arg0));
89+
EXPECT_TRUE(isa<sandboxir::User>(Const0));
90+
EXPECT_TRUE(isa<sandboxir::User>(OpaqueI));
91+
}

0 commit comments

Comments
 (0)