Skip to content

[SandboxIR] Boilerplate code #95814

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 1, 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
158 changes: 158 additions & 0 deletions llvm/include/llvm/SandboxIR/SandboxIR.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
//===- SandboxIR.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Sandbox IR is a lightweight overlay transactional IR on top of LLVM IR.
// Features:
// - You can save/rollback the state of the IR at any time.
// - Any changes made to Sandbox IR will automatically update the underlying
// LLVM IR so both IRs are always in sync.
// - Feels like LLVM IR, similar API.
//
// SandboxIR forms a class hierarchy that resembles that of LLVM IR
// but is in the `sandboxir` namespace:
//
// namespace sandboxir {
//
// +- Argument +- BinaryOperator
// | |
// Value -+- BasicBlock +- BranchInst
// | |
// +- Function +- Constant +- CastInst
// | | |
// +- User ------+- Instruction -+- CallInst
// |
// +- CmpInst
// |
// +- ExtractElementInst
// |
// +- GetElementPtrInst
// |
// +- InsertElementInst
// |
// +- LoadInst
// |
// +- OpaqueInst
// |
// +- PHINode
// |
// +- RetInst
// |
// +- SelectInst
// |
// +- ShuffleVectorInst
// |
// +- StoreInst
// |
// +- UnaryOperator
//
// Use
//
// } // namespace sandboxir
//

#ifndef LLVM_TRANSFORMS_SANDBOXIR_SANDBOXIR_H
#define LLVM_TRANSFORMS_SANDBOXIR_SANDBOXIR_H

#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/raw_ostream.h"

namespace llvm {

namespace sandboxir {

class Context;

/// A SandboxIR Value has users. This is the base class.
class Value {
public:
enum class ClassID : unsigned {
#define DEF_VALUE(ID, CLASS) ID,
#define DEF_USER(ID, CLASS) ID,
#define DEF_INSTR(ID, OPC, CLASS) ID,
#include "llvm/SandboxIR/SandboxIRValues.def"
};

protected:
static const char *getSubclassIDStr(ClassID ID) {
switch (ID) {
#define DEF_VALUE(ID, CLASS) \
case ClassID::ID: \
return #ID;
#define DEF_USER(ID, CLASS) \
case ClassID::ID: \
return #ID;
#define DEF_INSTR(ID, OPC, CLASS) \
case ClassID::ID: \
return #ID;
#include "llvm/SandboxIR/SandboxIRValues.def"
}
llvm_unreachable("Unimplemented ID");
}

/// For isa/dyn_cast.
ClassID SubclassID;
#ifndef NDEBUG
/// A unique ID used for forming the name (used for debugging).
unsigned UID;
#endif
/// The LLVM Value that corresponds to this SandboxIR Value.
/// NOTE: Some SBInstructions, like Packs, may include more than one value.
llvm::Value *Val = nullptr;

/// All values point to the context.
Context &Ctx;
// This is used by eraseFromParent().
void clearValue() { Val = nullptr; }
template <typename ItTy, typename SBTy> friend class LLVMOpUserItToSBTy;

public:
Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx);
virtual ~Value() = default;
ClassID getSubclassID() const { return SubclassID; }

Type *getType() const { return Val->getType(); }

Context &getContext() const;
#ifndef NDEBUG
/// Should crash if there is something wrong with the instruction.
virtual void verify() const = 0;
/// Returns the name in the form 'SB<number>.' like 'SB1.'
std::string getName() const;
virtual void dumpCommonHeader(raw_ostream &OS) const;
void dumpCommonFooter(raw_ostream &OS) const;
void dumpCommonPrefix(raw_ostream &OS) const;
void dumpCommonSuffix(raw_ostream &OS) const;
void printAsOperandCommon(raw_ostream &OS) const;
#endif
};

class User : public Value {
public:
User(ClassID ID, llvm::Value *V, Context &Ctx) : Value(ID, V, Ctx) {}
/// For isa/dyn_cast.
static bool classof(const Value *From);
#ifndef NDEBUG
void verify() const override {
assert(isa<llvm::User>(Val) && "Expected User!");
}
void dumpCommonHeader(raw_ostream &OS) const final;
#endif
};

class Context {
protected:
LLVMContext &LLVMCtx;

public:
Context(LLVMContext &LLVMCtx) : LLVMCtx(LLVMCtx) {}
};
} // namespace sandboxir
} // namespace llvm

