diff --git a/include/luisa/ast/constant_data.h b/include/luisa/ast/constant_data.h index 5abecaae9..e8ef3a303 100644 --- a/include/luisa/ast/constant_data.h +++ b/include/luisa/ast/constant_data.h @@ -42,7 +42,6 @@ class LC_AST_API ConstantDecoder { }; class LC_AST_API ConstantData { - friend class CallableLibrary; private: @@ -59,6 +58,7 @@ class LC_AST_API ConstantData { [[nodiscard]] auto raw() const noexcept { return _raw; } [[nodiscard]] auto type() const noexcept { return _type; } [[nodiscard]] auto hash() const noexcept { return _hash; } + [[nodiscard]] explicit operator bool() const noexcept { return _raw != nullptr; } [[nodiscard]] bool operator==(const ConstantData &rhs) const noexcept { return _hash == rhs._hash; } void decode(ConstantDecoder &d) const noexcept { d.decode(_type, _raw); } }; diff --git a/include/luisa/xir/argument.h b/include/luisa/xir/argument.h index bc1dd405c..7563f7e4e 100644 --- a/include/luisa/xir/argument.h +++ b/include/luisa/xir/argument.h @@ -4,13 +4,14 @@ namespace luisa::compute::xir { -class Argument : public Value { +class LC_XIR_API Argument : public Value { private: bool _by_ref = false; public: - explicit Argument(const Type *type = nullptr, + explicit Argument(Pool *pool, + const Type *type = nullptr, bool by_ref = false, const Name *name = nullptr) noexcept; void set_by_ref(bool by_ref) noexcept { _by_ref = by_ref; } diff --git a/include/luisa/xir/basic_block.h b/include/luisa/xir/basic_block.h index 29f34e410..3902cbdf8 100644 --- a/include/luisa/xir/basic_block.h +++ b/include/luisa/xir/basic_block.h @@ -7,24 +7,19 @@ namespace luisa::compute::xir { class Function; class Instruction; -class LC_XIR_API BasicBlock : public PooledObject { +class LC_XIR_API BasicBlock : public Value { private: Function *_function = nullptr; - BasicBlock *_parent_block = nullptr; - const Name *_name = nullptr; InlineInstructionList _instructions; public: - explicit BasicBlock(Function *function = nullptr, - BasicBlock *parent_block = nullptr, + explicit BasicBlock(Pool *pool, + Function *function = nullptr, const Name *name = nullptr) noexcept; void set_function(Function *function) noexcept; - void set_parent_block(BasicBlock *parent_block) noexcept; - void set_name(const Name *name) noexcept; - [[nodiscard]] auto function() const noexcept { return _function; } - [[nodiscard]] auto parent_block() const noexcept { return _parent_block; } - [[nodiscard]] auto name() const noexcept { return _name; } + [[nodiscard]] auto function() noexcept { return _function; } + [[nodiscard]] auto function() const noexcept { return const_cast(_function); } [[nodiscard]] auto &instructions() noexcept { return _instructions; } [[nodiscard]] auto &instructions() const noexcept { return _instructions; } }; diff --git a/include/luisa/xir/constant.h b/include/luisa/xir/constant.h index eff8cb6ee..ef32cbc9d 100644 --- a/include/luisa/xir/constant.h +++ b/include/luisa/xir/constant.h @@ -11,8 +11,7 @@ class LC_XIR_API Constant : public Value { ConstantData _data; public: - Constant() noexcept = default; - explicit Constant(ConstantData data, const Name *name = nullptr) noexcept; + explicit Constant(Pool *pool, ConstantData data = {}, const Name *name = nullptr) noexcept; void set_data(ConstantData data) noexcept; [[nodiscard]] auto data() const noexcept { return _data; } }; diff --git a/include/luisa/xir/function.h b/include/luisa/xir/function.h index 6d2a4382a..6e0c34e3a 100644 --- a/include/luisa/xir/function.h +++ b/include/luisa/xir/function.h @@ -4,7 +4,11 @@ namespace luisa::compute::xir { -class Function : public PooledObject { +class LC_XIR_API Function : public PooledObject { + +public: + explicit Function(Pool *pool) noexcept : PooledObject{pool} {} + }; }// namespace luisa::compute::xir diff --git a/include/luisa/xir/ilist.h b/include/luisa/xir/ilist.h index 6a2e3b413..0cbf3421b 100644 --- a/include/luisa/xir/ilist.h +++ b/include/luisa/xir/ilist.h @@ -108,9 +108,11 @@ class IntrusiveNode : public Base { public: using Super = IntrusiveNode; - using Base::Base; static_assert(std::is_base_of_v); +protected: + using Base::Base; + private: friend IntrusiveList; friend InlineIntrusiveList; @@ -162,9 +164,9 @@ class IntrusiveList : public detail::IntrusiveListImpl> { Node *_tail_sentinel = nullptr; public: - explicit IntrusiveList(Pool &pool) noexcept { - _head_sentinel = pool.create(); - _tail_sentinel = pool.create(); + explicit IntrusiveList(Pool *pool) noexcept { + _head_sentinel = pool->create(); + _tail_sentinel = pool->create(); _head_sentinel->_next = _tail_sentinel; _tail_sentinel->_prev = _head_sentinel; } @@ -182,7 +184,8 @@ class InlineIntrusiveList : public detail::IntrusiveListImpl); +protected: + using Base::Base; + private: template friend class IntrusiveForwardList; diff --git a/include/luisa/xir/instruction.h b/include/luisa/xir/instruction.h index dc8e9415a..c9cd3143b 100644 --- a/include/luisa/xir/instruction.h +++ b/include/luisa/xir/instruction.h @@ -12,7 +12,8 @@ class LC_XIR_API Instruction : public IntrusiveNode { BasicBlock *_parent_block = nullptr; public: - explicit Instruction(const Type *type = nullptr, + explicit Instruction(Pool *pool, + const Type *type = nullptr, BasicBlock *parent_block = nullptr, const Name *name = nullptr) noexcept; void remove_self() noexcept override; diff --git a/include/luisa/xir/instructions/branch.h b/include/luisa/xir/instructions/branch.h index 2e6a8bde6..33a46dcee 100644 --- a/include/luisa/xir/instructions/branch.h +++ b/include/luisa/xir/instructions/branch.h @@ -1,19 +1,35 @@ #pragma once +#include "luisa/xir/basic_block.h" + #include namespace luisa::compute::xir { class BasicBlock; -class BranchInst : public Instruction { - -private: - BasicBlock *_true_block = nullptr; - BasicBlock *_false_block = nullptr; +class LC_XIR_API BranchInst : public Instruction { public: + explicit BranchInst(Pool *pool, + Value *cond = nullptr, + BasicBlock *true_block = nullptr, + BasicBlock *false_block = nullptr, + BasicBlock *parent_block = nullptr, + const Name *name = nullptr) noexcept; + + void set_cond(Value *cond) noexcept; + void set_true_block(BasicBlock *block) noexcept; + void set_false_block(BasicBlock *block) noexcept; + + [[nodiscard]] Value *cond() noexcept; + [[nodiscard]] const Value *cond() const noexcept; + + [[nodiscard]] BasicBlock *true_block() noexcept; + [[nodiscard]] const BasicBlock *true_block() const noexcept; + [[nodiscard]] BasicBlock *false_block() noexcept; + [[nodiscard]] const BasicBlock *false_block() const noexcept; }; }// namespace luisa::compute::xir diff --git a/include/luisa/xir/metadata.h b/include/luisa/xir/metadata.h index 9a0691169..fe5477152 100644 --- a/include/luisa/xir/metadata.h +++ b/include/luisa/xir/metadata.h @@ -4,7 +4,11 @@ namespace luisa::compute::xir { -struct LC_XIR_API Metadata : IntrusiveForwardNode {}; +class LC_XIR_API Metadata : public IntrusiveForwardNode { + +public: + explicit Metadata(Pool *pool) noexcept; +}; using MetadataList = IntrusiveForwardList; diff --git a/include/luisa/xir/metadata/location.h b/include/luisa/xir/metadata/location.h index ad5e47203..4f88a3c97 100644 --- a/include/luisa/xir/metadata/location.h +++ b/include/luisa/xir/metadata/location.h @@ -1,9 +1,27 @@ #pragma once +#include #include namespace luisa::compute::xir { +class LC_XIR_API LocationMD : public Metadata { +private: + luisa::filesystem::path _file; + int _line; + int _column; -} \ No newline at end of file +public: + explicit LocationMD(Pool *pool, + luisa::filesystem::path file = {}, + int line = -1, int column = -1) noexcept; + void set_file(luisa::filesystem::path file) noexcept { _file = std::move(file); } + void set_line(int line) noexcept { _line = line; } + void set_column(int column) noexcept { _column = column; } + [[nodiscard]] auto &file() const noexcept { return _file; } + [[nodiscard]] auto line() const noexcept { return _line; } + [[nodiscard]] auto column() const noexcept { return _column; } +}; + +}// namespace luisa::compute::xir \ No newline at end of file diff --git a/include/luisa/xir/name.h b/include/luisa/xir/name.h index bb7731d15..f096739dd 100644 --- a/include/luisa/xir/name.h +++ b/include/luisa/xir/name.h @@ -5,12 +5,14 @@ namespace luisa::compute::xir { -class Name : public PooledObject { +class LC_XIR_API Name : public PooledObject { private: luisa::string _s; public: + explicit Name(Pool *pool, luisa::string s = {}) noexcept; + [[nodiscard]] auto string() const noexcept { return _s; } [[nodiscard]] const auto &operator*() const noexcept { return _s; } [[nodiscard]] const auto *operator->() const noexcept { return &_s; } }; diff --git a/include/luisa/xir/pool.h b/include/luisa/xir/pool.h index b6192b4cf..0b30b727e 100644 --- a/include/luisa/xir/pool.h +++ b/include/luisa/xir/pool.h @@ -8,10 +8,19 @@ namespace luisa::compute::xir { -struct LC_XIR_API PooledObject { +class Pool; - PooledObject() noexcept = default; +class LC_XIR_API PooledObject { + +private: + Pool *_pool; + +protected: + explicit PooledObject(Pool *pool) noexcept : _pool{pool} {} + +public: virtual ~PooledObject() noexcept = default; + [[nodiscard]] auto pool() const noexcept { return _pool; } // make the object pinned to its memory location PooledObject(PooledObject &&) noexcept = delete; @@ -33,7 +42,8 @@ class LC_XIR_API Pool : public concepts::Noncopyable { template requires std::derived_from [[nodiscard]] T *create(Args &&...args) { - auto object = luisa::new_with_allocator(std::forward(args)...); + auto object = luisa::new_with_allocator(this, std::forward(args)...); + assert(object->pool() == this && "PooledObject must be created with the correct pool."); _objects.emplace_back(object); return object; } diff --git a/include/luisa/xir/shared.h b/include/luisa/xir/shared.h index 415adafee..97bc70a52 100644 --- a/include/luisa/xir/shared.h +++ b/include/luisa/xir/shared.h @@ -4,7 +4,7 @@ namespace luisa::compute::xir { -class Shared : public Value { +class LC_XIR_API Shared : public Value { public: using Value::Value; }; diff --git a/include/luisa/xir/use.h b/include/luisa/xir/use.h index b3d3f9703..0730ed590 100644 --- a/include/luisa/xir/use.h +++ b/include/luisa/xir/use.h @@ -14,18 +14,16 @@ class LC_XIR_API Use : public IntrusiveForwardNode { User *_user = nullptr; public: - [[nodiscard]] auto value() noexcept { return _value; } - [[nodiscard]] auto value() const noexcept { return _value; } - [[nodiscard]] auto user() noexcept { return _user; } - [[nodiscard]] auto user() const noexcept { return _user; } - -public: - Use() noexcept = default; - Use(Value *value, User *user) noexcept; + explicit Use(Pool *pool, Value *value = nullptr, User *user = nullptr) noexcept; // set value, also update the use list of the old and new values void set_value(Value *value) noexcept; // set user, also update the use list of the old and new users void set_user(User *user) noexcept; + + [[nodiscard]] auto value() noexcept { return _value; } + [[nodiscard]] auto user() noexcept { return _user; } + [[nodiscard]] auto value() const noexcept { return const_cast(_value); } + [[nodiscard]] auto user() const noexcept { return const_cast(_user); } }; using UseList = IntrusiveForwardList; diff --git a/include/luisa/xir/user.h b/include/luisa/xir/user.h index 0e793383c..4eb48c1c8 100644 --- a/include/luisa/xir/user.h +++ b/include/luisa/xir/user.h @@ -13,10 +13,15 @@ class LC_XIR_API User : public Value { using Value::Value; void remove_operand_uses() noexcept; void add_operand_uses() noexcept; - void set_operands(luisa::vector operands) noexcept; - void set_operands(Pool &pool, luisa::span operands) noexcept; + void set_operand(size_t index, Value *value) noexcept; + [[nodiscard]] Use *operand_use(size_t index) noexcept; + [[nodiscard]] const Use *operand_use(size_t index) const noexcept; + [[nodiscard]] Value *operand(size_t index) noexcept; + [[nodiscard]] const Value *operand(size_t index) const noexcept; + void set_operand_count(size_t n) noexcept; + void set_operands(luisa::span operands) noexcept; [[nodiscard]] auto operands() noexcept { return luisa::span{_operands}; } - [[nodiscard]] auto operands() const noexcept { return luisa::span{_operands}; } + [[nodiscard]] auto operands() const noexcept { return luisa::span{_operands}; } }; }// namespace luisa::compute::xir diff --git a/include/luisa/xir/value.h b/include/luisa/xir/value.h index b57064d25..07d1ca995 100644 --- a/include/luisa/xir/value.h +++ b/include/luisa/xir/value.h @@ -19,7 +19,7 @@ class LC_XIR_API Value : public PooledObject { MetadataList _metadata_list; public: - explicit Value(const Type *type = nullptr, const Name *name = nullptr) noexcept; + explicit Value(Pool *pool, const Type *type = nullptr, const Name *name = nullptr) noexcept; void set_type(const Type *type) noexcept { _type = type; } void set_name(const Name *name) noexcept { _name = name; } diff --git a/src/xir/CMakeLists.txt b/src/xir/CMakeLists.txt index a6a041827..3c84debff 100644 --- a/src/xir/CMakeLists.txt +++ b/src/xir/CMakeLists.txt @@ -5,6 +5,7 @@ set(LUISA_COMPUTE_XIR_SOURCES function.cpp instruction.cpp metadata.cpp + name.cpp pool.cpp shared.cpp use.cpp diff --git a/src/xir/argument.cpp b/src/xir/argument.cpp index 93d5d3e78..71d20bf78 100644 --- a/src/xir/argument.cpp +++ b/src/xir/argument.cpp @@ -2,7 +2,8 @@ namespace luisa::compute::xir { -Argument::Argument(const Type *type, bool by_ref, const Name *name) noexcept - : Value{type, name}, _by_ref{by_ref} {} +Argument::Argument(Pool *pool, const Type *type, + bool by_ref, const Name *name) noexcept + : Value{pool, type, name}, _by_ref{by_ref} {} }// namespace luisa::compute::xir diff --git a/src/xir/basic_block.cpp b/src/xir/basic_block.cpp index 1c4b88fa4..b229bad61 100644 --- a/src/xir/basic_block.cpp +++ b/src/xir/basic_block.cpp @@ -2,8 +2,10 @@ namespace luisa::compute::xir { -BasicBlock::BasicBlock(Function *function, BasicBlock *parent_block, const Name *name) noexcept - : _function{function}, _parent_block{parent_block}, _name{name} { +BasicBlock::BasicBlock(Pool *pool, Function *function, const Name *name) noexcept + : Value{pool, nullptr, name}, + _function{function}, + _instructions{pool} { _instructions.head_sentinel()->set_parent_block(this); _instructions.tail_sentinel()->set_parent_block(this); } @@ -12,12 +14,4 @@ void BasicBlock::set_function(Function *function) noexcept { _function = function; } -void BasicBlock::set_parent_block(BasicBlock *parent_block) noexcept { - _parent_block = parent_block; -} - -void BasicBlock::set_name(const Name *name) noexcept { - _name = name; -} - }// namespace luisa::compute::xir diff --git a/src/xir/constant.cpp b/src/xir/constant.cpp index e02202e69..1635a8d0a 100644 --- a/src/xir/constant.cpp +++ b/src/xir/constant.cpp @@ -3,11 +3,11 @@ namespace luisa::compute::xir { -Constant::Constant(ConstantData data, const Name *name) noexcept - : Value{data.type(), name} { set_data(data); } +Constant::Constant(Pool *pool, ConstantData data, const Name *name) noexcept + : Value{pool, data.type(), name} { set_data(data); } void Constant::set_data(ConstantData data) noexcept { - LUISA_DEBUG_ASSERT(data.type() == type(), + LUISA_DEBUG_ASSERT(!data || data.type() == type(), "Constant data type mismatch: {} vs {}", data.type()->description(), type()->description()); diff --git a/src/xir/instruction.cpp b/src/xir/instruction.cpp index db8a02497..7fd4d2909 100644 --- a/src/xir/instruction.cpp +++ b/src/xir/instruction.cpp @@ -2,10 +2,13 @@ namespace luisa::compute::xir { -Instruction::Instruction(const Type *type, +Instruction::Instruction(Pool *pool, + const Type *type, BasicBlock *parent_block, const Name *name) noexcept - : Super{type, name} { set_parent_block(parent_block); } + : Super{pool, type, name} { + set_parent_block(parent_block); +} void Instruction::remove_self() noexcept { Super::remove_self(); diff --git a/src/xir/instructions/branch.cpp b/src/xir/instructions/branch.cpp index 3ab63f249..6a62a4a1f 100644 --- a/src/xir/instructions/branch.cpp +++ b/src/xir/instructions/branch.cpp @@ -2,4 +2,52 @@ namespace luisa::compute::xir { +BranchInst::BranchInst(Pool *pool, Value *cond, + BasicBlock *true_block, + BasicBlock *false_block, + BasicBlock *parent_block, + const Name *name) noexcept + : Instruction{pool, nullptr, parent_block, name} { + set_operand_count(3u); + set_cond(cond); + set_true_block(true_block); + set_false_block(false_block); } + +void BranchInst::set_cond(Value *cond) noexcept { + set_operand(0, cond); +} + +void BranchInst::set_true_block(BasicBlock *block) noexcept { + set_operand(1, block); +} + +void BranchInst::set_false_block(BasicBlock *block) noexcept { + set_operand(2, block); +} + +Value *BranchInst::cond() noexcept { + return operand(0); +} + +const Value *BranchInst::cond() const noexcept { + return operand(0); +} + +BasicBlock *BranchInst::true_block() noexcept { + return static_cast(operand(1)); +} + +const BasicBlock *BranchInst::true_block() const noexcept { + return static_cast(operand(1)); +} + +BasicBlock *BranchInst::false_block() noexcept { + return static_cast(operand(2)); +} + +const BasicBlock *BranchInst::false_block() const noexcept { + return static_cast(operand(2)); +} + +}// namespace luisa::compute::xir diff --git a/src/xir/metadata.cpp b/src/xir/metadata.cpp index 5b6bcf6b4..6c3105da7 100644 --- a/src/xir/metadata.cpp +++ b/src/xir/metadata.cpp @@ -2,6 +2,6 @@ namespace luisa::compute::xir { +Metadata::Metadata(Pool *pool) noexcept : Super{pool} {} - -} +}// namespace luisa::compute::xir diff --git a/src/xir/metadata/location.cpp b/src/xir/metadata/location.cpp index 02eb6407b..e1d44347c 100644 --- a/src/xir/metadata/location.cpp +++ b/src/xir/metadata/location.cpp @@ -2,6 +2,12 @@ namespace luisa::compute::xir { - - -} +LocationMD::LocationMD(Pool *pool, + luisa::filesystem::path file, + int line, int column) noexcept + : Metadata{pool}, + _file{std::move(file)}, + _line{line}, + _column{column} {} + +}// namespace luisa::compute::xir diff --git a/src/xir/name.cpp b/src/xir/name.cpp new file mode 100644 index 000000000..fa923b9f0 --- /dev/null +++ b/src/xir/name.cpp @@ -0,0 +1,8 @@ +#include + +namespace luisa::compute::xir { + +Name::Name(Pool *pool, luisa::string s) noexcept + : PooledObject{pool}, _s{std::move(s)} {} + +}// namespace luisa::compute::xir diff --git a/src/xir/pool.cpp b/src/xir/pool.cpp index 6dbe224d1..f300ae112 100644 --- a/src/xir/pool.cpp +++ b/src/xir/pool.cpp @@ -3,7 +3,7 @@ namespace luisa::compute::xir { Pool::Pool(size_t init_cap) noexcept { - if (init_cap) { + if (init_cap != 0u) { _objects.reserve(init_cap); } } diff --git a/src/xir/shared.cpp b/src/xir/shared.cpp index 15fc6339b..ec53fb255 100644 --- a/src/xir/shared.cpp +++ b/src/xir/shared.cpp @@ -2,4 +2,4 @@ namespace luisa::compute::xir { -} +}// namespace luisa::compute::xir diff --git a/src/xir/use.cpp b/src/xir/use.cpp index 9d6af65d1..d7234d691 100644 --- a/src/xir/use.cpp +++ b/src/xir/use.cpp @@ -4,7 +4,7 @@ namespace luisa::compute::xir { -Use::Use(Value *value, User *user) noexcept { +Use::Use(Pool *pool, Value *value, User *user) noexcept : Super{pool} { set_value(value); set_user(user); } diff --git a/src/xir/user.cpp b/src/xir/user.cpp index fe2d46f3a..4e117a9f2 100644 --- a/src/xir/user.cpp +++ b/src/xir/user.cpp @@ -1,34 +1,69 @@ +#include #include namespace luisa::compute::xir { void User::remove_operand_uses() noexcept { for (auto o : _operands) { - o->remove_self(); + if (o != nullptr) { + o->remove_self(); + } } } void User::add_operand_uses() noexcept { for (auto o : _operands) { - if (auto value = o->value(); value && !o->is_linked()) { - o->add_to_list(value->use_list()); + if (o != nullptr) { + LUISA_DEBUG_ASSERT(o->user() == this, "Use::user() should be the same as this."); + if (!o->is_linked() && o->value() != nullptr) { + o->add_to_list(o->value()->use_list()); + } } } } -void User::set_operands(luisa::vector operands) noexcept { - remove_operand_uses(); - _operands = std::move(operands); - add_operand_uses(); +void User::set_operand(size_t index, Value *value) noexcept { + LUISA_DEBUG_ASSERT(index < _operands.size(), "Index out of range."); + if (auto old = _operands[index]) { + old->set_value(value); + } else { + auto use = pool()->create(value, this); + _operands[index] = use; + } +} + +Use *User::operand_use(size_t index) noexcept { + LUISA_DEBUG_ASSERT(index < _operands.size(), "Index out of range."); + return _operands[index]; +} + +const Use *User::operand_use(size_t index) const noexcept { + LUISA_DEBUG_ASSERT(index < _operands.size(), "Index out of range."); + return _operands[index]; } -void User::set_operands(Pool &pool, luisa::span operands) noexcept { - luisa::vector operand_uses; - operand_uses.reserve(operands.size()); +Value *User::operand(size_t index) noexcept { + return operand_use(index)->value(); +} + +const Value *User::operand(size_t index) const noexcept { + return operand_use(index)->value(); +} + +void User::set_operand_count(size_t n) noexcept { + for (auto i = n; i < _operands.size(); i++) { + _operands[i]->remove_self(); + } + _operands.resize(n); +} + +void User::set_operands(luisa::span operands) noexcept { + remove_operand_uses(); + _operands.clear(); for (auto o : operands) { - operand_uses.emplace_back(pool.create(o, this)); + auto use = pool()->create(o, this); + _operands.emplace_back(use); } - set_operands(std::move(operand_uses)); } }// namespace luisa::compute::xir diff --git a/src/xir/value.cpp b/src/xir/value.cpp index 2f3763384..ce4c6b99e 100644 --- a/src/xir/value.cpp +++ b/src/xir/value.cpp @@ -2,7 +2,7 @@ namespace luisa::compute::xir { -Value::Value(const Type *type, const Name *name) noexcept - : _type{type}, _name{name} {} +Value::Value(Pool *pool, const Type *type, const Name *name) noexcept + : PooledObject{pool}, _type{type}, _name{name} {} }// namespace luisa::compute::xir