Skip to content

[SandboxIR] More boilerplate: Function, Argument, Constant, Instruction, OpaqueInst #97343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions llvm/include/llvm/SandboxIR/SandboxIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#ifndef LLVM_TRANSFORMS_SANDBOXIR_SANDBOXIR_H
#define LLVM_TRANSFORMS_SANDBOXIR_SANDBOXIR_H

#include "llvm/IR/Function.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -129,6 +130,35 @@ class Value {
void dumpCommonPrefix(raw_ostream &OS) const;
void dumpCommonSuffix(raw_ostream &OS) const;
void printAsOperandCommon(raw_ostream &OS) const;
friend raw_ostream &operator<<(raw_ostream &OS, const sandboxir::Value &V) {
V.dump(OS);
return OS;
}
virtual void dump(raw_ostream &OS) const = 0;
LLVM_DUMP_METHOD virtual void dump() const = 0;
#endif
};

/// Argument of a sandboxir::Function.
class Argument : public sandboxir::Value {
public:
Argument(llvm::Argument *Arg, sandboxir::Context &Ctx)
: sandboxir::Value(ClassID::Argument, Arg, Ctx) {}
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::Argument;
}
#ifndef NDEBUG
void verify() const final {
assert(isa<llvm::Argument>(Val) && "Expected Argument!");
}
friend raw_ostream &operator<<(raw_ostream &OS,
const sandboxir::Argument &TArg) {
TArg.dump(OS);
return OS;
}
void printAsOperand(raw_ostream &OS) const;
void dump(raw_ostream &OS) const final;
LLVM_DUMP_METHOD void dump() const final;
#endif
};

Expand All @@ -142,16 +172,136 @@ class User : public Value {
assert(isa<llvm::User>(Val) && "Expected User!");
}
void dumpCommonHeader(raw_ostream &OS) const final;
void dump(raw_ostream &OS) const override {
// TODO: Remove this tmp implementation once we get the Instruction classes.
}
LLVM_DUMP_METHOD void dump() const override {
// TODO: Remove this tmp implementation once we get the Instruction classes.
}
#endif
};

class Constant : public sandboxir::User {
public:
Constant(llvm::Constant *C, sandboxir::Context &SBCtx)
: sandboxir::User(ClassID::Constant, C, SBCtx) {}
/// For isa/dyn_cast.
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::Constant ||
From->getSubclassID() == ClassID::Function;
}
sandboxir::Context &getParent() const { return getContext(); }
#ifndef NDEBUG
void verify() const final {
assert(isa<llvm::Constant>(Val) && "Expected Constant!");
}
friend raw_ostream &operator<<(raw_ostream &OS,
const sandboxir::Constant &SBC) {
SBC.dump(OS);
return OS;
}
void dump(raw_ostream &OS) const override;
LLVM_DUMP_METHOD void dump() const override;
#endif
};

/// A sandboxir::User with operands and opcode.
class Instruction : public sandboxir::User {
public:
enum class Opcode {
#define DEF_VALUE(ID, CLASS)
#define DEF_USER(ID, CLASS)
#define OP(OPC) OPC,
#define DEF_INSTR(ID, OPC, CLASS) OPC
#include "llvm/SandboxIR/SandboxIRValues.def"
};

Instruction(ClassID ID, Opcode Opc, llvm::Instruction *I,
sandboxir::Context &SBCtx)
: sandboxir::User(ID, I, SBCtx), Opc(Opc) {}

protected:
Opcode Opc;

public:
static const char *getOpcodeName(Opcode Opc);
#ifndef NDEBUG
friend raw_ostream &operator<<(raw_ostream &OS, Opcode Opc) {
OS << getOpcodeName(Opc);
return OS;
}
#endif
/// For isa/dyn_cast.
static bool classof(const sandboxir::Value *From);

#ifndef NDEBUG
friend raw_ostream &operator<<(raw_ostream &OS,
const sandboxir::Instruction &SBI) {
SBI.dump(OS);
return OS;
}
void dump(raw_ostream &OS) const override;
LLVM_DUMP_METHOD void dump() const override;
#endif
};

/// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to
/// an OpaqueInstr.
class OpaqueInst : public sandboxir::Instruction {
public:
OpaqueInst(llvm::Instruction *I, sandboxir::Context &Ctx)
: sandboxir::Instruction(ClassID::Opaque, Opcode::Opaque, I, Ctx) {}
OpaqueInst(ClassID SubclassID, llvm::Instruction *I, sandboxir::Context &Ctx)
: sandboxir::Instruction(SubclassID, Opcode::Opaque, I, Ctx) {}
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::Opaque;
}
#ifndef NDEBUG
void verify() const final {
// Nothing to do
}
friend raw_ostream &operator<<(raw_ostream &OS,
const sandboxir::OpaqueInst &OI) {
OI.dump(OS);
return OS;
}
void dump(raw_ostream &OS) const override;
LLVM_DUMP_METHOD void dump() const override;
#endif
};

class Context {
protected:
LLVMContext &LLVMCtx;
/// Maps LLVM Value to the corresponding sandboxir::Value. Owns all
/// SandboxIR objects.
DenseMap<llvm::Value *, std::unique_ptr<sandboxir::Value>>
LLVMValueToValueMap;

public:
Context(LLVMContext &LLVMCtx) : LLVMCtx(LLVMCtx) {}
sandboxir::Value *getValue(llvm::Value *V) const;
};

class Function : public sandboxir::Value {
public:
Function(llvm::Function *F, sandboxir::Context &Ctx)
: sandboxir::Value(ClassID::Function, F, Ctx) {}
/// For isa/dyn_cast.
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::Function;
}

#ifndef NDEBUG
void verify() const final {
assert(isa<llvm::Function>(Val) && "Expected Function!");
}
void dumpNameAndArgs(raw_ostream &OS) const;
void dump(raw_ostream &OS) const final;
LLVM_DUMP_METHOD void dump() const final;
#endif
};

} // namespace sandboxir
} // namespace llvm

Expand Down
21 changes: 17 additions & 4 deletions llvm/include/llvm/SandboxIR/SandboxIRValues.def
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,23 @@
//===----------------------------------------------------------------------===//

// ClassID, Class
DEF_USER(User, sandboxir::User)
#ifndef DEF_VALUE
#define DEF_VALUE(ID, CLASS)
#endif
DEF_VALUE(Function, Function)
DEF_VALUE(Argument, Argument)

#ifndef DEF_USER
#define DEF_USER(ID, CLASS)
#endif
DEF_USER(User, User)
DEF_USER(Constant, Constant)

#ifndef DEF_INSTR
#define DEF_INSTR(ID, OPCODE, CLASS)
#endif
// ClassID, Opcode(s), Class
DEF_INSTR(Opaque, OP(Opaque), OpaqueInst)

#ifdef DEF_VALUE
#undef DEF_VALUE
Expand All @@ -18,9 +34,6 @@ DEF_USER(User, sandboxir::User)
#ifdef DEF_INSTR
#undef DEF_INSTR
#endif
#ifdef OPCODES
#undef OPCODES
#endif
#ifdef OP
#undef OP
#endif
114 changes: 114 additions & 0 deletions llvm/lib/SandboxIR/SandboxIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,122 @@ void Value::printAsOperandCommon(raw_ostream &OS) const {
OS << "NULL ";
}

void Argument::printAsOperand(raw_ostream &OS) const {
printAsOperandCommon(OS);
}
void Argument::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void Argument::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG

bool User::classof(const Value *From) {
switch (From->getSubclassID()) {
#define DEF_VALUE(ID, CLASS)
#define DEF_USER(ID, CLASS) \
case ClassID::ID: \
return true;
#define DEF_INSTR(ID, OPC, CLASS) \
case ClassID::ID: \
return true;
#include "llvm/SandboxIR/SandboxIRValues.def"
default:
return false;
}
}

#ifndef NDEBUG
void User::dumpCommonHeader(raw_ostream &OS) const {
Value::dumpCommonHeader(OS);
// TODO: This is incomplete
}
#endif // NDEBUG

const char *Instruction::getOpcodeName(Opcode Opc) {
switch (Opc) {
#define DEF_VALUE(ID, CLASS)
#define DEF_USER(ID, CLASS)
#define OP(OPC) \
case Opcode::OPC: \
return #OPC;
#define DEF_INSTR(ID, OPC, CLASS) OPC
#include "llvm/SandboxIR/SandboxIRValues.def"
}
}

bool Instruction::classof(const sandboxir::Value *From) {
switch (From->getSubclassID()) {
#define DEF_INSTR(ID, OPC, CLASS) \
case ClassID::ID: \
return true;
#include "llvm/SandboxIR/SandboxIRValues.def"
default:
return false;
}
}

