[tint][ir] Track owning block in BlockParam
This allows transforms to more easily determine suitable insertion
points, and enables the validator to ensure that block parameters are
only used in a single block.
Change-Id: Ia8ede6d86952bbc89be6fe6f09b6c8fb7ea377cf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/185523
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/block_param.h b/src/tint/lang/core/ir/block_param.h
index 009e022..0b697a2 100644
--- a/src/tint/lang/core/ir/block_param.h
+++ b/src/tint/lang/core/ir/block_param.h
@@ -31,25 +31,42 @@
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/utils/rtti/castable.h"
+// Forward declarations
+namespace tint::core::ir {
+class MultiInBlock;
+} // namespace tint::core::ir
+
namespace tint::core::ir {
-/// An instruction in the IR.
+/// A block parameter in the IR.
class BlockParam : public Castable<BlockParam, Value> {
public:
/// Constructor
- /// @param type the type of the var
+ /// @param type the type of the parameter
explicit BlockParam(const core::type::Type* type);
~BlockParam() override;
- /// @returns the type of the var
+ /// @returns the type of the parameter
const core::type::Type* Type() const override { return type_; }
+ /// Sets the block that this parameter belongs to.
+ /// @param block the block
+ void SetBlock(MultiInBlock* block) { block_ = block; }
+
+ /// @returns the block that this parameter belongs to, or nullptr
+ MultiInBlock* Block() { return block_; }
+
+ /// @returns the block that this parameter belongs to, or nullptr
+ const MultiInBlock* Block() const { return block_; }
+
/// @copydoc Instruction::Clone()
BlockParam* Clone(CloneContext& ctx) override;
private:
- /// the result type of the instruction
+ /// the type of the parameter
const core::type::Type* type_ = nullptr;
+ /// the block that the parameter belongs to
+ MultiInBlock* block_ = nullptr;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/multi_in_block.cc b/src/tint/lang/core/ir/multi_in_block.cc
index c57c622..411d06c 100644
--- a/src/tint/lang/core/ir/multi_in_block.cc
+++ b/src/tint/lang/core/ir/multi_in_block.cc
@@ -55,11 +55,25 @@
}
void MultiInBlock::SetParams(VectorRef<BlockParam*> params) {
+ for (auto* param : params_) {
+ param->SetBlock(nullptr);
+ }
params_ = std::move(params);
+ TINT_ASSERT_OR_RETURN(!params_.Any(IsNull));
+ for (auto* param : params_) {
+ param->SetBlock(this);
+ }
}
void MultiInBlock::SetParams(std::initializer_list<BlockParam*> params) {
+ for (auto* param : params_) {
+ param->SetBlock(nullptr);
+ }
params_ = std::move(params);
+ TINT_ASSERT_OR_RETURN(!params_.Any(IsNull));
+ for (auto* param : params_) {
+ param->SetBlock(this);
+ }
}
void MultiInBlock::AddInboundSiblingBranch(ir::Terminator* node) {
diff --git a/src/tint/lang/core/ir/multi_in_block_test.cc b/src/tint/lang/core/ir/multi_in_block_test.cc
index 790a90e..a377c44 100644
--- a/src/tint/lang/core/ir/multi_in_block_test.cc
+++ b/src/tint/lang/core/ir/multi_in_block_test.cc
@@ -54,7 +54,9 @@
auto* blk = b.MultiInBlock();
auto* add = b.Add(mod.Types().i32(), 1_i, 2_i);
blk->Append(add);
- blk->SetParams({b.BlockParam(mod.Types().i32()), b.BlockParam(mod.Types().f32())});
+ auto* param1 = b.BlockParam(mod.Types().i32());
+ auto* param2 = b.BlockParam(mod.Types().f32());
+ blk->SetParams({param1, param2});
blk->SetParent(loop);
auto* terminate = b.TerminateInvocation();
@@ -75,6 +77,12 @@
EXPECT_NE(add, new_blk->Front());
EXPECT_TRUE(new_blk->Front()->Is<Binary>());
EXPECT_EQ(BinaryOp::kAdd, new_blk->Front()->As<Binary>()->Op());
+
+ // Check parameter ownership is correct.
+ EXPECT_EQ(param1->Block(), blk);
+ EXPECT_EQ(param2->Block(), blk);
+ EXPECT_EQ(new_blk->Params()[0]->Block(), new_blk);
+ EXPECT_EQ(new_blk->Params()[1]->Block(), new_blk);
}
TEST_F(IR_MultiInBlockTest, CloneEmpty) {
@@ -86,5 +94,23 @@
EXPECT_EQ(0u, new_blk->Params().Length());
}
+TEST_F(IR_MultiInBlockTest, Parameters) {
+ auto* blk = b.MultiInBlock();
+
+ auto* param1 = b.BlockParam("a", mod.Types().i32());
+ auto* param2 = b.BlockParam("b", mod.Types().f32());
+ auto* param3 = b.BlockParam("b", mod.Types().f32());
+
+ blk->SetParams({param1, param2});
+ EXPECT_EQ(param1->Block(), blk);
+ EXPECT_EQ(param2->Block(), blk);
+ EXPECT_EQ(param3->Block(), nullptr);
+
+ blk->SetParams({param1, param3});
+ EXPECT_EQ(param1->Block(), blk);
+ EXPECT_EQ(param2->Block(), nullptr);
+ EXPECT_EQ(param3->Block(), blk);
+}
+
} // namespace
} // namespace tint::core::ir