Skip to content

Commit

Permalink
wip: XIR Builder
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike-Leo-Smith committed Oct 25, 2024
1 parent 030015c commit 3984aab
Show file tree
Hide file tree
Showing 24 changed files with 276 additions and 42 deletions.
4 changes: 2 additions & 2 deletions include/luisa/xir/basic_block.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ class LC_XIR_API BasicBlock : public Value {

private:
friend class User;
friend class Function;
void _set_parent_value(Value *parent_value) noexcept;

public:
explicit BasicBlock(Pool *pool, Value *parent_value = nullptr,
const Name *name = nullptr) noexcept;
explicit BasicBlock(Pool *pool, const Name *name = nullptr) noexcept;
[[nodiscard]] DerivedValueTag derived_value_tag() const noexcept final {
return DerivedValueTag::BASIC_BLOCK;
}
Expand Down
68 changes: 67 additions & 1 deletion include/luisa/xir/builder.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,73 @@
#pragma once

#include <luisa/xir/instructions/branch.h>
#include <luisa/xir/instructions/break.h>
#include <luisa/xir/instructions/call.h>
#include <luisa/xir/instructions/cast.h>
#include <luisa/xir/instructions/comment.h>
#include <luisa/xir/instructions/continue.h>
#include <luisa/xir/instructions/gep.h>
#include <luisa/xir/instructions/intrinsic.h>
#include <luisa/xir/instructions/load.h>
#include <luisa/xir/instructions/loop.h>
#include <luisa/xir/instructions/phi.h>
#include <luisa/xir/instructions/print.h>
#include <luisa/xir/instructions/return.h>
#include <luisa/xir/instructions/store.h>
#include <luisa/xir/instructions/switch.h>
#include <luisa/xir/instructions/unreachable.h>

namespace luisa::compute::xir {

class LC_XIR_API Builder {

private:
Instruction *_insertion_point = nullptr;

private:
void _check_valid_insertion_point() const noexcept;
[[nodiscard]] Pool *_pool_from_insertion_point() const noexcept;

template<typename T, typename... Args>
[[nodiscard]] auto _create_and_append_instruction(Args &&...args) noexcept {
auto inst = _pool_from_insertion_point()->create<T>(std::forward<Args>(args)...);
_insertion_point->insert_after_self(inst);
_insertion_point = inst;
return inst;
}

public:
Builder() noexcept;
void set_insertion_point(Instruction *insertion_point) noexcept;
void set_insertion_point(BasicBlock *block) noexcept;
[[nodiscard]] auto insertion_point() noexcept -> Instruction * { return _insertion_point; }
[[nodiscard]] auto insertion_point() const noexcept -> const Instruction * { return _insertion_point; }

public:
BranchInst *if_(Value *cond) noexcept;
SwitchInst *switch_(Value *value) noexcept;
LoopInst *loop() noexcept;

BreakInst *break_() noexcept;
ContinueInst *continue_() noexcept;
UnreachableInst *unreachable_() noexcept;
ReturnInst *return_(Value *value) noexcept;
ReturnInst *return_void() noexcept;

CallInst *call(const Type *type, Value *callee, luisa::span<Value *const> arguments) noexcept;
IntrinsicInst *call(const Type *type, IntrinsicOp op, luisa::span<Value *const> arguments) noexcept;

CastInst *static_cast_(const Type *type, Value *value) noexcept;
CastInst *bitwise_cast_(const Type *type, Value *value) noexcept;

PhiInst *phi(const Type *type) noexcept;
PrintInst *print(luisa::string format, luisa::span<Value *const> values) noexcept;

GEPInst *gep(const Type *type, Value *base, luisa::span<Value *const> indices) noexcept;
LoadInst *load(const Type *type, Value *variable) noexcept;
StoreInst *store(Value *variable, Value *value) noexcept;

CommentInst *comment(luisa::string text) noexcept;
};

}
}// namespace luisa::compute::xir
2 changes: 1 addition & 1 deletion include/luisa/xir/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class LC_XIR_API Function : public Value {

private:
FunctionTag _function_tag;
BasicBlock *_body = nullptr;
BasicBlock *_body;
ArgumentList _arguments;
SharedVariableList _shared_variables;
LocalVariableList _local_variables;
Expand Down
4 changes: 4 additions & 0 deletions include/luisa/xir/instructions/branch.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class LC_XIR_API BranchInst final : public Instruction {
void set_false_block(BasicBlock *block) noexcept;
void set_merge_block(BasicBlock *block) noexcept;

BasicBlock *create_true_block(Pool *pool, const Name *name = nullptr) noexcept;
BasicBlock *create_false_block(Pool *pool, const Name *name = nullptr) noexcept;
BasicBlock *create_merge_block(Pool *pool, const Name *name = nullptr) noexcept;

[[nodiscard]] Value *cond() noexcept;
[[nodiscard]] const Value *cond() const noexcept;

Expand Down
4 changes: 2 additions & 2 deletions include/luisa/xir/instructions/call.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ class LC_XIR_API CallInst final : public Instruction {
static constexpr size_t operand_index_argument_offset = 1u;

public:
explicit CallInst(Pool *pool, Value *callee = nullptr,
explicit CallInst(Pool *pool, const Type *type = nullptr,
Value *callee = nullptr,
luisa::span<Value *const> arguments = {},
const Type *type = nullptr,
const Name *name = nullptr) noexcept;
[[nodiscard]] DerivedInstructionTag derived_instruction_tag() const noexcept override {
return DerivedInstructionTag::CALL;
Expand Down
5 changes: 2 additions & 3 deletions include/luisa/xir/instructions/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ class LC_XIR_API CastInst final : public Instruction {
CastOp _op;

public:
explicit CastInst(Pool *pool, CastOp op = CastOp::STATIC_CAST,
Value *value = nullptr,
const Type *target_type = nullptr,
explicit CastInst(Pool *pool, const Type *target_type = nullptr,
CastOp op = CastOp::STATIC_CAST, Value *value = nullptr,
const Name *name = nullptr) noexcept;

[[nodiscard]] DerivedInstructionTag derived_instruction_tag() const noexcept override {
Expand Down
5 changes: 2 additions & 3 deletions include/luisa/xir/instructions/gep.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ class LC_XIR_API GEPInst final : public Instruction {
static constexpr size_t operand_index_index_offset = 1u;

public:
explicit GEPInst(Pool *pool, Value *base = nullptr,
luisa::span<Value *const> indices = {},
const Type *type = nullptr,
explicit GEPInst(Pool *pool, const Type *type = nullptr,
Value *base = nullptr, luisa::span<Value *const> indices = {},
const Name *name = nullptr) noexcept;
[[nodiscard]] DerivedInstructionTag derived_instruction_tag() const noexcept override {
return DerivedInstructionTag::GEP;
Expand Down
4 changes: 2 additions & 2 deletions include/luisa/xir/instructions/intrinsic.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,9 @@ class LC_XIR_API IntrinsicInst final : public Instruction {
IntrinsicOp _op;

public:
explicit IntrinsicInst(Pool *pool, IntrinsicOp op = IntrinsicOp::NOP,
explicit IntrinsicInst(Pool *pool, const Type *type = nullptr,
IntrinsicOp op = IntrinsicOp::NOP,
luisa::span<Value *const> operands = {},
const Type *type = nullptr,
const Name *name = nullptr) noexcept;
[[nodiscard]] DerivedInstructionTag derived_instruction_tag() const noexcept override {
return DerivedInstructionTag::INTRINSIC;
Expand Down
4 changes: 2 additions & 2 deletions include/luisa/xir/instructions/load.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace luisa::compute::xir {

class LC_XIR_API LoadInst final : public Instruction {
public:
explicit LoadInst(Pool *pool, Value *variable = nullptr,
const Type *type = nullptr,
explicit LoadInst(Pool *pool, const Type *type = nullptr,
Value *variable = nullptr,
const Name *name = nullptr) noexcept;
[[nodiscard]] DerivedInstructionTag derived_instruction_tag() const noexcept override {
return DerivedInstructionTag::LOAD;
Expand Down
8 changes: 6 additions & 2 deletions include/luisa/xir/instructions/loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ class LC_XIR_API LoopInst final : public Instruction {
static constexpr size_t operand_index_merge_block = 4u;

public:
explicit LoopInst(Pool *pool, Value *cond = nullptr,
const Name *name = nullptr) noexcept;
explicit LoopInst(Pool *pool, const Name *name = nullptr) noexcept;
[[nodiscard]] DerivedInstructionTag derived_instruction_tag() const noexcept override {
return DerivedInstructionTag::LOOP;
}
Expand All @@ -43,6 +42,11 @@ class LC_XIR_API LoopInst final : public Instruction {
void set_update_block(BasicBlock *block) noexcept;
void set_merge_block(BasicBlock *block) noexcept;

BasicBlock *create_prepare_block(Pool *pool, const Name *name = nullptr) noexcept;
BasicBlock *create_body_block(Pool *pool, const Name *name = nullptr) noexcept;
BasicBlock *create_update_block(Pool *pool, const Name *name = nullptr) noexcept;
BasicBlock *create_merge_block(Pool *pool, const Name *name = nullptr) noexcept;

[[nodiscard]] BasicBlock *prepare_block() noexcept;
[[nodiscard]] const BasicBlock *prepare_block() const noexcept;

Expand Down
3 changes: 1 addition & 2 deletions include/luisa/xir/instructions/store.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ class LC_XIR_API StoreInst final : public Instruction {
static constexpr size_t operand_index_value = 1u;

public:
explicit StoreInst(Pool *pool,
Value *variable = nullptr,
explicit StoreInst(Pool *pool, Value *variable = nullptr,
Value *value = nullptr,
const Name *name = nullptr) noexcept;

Expand Down
4 changes: 4 additions & 0 deletions include/luisa/xir/instructions/switch.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class LC_XIR_API SwitchInst final : public Instruction {
void set_default_block(BasicBlock *block) noexcept;
void set_merge_block(BasicBlock *block) noexcept;

BasicBlock *create_default_block(Pool *pool, const Name *name = nullptr) noexcept;
BasicBlock *create_merge_block(Pool *pool, const Name *name = nullptr) noexcept;
BasicBlock *create_case_block(Pool *pool, case_value_type value, const Name *name = nullptr) noexcept;

void set_case_count(size_t count) noexcept;
[[nodiscard]] size_t case_count() const noexcept;

Expand Down
1 change: 1 addition & 0 deletions src/xir/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set(LUISA_COMPUTE_XIR_SOURCES
basic_block.cpp
builder.cpp
constant.cpp
function.cpp
instruction.cpp
Expand Down
6 changes: 2 additions & 4 deletions src/xir/basic_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

namespace luisa::compute::xir {

BasicBlock::BasicBlock(Pool *pool, Value *parent_value, const Name *name) noexcept
: Value{pool, nullptr, name},
_parent_value{parent_value},
_instructions{pool} {
BasicBlock::BasicBlock(Pool *pool, const Name *name) noexcept
: Value{pool, nullptr, name}, _instructions{pool} {
_instructions.head_sentinel()->_set_parent_block(this);
_instructions.tail_sentinel()->_set_parent_block(this);
}
Expand Down
98 changes: 98 additions & 0 deletions src/xir/builder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include <luisa/core/logging.h>
#include <luisa/xir/builder.h>

namespace luisa::compute::xir {

void Builder::_check_valid_insertion_point() const noexcept {
LUISA_ASSERT(_insertion_point != nullptr, "Invalid insertion point.");
}

Pool *Builder::_pool_from_insertion_point() const noexcept {
_check_valid_insertion_point();
return _insertion_point->pool();
}

Builder::Builder() noexcept = default;

BranchInst *Builder::if_(Value *cond) noexcept {
return _create_and_append_instruction<BranchInst>(cond);
}

SwitchInst *Builder::switch_(Value *value) noexcept {
return _create_and_append_instruction<SwitchInst>(value);
}

LoopInst *Builder::loop() noexcept {
return _create_and_append_instruction<LoopInst>();
}

BreakInst *Builder::break_() noexcept {
return _create_and_append_instruction<BreakInst>();
}

ContinueInst *Builder::continue_() noexcept {
return _create_and_append_instruction<ContinueInst>();
}

UnreachableInst *Builder::unreachable_() noexcept {
return _create_and_append_instruction<UnreachableInst>();
}

ReturnInst *Builder::return_(Value *value) noexcept {
return _create_and_append_instruction<ReturnInst>(value);
}

ReturnInst *Builder::return_void() noexcept {
return _create_and_append_instruction<ReturnInst>();
}

CallInst *Builder::call(const Type *type, Value *callee, luisa::span<Value *const> arguments) noexcept {
return _create_and_append_instruction<CallInst>(type, callee, arguments);
}

IntrinsicInst *Builder::call(const Type *type, IntrinsicOp op, luisa::span<Value *const> arguments) noexcept {
return _create_and_append_instruction<IntrinsicInst>(type, op, arguments);
}

CastInst *Builder::static_cast_(const Type *type, Value *value) noexcept {
return _create_and_append_instruction<CastInst>(type, CastOp::STATIC_CAST, value);
}

CastInst *Builder::bitwise_cast_(const Type *type, Value *value) noexcept {
return _create_and_append_instruction<CastInst>(type, CastOp::BITWISE_CAST, value);
}

PhiInst *Builder::phi(const Type *type) noexcept {
return _create_and_append_instruction<PhiInst>(type);
}

PrintInst *Builder::print(luisa::string format, luisa::span<Value *const> values) noexcept {
return _create_and_append_instruction<PrintInst>(std::move(format), values);
}

GEPInst *Builder::gep(const Type *type, Value *base, luisa::span<Value *const> indices) noexcept {
return _create_and_append_instruction<GEPInst>(type, base, indices);
}

LoadInst *Builder::load(const Type *type, Value *variable) noexcept {
return _create_and_append_instruction<LoadInst>(type, variable);
}

StoreInst *Builder::store(Value *variable, Value *value) noexcept {
return _create_and_append_instruction<StoreInst>(variable, value);
}

CommentInst *Builder::comment(luisa::string text) noexcept {
return _create_and_append_instruction<CommentInst>(std::move(text));
}

void Builder::set_insertion_point(Instruction *insertion_point) noexcept {
_insertion_point = insertion_point;
}

void Builder::set_insertion_point(BasicBlock *block) noexcept {
auto instruction = block ? block->instructions().tail_sentinel()->prev() : nullptr;
set_insertion_point(instruction);
}

}// namespace luisa::compute::xir
6 changes: 3 additions & 3 deletions src/xir/function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
namespace luisa::compute::xir {

Function::Function(Pool *pool, FunctionTag tag, const Type *type, const Name *name) noexcept
: Value{pool, type, name},
_function_tag{tag}, _body{pool->create<BasicBlock>(this)},
_arguments{pool}, _shared_variables{pool}, _local_variables{pool} {
: Value{pool, type, name}, _body{pool->create<BasicBlock>()},
_function_tag{tag}, _arguments{pool}, _shared_variables{pool}, _local_variables{pool} {
_body->_set_parent_value(this);
_arguments.head_sentinel()->set_parent_function(this);
_arguments.tail_sentinel()->set_parent_function(this);
_shared_variables.head_sentinel()->set_parent_function(this);
Expand Down
18 changes: 18 additions & 0 deletions src/xir/instructions/branch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ void BranchInst::set_merge_block(BasicBlock *block) noexcept {
set_operand(operand_index_merge_block, block);
}

BasicBlock *BranchInst::create_true_block(Pool *pool, const Name *name) noexcept {
auto block = pool->create<BasicBlock>(name);
set_true_block(block);
return block;
}

BasicBlock *BranchInst::create_false_block(Pool *pool, const Name *name) noexcept {
auto block = pool->create<BasicBlock>(name);
set_false_block(block);
return block;
}

BasicBlock *BranchInst::create_merge_block(Pool *pool, const Name *name) noexcept {
auto block = pool->create<BasicBlock>(name);
set_merge_block(block);
return block;
}

Value *BranchInst::cond() noexcept {
return operand(operand_index_cond);
}
Expand Down
6 changes: 3 additions & 3 deletions src/xir/instructions/call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace luisa::compute::xir {

CallInst::CallInst(Pool *pool, Value *callee,
luisa::span<Value *const> arguments,
const Type *type, const Name *name) noexcept
CallInst::CallInst(Pool *pool, const Type *type,
Value *callee, luisa::span<Value *const> arguments,
const Name *name) noexcept
: Instruction{pool, type, name} {
set_operand_count(1u + arguments.size());
set_operand(operand_index_callee, callee);
Expand Down
5 changes: 3 additions & 2 deletions src/xir/instructions/cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

namespace luisa::compute::xir {

CastInst::CastInst(Pool *pool, CastOp op, Value *value,
const Type *target_type, const Name *name) noexcept
CastInst::CastInst(Pool *pool, const Type *target_type,
CastOp op, Value *value,
const Name *name) noexcept
: Instruction{pool, target_type, name}, _op{op} {
auto operands = std::array{value};
set_operands(operands);
Expand Down
Loading

0 comments on commit 3984aab

Please sign in to comment.