#ifndef NDEBUG
void Instruction::dump(raw_ostream &OS) const {
OS << "Unimplemented! Please override dump().";
}
void Instruction::dump() const {
dump(dbgs());
dbgs() << "\n";
}

void OpaqueInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}

void OpaqueInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}

void Constant::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}

void Constant::dump() const {
dump(dbgs());
dbgs() << "\n";
}

void Function::dumpNameAndArgs(raw_ostream &OS) const {
auto *F = cast<llvm::Function>(Val);
OS << *getType() << " @" << F->getName() << "(";
auto NumArgs = F->arg_size();
for (auto [Idx, Arg] : enumerate(F->args())) {
auto *SBArg = cast_or_null<Argument>(Ctx.getValue(&Arg));
if (SBArg == nullptr)
OS << "NULL";
else
SBArg->printAsOperand(OS);
if (Idx + 1 < NumArgs)
OS << ", ";
}
OS << ")";
}
void Function::dump(raw_ostream &OS) const {
dumpNameAndArgs(OS);
OS << " {\n";
OS << "}\n";
}
void Function::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG

Value *Context::getValue(llvm::Value *V) const {
auto It = LLVMValueToValueMap.find(V);
if (It != LLVMValueToValueMap.end())
return It->second.get();
return nullptr;
}
50 changes: 50 additions & 0 deletions llvm/unittests/SandboxIR/SandboxIRTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,53 @@ define void @foo(i32 %v1) {
sandboxir::Context Ctx(C);
[[maybe_unused]] sandboxir::User U(sandboxir::Value::ClassID::User, Ret, Ctx);
}

TEST_F(SandboxIRTest, FunctionArgumentConstantAndOpaqueInstInstantiation) {
parseIR(C, R"IR(
define void @foo(i32 %v1) {
%add = add i32 %v1, 42
ret void
}
)IR");
llvm::Function *LLVMF = &*M->getFunction("foo");
llvm::BasicBlock *LLVMBB = &*LLVMF->begin();
llvm::Instruction *LLVMAdd = &*LLVMBB->begin();
auto *LLVMC = cast<llvm::Constant>(LLVMAdd->getOperand(1));
auto *LLVMArg0 = LLVMF->getArg(0);

sandboxir::Context Ctx(C);
sandboxir::Function F(LLVMF, Ctx);
sandboxir::Argument Arg0(LLVMArg0, Ctx);
sandboxir::Constant Const0(LLVMC, Ctx);
sandboxir::OpaqueInst OpaqueI(LLVMAdd, Ctx);

EXPECT_TRUE(isa<sandboxir::Function>(F));
EXPECT_FALSE(isa<sandboxir::Function>(Arg0));
EXPECT_FALSE(isa<sandboxir::Function>(Const0));
EXPECT_FALSE(isa<sandboxir::Function>(OpaqueI));

EXPECT_FALSE(isa<sandboxir::Argument>(F));
EXPECT_TRUE(isa<sandboxir::Argument>(Arg0));
EXPECT_FALSE(isa<sandboxir::Argument>(Const0));
EXPECT_FALSE(isa<sandboxir::Argument>(OpaqueI));

EXPECT_TRUE(isa<sandboxir::Constant>(F));
EXPECT_FALSE(isa<sandboxir::Constant>(Arg0));
EXPECT_TRUE(isa<sandboxir::Constant>(Const0));
EXPECT_FALSE(isa<sandboxir::Constant>(OpaqueI));

EXPECT_FALSE(isa<sandboxir::OpaqueInst>(F));
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Arg0));
EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Const0));
EXPECT_TRUE(isa<sandboxir::OpaqueInst>(OpaqueI));

EXPECT_FALSE(isa<sandboxir::Instruction>(F));
EXPECT_FALSE(isa<sandboxir::Instruction>(Arg0));
EXPECT_FALSE(isa<sandboxir::Instruction>(Const0));
EXPECT_TRUE(isa<sandboxir::Instruction>(OpaqueI));

EXPECT_FALSE(isa<sandboxir::User>(F));
EXPECT_FALSE(isa<sandboxir::User>(Arg0));
EXPECT_TRUE(isa<sandboxir::User>(Const0));
EXPECT_TRUE(isa<sandboxir::User>(OpaqueI));
}
Loading