[ir] Track the operand index for value usages
Switch the usage list to be a hashset to allow direct lookup, which
will make it easier to remove specific usages.
Bug: tint:1718
Change-Id: Ie820a2f05aca11046fa5669247c784eaf1bb54c0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/135761
Reviewed-by: Ben Clayton <bclayton@google.com>
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/ir/access_test.cc b/src/tint/ir/access_test.cc
index 68b0306..9e09930 100644
--- a/src/tint/ir/access_test.cc
+++ b/src/tint/ir/access_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/access.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -28,11 +30,8 @@
auto* idx = b.Constant(u32(1));
auto* a = b.Access(mod.Types().i32(), var, utils::Vector{idx});
- EXPECT_EQ(1u, idx->Usage().Length());
- EXPECT_EQ(a, idx->Usage()[0]);
-
- EXPECT_EQ(1u, var->Usage().Length());
- EXPECT_EQ(a, var->Usage()[0]);
+ EXPECT_THAT(var->Usages(), testing::UnorderedElementsAre(Usage{a, 0u}));
+ EXPECT_THAT(idx->Usages(), testing::UnorderedElementsAre(Usage{a, 1u}));
}
TEST_F(IR_AccessTest, Fail_NullType) {
diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc
index 05dd2ff..60fd736 100644
--- a/src/tint/ir/binary_test.cc
+++ b/src/tint/ir/binary_test.cc
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
+#include "src/tint/ir/builder.h"
#include "src/tint/ir/instruction.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -344,29 +346,27 @@
}
TEST_F(IR_BinaryTest, Binary_Usage) {
- const auto* inst = b.And(mod.Types().i32(), b.Constant(4_i), b.Constant(2_i));
+ auto* inst = b.And(mod.Types().i32(), b.Constant(4_i), b.Constant(2_i));
EXPECT_EQ(inst->Kind(), Binary::Kind::kAnd);
ASSERT_NE(inst->LHS(), nullptr);
- ASSERT_EQ(inst->LHS()->Usage().Length(), 1u);
- EXPECT_EQ(inst->LHS()->Usage()[0], inst);
+ EXPECT_THAT(inst->LHS()->Usages(), testing::UnorderedElementsAre(Usage{inst, 0u}));
ASSERT_NE(inst->RHS(), nullptr);
- ASSERT_EQ(inst->RHS()->Usage().Length(), 1u);
- EXPECT_EQ(inst->RHS()->Usage()[0], inst);
+ EXPECT_THAT(inst->RHS()->Usages(), testing::UnorderedElementsAre(Usage{inst, 1u}));
}
TEST_F(IR_BinaryTest, Binary_Usage_DuplicateValue) {
auto val = b.Constant(4_i);
- const auto* inst = b.And(mod.Types().i32(), val, val);
+ auto* inst = b.And(mod.Types().i32(), val, val);
EXPECT_EQ(inst->Kind(), Binary::Kind::kAnd);
ASSERT_EQ(inst->LHS(), inst->RHS());
ASSERT_NE(inst->LHS(), nullptr);
- ASSERT_EQ(inst->LHS()->Usage().Length(), 1u);
- EXPECT_EQ(inst->LHS()->Usage()[0], inst);
+ EXPECT_THAT(inst->LHS()->Usages(),
+ testing::UnorderedElementsAre(Usage{inst, 0u}, Usage{inst, 1u}));
}
} // namespace
diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc
index cab7065..e8ed473 100644
--- a/src/tint/ir/bitcast_test.cc
+++ b/src/tint/ir/bitcast_test.cc
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
+#include "src/tint/ir/builder.h"
#include "src/tint/ir/constant.h"
#include "src/tint/ir/instruction.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -39,13 +41,12 @@
}
TEST_F(IR_BitcastTest, Bitcast_Usage) {
- const auto* inst = b.Bitcast(mod.Types().i32(), b.Constant(4_i));
+ auto* inst = b.Bitcast(mod.Types().i32(), b.Constant(4_i));
const auto args = inst->Args();
ASSERT_EQ(args.Length(), 1u);
ASSERT_NE(args[0], nullptr);
- ASSERT_EQ(args[0]->Usage().Length(), 1u);
- EXPECT_EQ(args[0]->Usage()[0], inst);
+ EXPECT_THAT(args[0]->Usages(), testing::UnorderedElementsAre(Usage{inst, 0u}));
}
TEST_F(IR_BitcastTest, Fail_NullValue) {
diff --git a/src/tint/ir/break_if.cc b/src/tint/ir/break_if.cc
index 7bf61c93..1168c54 100644
--- a/src/tint/ir/break_if.cc
+++ b/src/tint/ir/break_if.cc
@@ -31,7 +31,6 @@
AddOperand(condition);
if (loop_) {
- loop_->AddUsage(this);
loop_->Body()->AddInboundBranch(this);
loop_->Merge()->AddInboundBranch(this);
}
diff --git a/src/tint/ir/break_if_test.cc b/src/tint/ir/break_if_test.cc
index 54827bc..96363f1 100644
--- a/src/tint/ir/break_if_test.cc
+++ b/src/tint/ir/break_if_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/break_if.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -29,15 +31,10 @@
auto* arg2 = b.Constant(2_u);
auto* brk = b.BreakIf(cond, loop, utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, loop->Usage().Length());
- ASSERT_EQ(1u, cond->Usage().Length());
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
- EXPECT_EQ(brk, loop->Usage()[0]);
- EXPECT_EQ(brk, cond->Usage()[0]);
- EXPECT_EQ(brk, arg1->Usage()[0]);
- EXPECT_EQ(brk, arg2->Usage()[0]);
+ EXPECT_THAT(cond->Usages(), testing::UnorderedElementsAre(Usage{brk, 0u}));
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{brk, 1u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{brk, 2u}));
}
TEST_F(IR_BreakIfTest, Fail_NullCondition) {
diff --git a/src/tint/ir/builtin_test.cc b/src/tint/ir/builtin_test.cc
index 13fdb41..d5cf04a 100644
--- a/src/tint/ir/builtin_test.cc
+++ b/src/tint/ir/builtin_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/block_param.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -28,10 +29,8 @@
auto* builtin =
b.Builtin(mod.Types().f32(), builtin::Function::kAbs, utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
- EXPECT_EQ(builtin, arg1->Usage()[0]);
- EXPECT_EQ(builtin, arg2->Usage()[0]);
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{builtin, 0u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{builtin, 1u}));
}
TEST_F(IR_BuiltinTest, Fail_NullType) {
diff --git a/src/tint/ir/construct_test.cc b/src/tint/ir/construct_test.cc
index 9a2f92f..cdab810 100644
--- a/src/tint/ir/construct_test.cc
+++ b/src/tint/ir/construct_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/construct.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -27,10 +29,8 @@
auto* arg2 = b.Constant(false);
auto* c = b.Construct(mod.Types().f32(), utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
- EXPECT_EQ(c, arg1->Usage()[0]);
- EXPECT_EQ(c, arg2->Usage()[0]);
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{c, 0u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{c, 1u}));
}
TEST_F(IR_ConstructTest, Fail_NullType) {
diff --git a/src/tint/ir/continue.cc b/src/tint/ir/continue.cc
index 5e025b9..bf8cbf1 100644
--- a/src/tint/ir/continue.cc
+++ b/src/tint/ir/continue.cc
@@ -27,7 +27,6 @@
TINT_ASSERT(IR, loop_);
if (loop_) {
- loop_->AddUsage(this);
loop_->Continuing()->AddInboundBranch(this);
}
AddOperands(std::move(args));
diff --git a/src/tint/ir/continue_test.cc b/src/tint/ir/continue_test.cc
index 1cba56e..631d696 100644
--- a/src/tint/ir/continue_test.cc
+++ b/src/tint/ir/continue_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/continue.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -28,13 +30,9 @@
auto* arg2 = b.Constant(2_u);
auto* brk = b.Continue(loop, utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, loop->Usage().Length());
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
- EXPECT_EQ(brk, loop->Usage()[0]);
- EXPECT_EQ(brk, arg1->Usage()[0]);
- EXPECT_EQ(brk, arg2->Usage()[0]);
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{brk, 0u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{brk, 1u}));
}
TEST_F(IR_ContinueTest, Fail_NullLoop) {
diff --git a/src/tint/ir/exit_if.cc b/src/tint/ir/exit_if.cc
index f251d45..11cbd74 100644
--- a/src/tint/ir/exit_if.cc
+++ b/src/tint/ir/exit_if.cc
@@ -26,7 +26,6 @@
TINT_ASSERT(IR, if_);
if (if_) {
- if_->AddUsage(this);
if_->Merge()->AddInboundBranch(this);
}
AddOperands(std::move(args));
diff --git a/src/tint/ir/exit_if_test.cc b/src/tint/ir/exit_if_test.cc
index 2383449..13e0cc1 100644
--- a/src/tint/ir/exit_if_test.cc
+++ b/src/tint/ir/exit_if_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/exit_if.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -27,13 +29,9 @@
auto* arg2 = b.Constant(2_u);
auto* if_ = b.CreateIf(b.Constant(true));
auto* e = b.ExitIf(if_, utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
- ASSERT_EQ(1u, if_->Usage().Length());
- EXPECT_EQ(e, arg1->Usage()[0]);
- EXPECT_EQ(e, arg2->Usage()[0]);
- EXPECT_EQ(e, if_->Usage()[0]);
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{e, 0u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{e, 1u}));
}
TEST_F(IR_ExitIfTest, Fail_NullIf) {
diff --git a/src/tint/ir/exit_loop.cc b/src/tint/ir/exit_loop.cc
index 205a458..01b7b8a 100644
--- a/src/tint/ir/exit_loop.cc
+++ b/src/tint/ir/exit_loop.cc
@@ -27,7 +27,6 @@
TINT_ASSERT(IR, loop_);
if (loop_) {
- loop_->AddUsage(this);
loop_->Merge()->AddInboundBranch(this);
}
AddOperands(std::move(args));
diff --git a/src/tint/ir/exit_loop_test.cc b/src/tint/ir/exit_loop_test.cc
index 9a66ccc..11a6b28 100644
--- a/src/tint/ir/exit_loop_test.cc
+++ b/src/tint/ir/exit_loop_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/exit_loop.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -27,13 +29,9 @@
auto* arg2 = b.Constant(2_u);
auto* loop = b.CreateLoop();
auto* e = b.ExitLoop(loop, utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
- ASSERT_EQ(1u, loop->Usage().Length());
- EXPECT_EQ(e, arg1->Usage()[0]);
- EXPECT_EQ(e, arg2->Usage()[0]);
- EXPECT_EQ(e, loop->Usage()[0]);
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{e, 0u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{e, 1u}));
}
TEST_F(IR_ExitLoopTest, Fail_NullLoop) {
diff --git a/src/tint/ir/exit_switch.cc b/src/tint/ir/exit_switch.cc
index 6689742..f63e791 100644
--- a/src/tint/ir/exit_switch.cc
+++ b/src/tint/ir/exit_switch.cc
@@ -27,7 +27,6 @@
TINT_ASSERT(IR, switch_);
if (switch_) {
- switch_->AddUsage(this);
switch_->Merge()->AddInboundBranch(this);
}
AddOperands(std::move(args));
diff --git a/src/tint/ir/exit_switch_test.cc b/src/tint/ir/exit_switch_test.cc
index abdd433..945bb5c 100644
--- a/src/tint/ir/exit_switch_test.cc
+++ b/src/tint/ir/exit_switch_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/exit_switch.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -27,13 +29,9 @@
auto* arg2 = b.Constant(2_u);
auto* switch_ = b.CreateSwitch(b.Constant(true));
auto* e = b.ExitSwitch(switch_, utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
- ASSERT_EQ(1u, switch_->Usage().Length());
- EXPECT_EQ(e, arg1->Usage()[0]);
- EXPECT_EQ(e, arg2->Usage()[0]);
- EXPECT_EQ(e, switch_->Usage()[0]);
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{e, 0u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{e, 1u}));
}
TEST_F(IR_ExitSwitchTest, Fail_NullSwitch) {
diff --git a/src/tint/ir/if_test.cc b/src/tint/ir/if_test.cc
index d83d062..27f1df7 100644
--- a/src/tint/ir/if_test.cc
+++ b/src/tint/ir/if_test.cc
@@ -13,6 +13,7 @@
// limitations under the License.
#include "src/tint/ir/if.h"
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -25,8 +26,7 @@
TEST_F(IR_IfTest, Usage) {
auto* cond = b.Constant(true);
auto* if_ = b.CreateIf(cond);
- ASSERT_EQ(1u, cond->Usage().Length());
- EXPECT_EQ(if_, cond->Usage()[0]);
+ EXPECT_THAT(cond->Usages(), testing::UnorderedElementsAre(Usage{if_, 0u}));
}
TEST_F(IR_IfTest, Fail_NullCondition) {
diff --git a/src/tint/ir/load_test.cc b/src/tint/ir/load_test.cc
index 440eabf..ad21d13 100644
--- a/src/tint/ir/load_test.cc
+++ b/src/tint/ir/load_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/builder.h"
#include "src/tint/ir/instruction.h"
@@ -24,7 +25,7 @@
using IR_LoadTest = IRTestHelper;
-TEST_F(IR_LoadTest, Creat) {
+TEST_F(IR_LoadTest, Create) {
auto* store_type = mod.Types().i32();
auto* var = b.Declare(mod.Types().pointer(store_type, builtin::AddressSpace::kFunction,
builtin::Access::kReadWrite));
@@ -43,11 +44,10 @@
auto* store_type = mod.Types().i32();
auto* var = b.Declare(mod.Types().pointer(store_type, builtin::AddressSpace::kFunction,
builtin::Access::kReadWrite));
- const auto* inst = b.Load(var);
+ auto* inst = b.Load(var);
ASSERT_NE(inst->From(), nullptr);
- ASSERT_EQ(inst->From()->Usage().Length(), 1u);
- EXPECT_EQ(inst->From()->Usage()[0], inst);
+ EXPECT_THAT(inst->From()->Usages(), testing::UnorderedElementsAre(Usage{inst, 0u}));
}
TEST_F(IR_LoadTest, Fail_NullType) {
diff --git a/src/tint/ir/next_iteration.cc b/src/tint/ir/next_iteration.cc
index 8e4b1e2..0d18617 100644
--- a/src/tint/ir/next_iteration.cc
+++ b/src/tint/ir/next_iteration.cc
@@ -27,7 +27,6 @@
TINT_ASSERT(IR, loop_);
if (loop_) {
- loop_->AddUsage(this);
loop_->Body()->AddInboundBranch(this);
}
AddOperands(std::move(args));
diff --git a/src/tint/ir/operand_instruction.h b/src/tint/ir/operand_instruction.h
index b60d753..3e8dad3 100644
--- a/src/tint/ir/operand_instruction.h
+++ b/src/tint/ir/operand_instruction.h
@@ -31,7 +31,7 @@
/// @param value the operand value to append
void AddOperand(ir::Value* value) {
if (value) {
- value->AddUsage(this);
+ value->AddUsage({this, static_cast<uint32_t>(operands_.Length())});
}
operands_.Push(value);
}
diff --git a/src/tint/ir/return.cc b/src/tint/ir/return.cc
index f70af84..73bcde0 100644
--- a/src/tint/ir/return.cc
+++ b/src/tint/ir/return.cc
@@ -26,7 +26,7 @@
TINT_ASSERT(IR, func_);
if (func_) {
- func_->AddUsage(this);
+ func_->AddUsage({this, 0u});
}
AddOperands(std::move(args));
}
diff --git a/src/tint/ir/store_test.cc b/src/tint/ir/store_test.cc
index f323612..a28ecad 100644
--- a/src/tint/ir/store_test.cc
+++ b/src/tint/ir/store_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/builder.h"
#include "src/tint/ir/instruction.h"
@@ -40,15 +41,13 @@
TEST_F(IR_StoreTest, Store_Usage) {
auto* to = b.Discard();
- const auto* inst = b.Store(to, b.Constant(4_i));
+ auto* inst = b.Store(to, b.Constant(4_i));
ASSERT_NE(inst->To(), nullptr);
- ASSERT_EQ(inst->To()->Usage().Length(), 1u);
- EXPECT_EQ(inst->To()->Usage()[0], inst);
+ EXPECT_THAT(inst->To()->Usages(), testing::UnorderedElementsAre(Usage{inst, 0u}));
ASSERT_NE(inst->From(), nullptr);
- ASSERT_EQ(inst->From()->Usage().Length(), 1u);
- EXPECT_EQ(inst->From()->Usage()[0], inst);
+ EXPECT_THAT(inst->From()->Usages(), testing::UnorderedElementsAre(Usage{inst, 1u}));
}
TEST_F(IR_StoreTest, Fail_NullTo) {
diff --git a/src/tint/ir/switch_test.cc b/src/tint/ir/switch_test.cc
index 4d1a0ec..3ea47fb 100644
--- a/src/tint/ir/switch_test.cc
+++ b/src/tint/ir/switch_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/switch.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -24,9 +26,8 @@
TEST_F(IR_SwitchTest, Usage) {
auto* cond = b.Constant(true);
- auto* if_ = b.CreateSwitch(cond);
- ASSERT_EQ(1u, cond->Usage().Length());
- EXPECT_EQ(if_, cond->Usage()[0]);
+ auto* switch_ = b.CreateSwitch(cond);
+ EXPECT_THAT(cond->Usages(), testing::UnorderedElementsAre(Usage{switch_, 0u}));
}
TEST_F(IR_SwitchTest, Fail_NullCondition) {
diff --git a/src/tint/ir/swizzle_test.cc b/src/tint/ir/swizzle_test.cc
index 0aa3bbb..64df5c6 100644
--- a/src/tint/ir/swizzle_test.cc
+++ b/src/tint/ir/swizzle_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/swizzle.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -27,8 +29,7 @@
auto* var = b.Declare(ty);
auto* a = b.Swizzle(mod.Types().i32(), var, utils::Vector{1u});
- EXPECT_EQ(1u, var->Usage().Length());
- EXPECT_EQ(a, var->Usage()[0]);
+ EXPECT_THAT(var->Usages(), testing::UnorderedElementsAre(Usage{a, 0u}));
}
TEST_F(IR_SwizzleTest, Fail_NullType) {
diff --git a/src/tint/ir/to_program.cc b/src/tint/ir/to_program.cc
index 5ecf7d5..b226236 100644
--- a/src/tint/ir/to_program.cc
+++ b/src/tint/ir/to_program.cc
@@ -322,7 +322,7 @@
// of usage. Currently a value is inlined if it has a single usage and is unnamed.
// TODO(crbug.com/tint/1902): This logic needs to check that the sequence of side-effecting
// expressions is not changed by inlining the expression. This needs fixing.
- bool create_let = val->Usage().Length() > 1 || mod.NameOf(val).IsValid();
+ bool create_let = val->Usages().Count() > 1 || mod.NameOf(val).IsValid();
if (create_let) {
auto* init = Expr(val); // Must come before giving the value a name
auto name = AssignNameTo(val);
diff --git a/src/tint/ir/unary_test.cc b/src/tint/ir/unary_test.cc
index 2803527..2f2307e 100644
--- a/src/tint/ir/unary_test.cc
+++ b/src/tint/ir/unary_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/builder.h"
#include "src/tint/ir/instruction.h"
@@ -54,8 +55,7 @@
EXPECT_EQ(inst->Kind(), Unary::Kind::kNegation);
ASSERT_NE(inst->Val(), nullptr);
- ASSERT_EQ(inst->Val()->Usage().Length(), 1u);
- EXPECT_EQ(inst->Val()->Usage()[0], inst);
+ EXPECT_THAT(inst->Val()->Usages(), testing::UnorderedElementsAre(Usage{inst, 0u}));
}
TEST_F(IR_UnaryTest, Fail_NullType) {
diff --git a/src/tint/ir/user_call_test.cc b/src/tint/ir/user_call_test.cc
index 8e989a5..2fd9151 100644
--- a/src/tint/ir/user_call_test.cc
+++ b/src/tint/ir/user_call_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/user_call.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -23,15 +25,13 @@
using IR_UserCallTest = IRTestHelper;
TEST_F(IR_UserCallTest, Usage) {
+ auto* func = b.CreateFunction("myfunc", mod.Types().void_());
auto* arg1 = b.Constant(1_u);
auto* arg2 = b.Constant(2_u);
- auto* e = b.UserCall(mod.Types().void_(), b.CreateFunction("myfunc", mod.Types().void_()),
- utils::Vector{arg1, arg2});
- ASSERT_EQ(1u, arg1->Usage().Length());
- ASSERT_EQ(1u, arg2->Usage().Length());
-
- EXPECT_EQ(e, arg1->Usage()[0]);
- EXPECT_EQ(e, arg2->Usage()[0]);
+ auto* e = b.UserCall(mod.Types().void_(), func, utils::Vector{arg1, arg2});
+ EXPECT_THAT(func->Usages(), testing::UnorderedElementsAre(Usage{e, 0u}));
+ EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{e, 1u}));
+ EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{e, 2u}));
}
TEST_F(IR_UserCallTest, Fail_NullType) {
diff --git a/src/tint/ir/value.h b/src/tint/ir/value.h
index b090ad8..6311691 100644
--- a/src/tint/ir/value.h
+++ b/src/tint/ir/value.h
@@ -17,7 +17,7 @@
#include "src/tint/type/type.h"
#include "src/tint/utils/castable.h"
-#include "src/tint/utils/unique_vector.h"
+#include "src/tint/utils/hashset.h"
// Forward declarations
namespace tint::ir {
@@ -26,19 +26,43 @@
namespace tint::ir {
+/// A specific usage of a Value in the IR.
+struct Usage {
+ /// The instruction that is using the value;
+ Instruction* instruction = nullptr;
+ /// The index of the operand that is the value being used.
+ uint32_t operand_index = 0u;
+
+ /// A specialization of utils::Hasher for Usage.
+ struct Hasher {
+ /// @param u the usage to hash
+ /// @returns a hash of the usage
+ inline std::size_t operator()(const Usage& u) const {
+ return utils::Hash(u.instruction, u.operand_index);
+ }
+ };
+
+ /// An equality helper for Usage.
+ /// @param other the usage to compare against
+ /// @returns true if the two usages are equal
+ bool operator==(const Usage& other) const {
+ return instruction == other.instruction && operand_index == other.operand_index;
+ }
+};
+
/// Value in the IR.
class Value : public utils::Castable<Value> {
public:
/// Destructor
~Value() override;
- /// Adds an instruction which uses this value.
- /// @param inst the instruction
- void AddUsage(const Instruction* inst) { uses_.Add(inst); }
+ /// Adds a usage of this value.
+ /// @param u the usage
+ void AddUsage(Usage u) { uses_.Add(u); }
- /// @returns the vector of instructions which use this value. An instruction will only be
- /// returned once even if that instruction uses the given value multiple times.
- utils::VectorRef<const Instruction*> Usage() const { return uses_; }
+ /// @returns the set of usages of this value. An instruction may appear multiple times if it
+ /// uses the value for multiple different operands.
+ const utils::Hashset<Usage, 4, Usage::Hasher>& Usages() const { return uses_; }
/// @returns the type of the value
virtual const type::Type* Type() const { return nullptr; }
@@ -48,9 +72,8 @@
Value();
private:
- utils::UniqueVector<const Instruction*, 4> uses_;
+ utils::Hashset<Usage, 4, Usage::Hasher> uses_;
};
-
} // namespace tint::ir
#endif // SRC_TINT_IR_VALUE_H_
diff --git a/src/tint/ir/var.cc b/src/tint/ir/var.cc
index 6ebe53f..218d512 100644
--- a/src/tint/ir/var.cc
+++ b/src/tint/ir/var.cc
@@ -31,7 +31,7 @@
void Var::SetInitializer(Value* initializer) {
operands_[0] = initializer;
if (initializer) {
- initializer->AddUsage(this);
+ initializer->AddUsage({this, 0u});
}
// TODO(dsinclair): Probably should do a RemoveUsage on an existing initializer if set
}
diff --git a/src/tint/ir/var_test.cc b/src/tint/ir/var_test.cc
index 92a2c3c..43b1767 100644
--- a/src/tint/ir/var_test.cc
+++ b/src/tint/ir/var_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "src/tint/ir/var.h"
+
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ir/ir_test_helper.h"
@@ -39,8 +41,7 @@
auto* init = b.Constant(1_f);
var->SetInitializer(init);
- ASSERT_EQ(1u, init->Usage().Length());
- EXPECT_EQ(var, init->Usage()[0]);
+ EXPECT_THAT(init->Usages(), testing::UnorderedElementsAre(Usage{var, 0u}));
}
} // namespace