#endif // LLVM_TRANSFORMS_SANDBOXIR_SANDBOXIR_H
26 changes: 26 additions & 0 deletions llvm/include/llvm/SandboxIR/SandboxIRValues.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===- SandboxIRValues.def --------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// ClassID, Class
DEF_USER(User, sandboxir::User)

#ifdef DEF_VALUE
#undef DEF_VALUE
#endif
#ifdef DEF_USER
#undef DEF_USER
#endif
#ifdef DEF_INSTR
#undef DEF_INSTR
#endif
#ifdef OPCODES
#undef OPCODES
#endif
#ifdef OP
#undef OP
#endif
1 change: 1 addition & 0 deletions llvm/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ add_subdirectory(DebugInfo)
add_subdirectory(DWP)
add_subdirectory(ExecutionEngine)
add_subdirectory(Target)
add_subdirectory(SandboxIR)
add_subdirectory(AsmParser)
add_subdirectory(LineEditor)
add_subdirectory(ProfileData)
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/SandboxIR/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
add_llvm_component_library(LLVMSandboxIR
SandboxIR.cpp

ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms/SandboxIR

LINK_COMPONENTS
Core
Support
)

66 changes: 66 additions & 0 deletions llvm/lib/SandboxIR/SandboxIR.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//===- SandboxIR.cpp - A transactional overlay IR on top of LLVM IR -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/SandboxIR/SandboxIR.h"
#include "llvm/Support/Debug.h"
#include <sstream>

using namespace llvm;
using namespace sandboxir;

sandboxir::Value::Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx)
: SubclassID(SubclassID), Val(Val), Ctx(Ctx) {
#ifndef NDEBUG
UID = 0; // FIXME: Once SBContext is available.
#endif
}

#ifndef NDEBUG
std::string sandboxir::Value::getName() const {
std::stringstream SS;
SS << "SB" << UID << ".";
return SS.str();
}

void sandboxir::Value::dumpCommonHeader(raw_ostream &OS) const {
OS << getName() << " " << getSubclassIDStr(SubclassID) << " ";
}

void sandboxir::Value::dumpCommonFooter(raw_ostream &OS) const {
OS.indent(2) << "Val: ";
if (Val)
OS << *Val;
else
OS << "NULL";
OS << "\n";
}

void sandboxir::Value::dumpCommonPrefix(raw_ostream &OS) const {
if (Val)
OS << *Val;
else
OS << "NULL ";
}

void sandboxir::Value::dumpCommonSuffix(raw_ostream &OS) const {
OS << " ; " << getName() << " (" << getSubclassIDStr(SubclassID) << ") "
<< this;
}

void sandboxir::Value::printAsOperandCommon(raw_ostream &OS) const {
if (Val)
Val->printAsOperand(OS);
else
OS << "NULL ";
}

void sandboxir::User::dumpCommonHeader(raw_ostream &OS) const {
Value::dumpCommonHeader(OS);
// TODO: This is incomplete
}
#endif // NDEBUG
1 change: 1 addition & 0 deletions llvm/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ add_subdirectory(Option)
add_subdirectory(Remarks)
add_subdirectory(Passes)
add_subdirectory(ProfileData)
add_subdirectory(SandboxIR)
add_subdirectory(Support)
add_subdirectory(TableGen)
add_subdirectory(Target)
Expand Down
10 changes: 10 additions & 0 deletions llvm/unittests/SandboxIR/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set(LLVM_LINK_COMPONENTS
AsmParser
SandboxIR
)

add_llvm_unittest(SandboxIRTests
SandboxIRTest.cpp
)

set_property(TARGET SandboxIRTests PROPERTY FOLDER "Tests/UnitTests/TransformsTests")
42 changes: 42 additions & 0 deletions llvm/unittests/SandboxIR/SandboxIRTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===- SandboxIRTest.cpp --------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/SandboxIR/SandboxIR.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"

using namespace llvm;

struct SandboxIRTest : public testing::Test {
LLVMContext C;
std::unique_ptr<Module> M;

void parseIR(LLVMContext &C, const char *IR) {
SMDiagnostic Err;
M = parseAssemblyString(IR, Err, C);
if (!M)
Err.print("SandboxIRTest", errs());
}
};

TEST_F(SandboxIRTest, UserInstantiation) {
parseIR(C, R"IR(
define void @foo(i32 %v1) {
ret void
}
)IR");
Function &F = *M->getFunction("foo");
auto *Ret = F.begin()->getTerminator();
sandboxir::Context Ctx(C);
[[maybe_unused]] sandboxir::User U(sandboxir::Value::ClassID::User, Ret, Ctx);
}
Loading