[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