[tint][ir] Make Builder insertion point logic more flexible.
Change-Id: I76b7b424b88e778188ac232e44f67abd3c28fccb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/152402
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/builder.cc b/src/tint/lang/core/ir/builder.cc
index 71419f9..07ffe5a 100644
--- a/src/tint/lang/core/ir/builder.cc
+++ b/src/tint/lang/core/ir/builder.cc
@@ -25,7 +25,8 @@
Builder::Builder(Module& mod) : ir(mod) {}
-Builder::Builder(Module& mod, ir::Block* block) : current_block_(block), ir(mod) {}
+Builder::Builder(Module& mod, ir::Block* block)
+ : insertion_point_(InsertionPoints::AppendToBlock{block}), ir(mod) {}
Builder::~Builder() = default;
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index ffa0347..90608d2 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -104,11 +104,56 @@
using DisableIfVectorLike = tint::traits::EnableIf<
!tint::IsVectorLike<tint::traits::Decay<tint::traits::NthTypeOf<0, TYPES..., void>>>>;
- /// If set, any created instruction will be auto-appended to the block.
- ir::Block* current_block_ = nullptr;
+ /// A namespace for the various instruction insertion method
+ struct InsertionPoints {
+ /// Insertion point method that does no insertion
+ struct NoInsertion {
+ /// The insertion point function
+ void operator()(ir::Instruction*) {}
+ };
+ /// Insertion point method that inserts the instruction to the end of #block
+ struct AppendToBlock {
+ /// The block to insert new instructions to the end of
+ ir::Block* block = nullptr;
+ /// The insertion point function
+ /// @param i the instruction to insert
+ void operator()(ir::Instruction* i) { block->Append(i); }
+ };
+ /// Insertion point method that inserts the instruction to the front of #block
+ struct PrependToBlock {
+ /// The block to insert new instructions to the front of
+ ir::Block* block = nullptr;
+ /// The insertion point function
+ /// @param i the instruction to insert
+ void operator()(ir::Instruction* i) { block->Prepend(i); }
+ };
+ /// Insertion point method that inserts the instruction after #after
+ struct InsertAfter {
+ /// The instruction to insert new instructions after
+ ir::Instruction* after = nullptr;
+ /// The insertion point function
+ /// @param i the instruction to insert
+ void operator()(ir::Instruction* i) { i->InsertAfter(after); }
+ };
+ /// Insertion point method that inserts the instruction before #before
+ struct InsertBefore {
+ /// The instruction to insert new instructions before
+ ir::Instruction* before = nullptr;
+ /// The insertion point function
+ /// @param i the instruction to insert
+ void operator()(ir::Instruction* i) { i->InsertBefore(before); }
+ };
+ };
- /// If set, any created instruction will be auto-inserted before this instruction.
- ir::Instruction* current_insertion_point_ = nullptr;
+ /// A variant of different instruction insertion methods
+ using InsertionPoint = std::variant<InsertionPoints::NoInsertion,
+ InsertionPoints::AppendToBlock,
+ InsertionPoints::PrependToBlock,
+ InsertionPoints::InsertAfter,
+ InsertionPoints::InsertBefore>;
+
+ /// The insertion method used for new instructions.
+ InsertionPoint insertion_point_{InsertionPoints::NoInsertion{}};
public:
/// Constructor
@@ -116,7 +161,7 @@
explicit Builder(Module& mod);
/// Constructor
/// @param mod the ir::Module to wrap with this builder
- /// @param block the block to insert too
+ /// @param block the block to append to
Builder(Module& mod, ir::Block* block);
/// Destructor
~Builder();
@@ -131,8 +176,25 @@
/// @param cb the function to call with the builder appending to block @p b
template <typename FUNCTION>
void Append(ir::Block* b, FUNCTION&& cb) {
- TINT_SCOPED_ASSIGNMENT(current_block_, b);
- TINT_SCOPED_ASSIGNMENT(current_insertion_point_, nullptr);
+ TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::AppendToBlock{b});
+ cb();
+ }
+
+ /// Calls @p cb with the builder prepending to block @p b
+ /// @param b the block to set as the block to prepend to
+ /// @param cb the function to call with the builder prepending to block @p b
+ template <typename FUNCTION>
+ void Prepend(ir::Block* b, FUNCTION&& cb) {
+ TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::PrependToBlock{b});
+ cb();
+ }
+
+ /// Calls @p cb with the builder inserting after @p ip
+ /// @param ip the insertion point for new instructions
+ /// @param cb the function to call with the builder inserting new instructions after @p ip
+ template <typename FUNCTION>
+ void InsertAfter(ir::Instruction* ip, FUNCTION&& cb) {
+ TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::InsertAfter{ip});
cb();
}
@@ -141,23 +203,18 @@
/// @param cb the function to call with the builder inserting new instructions before @p ip
template <typename FUNCTION>
void InsertBefore(ir::Instruction* ip, FUNCTION&& cb) {
- TINT_SCOPED_ASSIGNMENT(current_block_, nullptr);
- TINT_SCOPED_ASSIGNMENT(current_insertion_point_, ip);
+ TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::InsertBefore{ip});
cb();
}
- /// Appends and returns the instruction @p val to the current insertion point. If there is no
- /// current insertion point set, then @p val is just returned.
- /// @param val the instruction to append
+ /// Adds and returns the instruction @p instruction to the current insertion point. If there
+ /// is no current insertion point set, then @p instruction is just returned.
+ /// @param instruction the instruction to append
/// @returns the instruction
template <typename T>
- T* Append(T* val) {
- if (current_insertion_point_) {
- val->InsertBefore(current_insertion_point_);
- } else if (current_block_) {
- current_block_->Append(val);
- }
- return val;
+ T* Append(T* instruction) {
+ std::visit([instruction](auto&& mode) { mode(instruction); }, insertion_point_);
+ return instruction;
}
/// @returns a new block