From afd7f2aa21719374eee8a8201b2e4357b49c046d Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Tue, 3 Jan 2023 21:55:36 +0000 Subject: [PATCH] [ir] Add usage tracking to ir::Value. This CL updates ir:Value to track the instructions which use a given value. The instructions add their usage upon construction. This necessitates making the values non-const in a lot of places as they get changed by the instruction. The `result` value is moved up to the base instruction class as it should exist in all instructions. Bug: tint:1718 Change-Id: Id7ab6e43d48caea502756d274dd6be2e1e4240f1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116141 Commit-Queue: Dan Sinclair Reviewed-by: Ben Clayton Kokoro: Kokoro --- src/tint/ir/binary.cc | 7 +- src/tint/ir/binary.h | 11 +- src/tint/ir/binary_test.cc | 43 +++ src/tint/ir/bitcast.cc | 4 +- src/tint/ir/bitcast.h | 9 +- src/tint/ir/bitcast_test.cc | 16 + src/tint/ir/builder.cc | 45 ++- src/tint/ir/builder.h | 57 ++-- src/tint/ir/builder_impl.cc | 16 +- src/tint/ir/builder_impl.h | 8 +- src/tint/ir/instruction.cc | 5 +- src/tint/ir/instruction.h | 10 +- src/tint/ir/instruction_test.cc | 499 -------------------------------- src/tint/ir/value.h | 17 ++ 14 files changed, 159 insertions(+), 588 deletions(-) delete mode 100644 src/tint/ir/instruction_test.cc diff --git a/src/tint/ir/binary.cc b/src/tint/ir/binary.cc index ccb679b736..e48ca86565 100644 --- a/src/tint/ir/binary.cc +++ b/src/tint/ir/binary.cc @@ -19,11 +19,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Binary); namespace tint::ir { -Binary::Binary(Kind kind, const Value* result, const Value* lhs, const Value* rhs) - : kind_(kind), result_(result), lhs_(lhs), rhs_(rhs) { - TINT_ASSERT(IR, result_); +Binary::Binary(Kind kind, Value* result, Value* lhs, Value* rhs) + : Base(result), kind_(kind), lhs_(lhs), rhs_(rhs) { TINT_ASSERT(IR, lhs_); TINT_ASSERT(IR, rhs_); + lhs_->AddUsage(this); + rhs_->AddUsage(this); } Binary::~Binary() = default; diff --git a/src/tint/ir/binary.h b/src/tint/ir/binary.h index c2df24ef54..85ad9dc9cb 100644 --- a/src/tint/ir/binary.h +++ b/src/tint/ir/binary.h @@ -19,7 +19,6 @@ #include "src/tint/castable.h" #include "src/tint/ir/instruction.h" -#include "src/tint/ir/value.h" #include "src/tint/symbol_table.h" #include "src/tint/type/type.h" @@ -59,7 +58,7 @@ class Binary : public Castable { /// @param result the result value /// @param lhs the lhs of the instruction /// @param rhs the rhs of the instruction - Binary(Kind kind, const Value* result, const Value* lhs, const Value* rhs); + Binary(Kind kind, Value* result, Value* lhs, Value* rhs); Binary(const Binary& instr) = delete; Binary(Binary&& instr) = delete; ~Binary() override; @@ -70,9 +69,6 @@ class Binary : public Castable { /// @returns the kind of instruction Kind GetKind() const { return kind_; } - /// @returns the result value for the instruction - const Value* Result() const { return result_; } - /// @returns the left-hand-side value for the instruction const Value* LHS() const { return lhs_; } @@ -87,9 +83,8 @@ class Binary : public Castable { private: Kind kind_; - const Value* result_ = nullptr; - const Value* lhs_ = nullptr; - const Value* rhs_ = nullptr; + Value* lhs_ = nullptr; + Value* rhs_ = nullptr; }; std::ostream& operator<<(std::ostream& out, const Binary&); diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc index 05d70651ee..f23487917a 100644 --- a/src/tint/ir/binary_test.cc +++ b/src/tint/ir/binary_test.cc @@ -511,5 +511,48 @@ TEST_F(IR_InstructionTest, CreateModulo) { EXPECT_EQ(str.str(), "%42 (i32) = 4 % 2"); } +TEST_F(IR_InstructionTest, Binary_Usage) { + auto& b = CreateEmptyBuilder(); + + b.builder.next_temp_id = Temp::Id(42); + const auto* instr = b.builder.And(b.builder.ir.types.Get(), b.builder.Constant(4_i), + b.builder.Constant(2_i)); + + EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd); + + ASSERT_NE(instr->Result(), nullptr); + ASSERT_EQ(instr->Result()->Usage().Length(), 1); + EXPECT_EQ(instr->Result()->Usage()[0], instr); + + ASSERT_NE(instr->LHS(), nullptr); + ASSERT_EQ(instr->LHS()->Usage().Length(), 1); + EXPECT_EQ(instr->LHS()->Usage()[0], instr); + + ASSERT_NE(instr->RHS(), nullptr); + ASSERT_EQ(instr->RHS()->Usage().Length(), 1); + EXPECT_EQ(instr->RHS()->Usage()[0], instr); +} + +TEST_F(IR_InstructionTest, Binary_Usage_DuplicateValue) { + auto& b = CreateEmptyBuilder(); + + auto val = b.builder.Constant(4_i); + + b.builder.next_temp_id = Temp::Id(42); + const auto* instr = b.builder.And(b.builder.ir.types.Get(), val, val); + + EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd); + + ASSERT_NE(instr->Result(), nullptr); + ASSERT_EQ(instr->Result()->Usage().Length(), 1); + EXPECT_EQ(instr->Result()->Usage()[0], instr); + + ASSERT_EQ(instr->LHS(), instr->RHS()); + + ASSERT_NE(instr->LHS(), nullptr); + ASSERT_EQ(instr->LHS()->Usage().Length(), 1); + EXPECT_EQ(instr->LHS()->Usage()[0], instr); +} + } // namespace } // namespace tint::ir diff --git a/src/tint/ir/bitcast.cc b/src/tint/ir/bitcast.cc index 7ea2b7ff36..512d93accf 100644 --- a/src/tint/ir/bitcast.cc +++ b/src/tint/ir/bitcast.cc @@ -19,9 +19,9 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Bitcast); namespace tint::ir { -Bitcast::Bitcast(const Value* result, const Value* val) : result_(result), val_(val) { - TINT_ASSERT(IR, result_); +Bitcast::Bitcast(Value* result, Value* val) : Base(result), val_(val) { TINT_ASSERT(IR, val_); + val_->AddUsage(this); } Bitcast::~Bitcast() = default; diff --git a/src/tint/ir/bitcast.h b/src/tint/ir/bitcast.h index 56b9651697..df8a05e1b0 100644 --- a/src/tint/ir/bitcast.h +++ b/src/tint/ir/bitcast.h @@ -19,7 +19,6 @@ #include "src/tint/castable.h" #include "src/tint/ir/instruction.h" -#include "src/tint/ir/value.h" #include "src/tint/symbol_table.h" #include "src/tint/type/type.h" @@ -31,7 +30,7 @@ class Bitcast : public Castable { /// Constructor /// @param result the result value /// @param val the value being bitcast - Bitcast(const Value* result, const Value* val); + Bitcast(Value* result, Value* val); Bitcast(const Bitcast& instr) = delete; Bitcast(Bitcast&& instr) = delete; ~Bitcast() override; @@ -39,9 +38,6 @@ class Bitcast : public Castable { Bitcast& operator=(const Bitcast& instr) = delete; Bitcast& operator=(Bitcast&& instr) = delete; - /// @returns the result value for the instruction - const Value* Result() const { return result_; } - /// @returns the left-hand-side value for the instruction const Value* Val() const { return val_; } @@ -52,8 +48,7 @@ class Bitcast : public Castable { std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override; private: - const Value* result_ = nullptr; - const Value* val_ = nullptr; + Value* val_ = nullptr; }; std::ostream& operator<<(std::ostream& out, const Bitcast&); diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc index 3b5cecdd52..91c5c4bd5e 100644 --- a/src/tint/ir/bitcast_test.cc +++ b/src/tint/ir/bitcast_test.cc @@ -45,5 +45,21 @@ TEST_F(IR_InstructionTest, Bitcast) { EXPECT_EQ(str.str(), "%42 (i32) = bitcast(4)"); } +TEST_F(IR_InstructionTest, Bitcast_Usage) { + auto& b = CreateEmptyBuilder(); + + b.builder.next_temp_id = Temp::Id(42); + const auto* instr = + b.builder.Bitcast(b.builder.ir.types.Get(), b.builder.Constant(4_i)); + + ASSERT_NE(instr->Result(), nullptr); + ASSERT_EQ(instr->Result()->Usage().Length(), 1); + EXPECT_EQ(instr->Result()->Usage()[0], instr); + + ASSERT_NE(instr->Val(), nullptr); + ASSERT_EQ(instr->Val()->Usage().Length(), 1); + EXPECT_EQ(instr->Val()->Usage()[0], instr); +} + } // namespace } // namespace tint::ir diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc index ba0ed9e038..e65c2fc3ec 100644 --- a/src/tint/ir/builder.cc +++ b/src/tint/ir/builder.cc @@ -97,88 +97,83 @@ Temp::Id Builder::AllocateTempId() { return next_temp_id++; } -const Binary* Builder::CreateBinary(Binary::Kind kind, - const type::Type* type, - const Value* lhs, - const Value* rhs) { +Binary* Builder::CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs) { return ir.instructions.Create(kind, Temp(type), lhs, rhs); } -const Binary* Builder::And(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::And(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kAnd, type, lhs, rhs); } -const Binary* Builder::Or(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Or(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kOr, type, lhs, rhs); } -const Binary* Builder::Xor(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Xor(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kXor, type, lhs, rhs); } -const Binary* Builder::LogicalAnd(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::LogicalAnd(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kLogicalAnd, type, lhs, rhs); } -const Binary* Builder::LogicalOr(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::LogicalOr(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kLogicalOr, type, lhs, rhs); } -const Binary* Builder::Equal(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Equal(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kEqual, type, lhs, rhs); } -const Binary* Builder::NotEqual(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::NotEqual(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kNotEqual, type, lhs, rhs); } -const Binary* Builder::LessThan(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::LessThan(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kLessThan, type, lhs, rhs); } -const Binary* Builder::GreaterThan(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::GreaterThan(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kGreaterThan, type, lhs, rhs); } -const Binary* Builder::LessThanEqual(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::LessThanEqual(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kLessThanEqual, type, lhs, rhs); } -const Binary* Builder::GreaterThanEqual(const type::Type* type, - const Value* lhs, - const Value* rhs) { +Binary* Builder::GreaterThanEqual(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kGreaterThanEqual, type, lhs, rhs); } -const Binary* Builder::ShiftLeft(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::ShiftLeft(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kShiftLeft, type, lhs, rhs); } -const Binary* Builder::ShiftRight(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::ShiftRight(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kShiftRight, type, lhs, rhs); } -const Binary* Builder::Add(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Add(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kAdd, type, lhs, rhs); } -const Binary* Builder::Subtract(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Subtract(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kSubtract, type, lhs, rhs); } -const Binary* Builder::Multiply(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Multiply(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kMultiply, type, lhs, rhs); } -const Binary* Builder::Divide(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Divide(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kDivide, type, lhs, rhs); } -const Binary* Builder::Modulo(const type::Type* type, const Value* lhs, const Value* rhs) { +Binary* Builder::Modulo(const type::Type* type, Value* lhs, Value* rhs) { return CreateBinary(Binary::Kind::kModulo, type, lhs, rhs); } -const ir::Bitcast* Builder::Bitcast(const type::Type* type, const Value* val) { +ir::Bitcast* Builder::Bitcast(const type::Type* type, Value* val) { return ir.instructions.Create(Temp(type), val); } diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h index 7f442f2159..ad9e2e1454 100644 --- a/src/tint/ir/builder.h +++ b/src/tint/ir/builder.h @@ -105,49 +105,49 @@ class Builder { /// Creates a new ir::Constant /// @param val the constant value /// @returns the new constant - const ir::Constant* Constant(const constant::Value* val) { + ir::Constant* Constant(const constant::Value* val) { return ir.values.Create(val); } /// Creates a ir::Constant for an i32 Scalar /// @param v the value /// @returns the new constant - const ir::Constant* Constant(i32 v) { + ir::Constant* Constant(i32 v) { return Constant(create>(ir.types.Get(), v)); } /// Creates a ir::Constant for a u32 Scalar /// @param v the value /// @returns the new constant - const ir::Constant* Constant(u32 v) { + ir::Constant* Constant(u32 v) { return Constant(create>(ir.types.Get(), v)); } /// Creates a ir::Constant for a f32 Scalar /// @param v the value /// @returns the new constant - const ir::Constant* Constant(f32 v) { + ir::Constant* Constant(f32 v) { return Constant(create>(ir.types.Get(), v)); } /// Creates a ir::Constant for a f16 Scalar /// @param v the value /// @returns the new constant - const ir::Constant* Constant(f16 v) { + ir::Constant* Constant(f16 v) { return Constant(create>(ir.types.Get(), v)); } /// Creates a ir::Constant for a bool Scalar /// @param v the value /// @returns the new constant - const ir::Constant* Constant(bool v) { + ir::Constant* Constant(bool v) { return Constant(create>(ir.types.Get(), v)); } /// Creates a new Temporary /// @param type the type of the temporary /// @returns the new temporary - const ir::Temp* Temp(const type::Type* type) { + ir::Temp* Temp(const type::Type* type) { return ir.values.Create(type, AllocateTempId()); } @@ -157,142 +157,139 @@ class Builder { /// @param lhs the left-hand-side of the operation /// @param rhs the right-hand-side of the operation /// @returns the operation - const Binary* CreateBinary(Binary::Kind kind, - const type::Type* type, - const Value* lhs, - const Value* rhs); + Binary* CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs); /// Creates an And operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* And(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* And(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Or operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Or(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Or(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Xor operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Xor(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Xor(const type::Type* type, Value* lhs, Value* rhs); /// Creates an LogicalAnd operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* LogicalAnd(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* LogicalAnd(const type::Type* type, Value* lhs, Value* rhs); /// Creates an LogicalOr operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* LogicalOr(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* LogicalOr(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Equal operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Equal(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Equal(const type::Type* type, Value* lhs, Value* rhs); /// Creates an NotEqual operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* NotEqual(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* NotEqual(const type::Type* type, Value* lhs, Value* rhs); /// Creates an LessThan operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* LessThan(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* LessThan(const type::Type* type, Value* lhs, Value* rhs); /// Creates an GreaterThan operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* GreaterThan(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* GreaterThan(const type::Type* type, Value* lhs, Value* rhs); /// Creates an LessThanEqual operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* LessThanEqual(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* LessThanEqual(const type::Type* type, Value* lhs, Value* rhs); /// Creates an GreaterThanEqual operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* GreaterThanEqual(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* GreaterThanEqual(const type::Type* type, Value* lhs, Value* rhs); /// Creates an ShiftLeft operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* ShiftLeft(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* ShiftLeft(const type::Type* type, Value* lhs, Value* rhs); /// Creates an ShiftRight operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* ShiftRight(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* ShiftRight(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Add operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Add(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Add(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Subtract operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Subtract(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Subtract(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Multiply operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Multiply(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Multiply(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Divide operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Divide(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Divide(const type::Type* type, Value* lhs, Value* rhs); /// Creates an Modulo operation /// @param type the result type of the expression /// @param lhs the lhs of the add /// @param rhs the rhs of the add /// @returns the operation - const Binary* Modulo(const type::Type* type, const Value* lhs, const Value* rhs); + Binary* Modulo(const type::Type* type, Value* lhs, Value* rhs); /// Creates a bitcast instruction /// @param type the result type of the bitcast /// @param val the value being bitcast /// @returns the instruction - const ir::Bitcast* Bitcast(const type::Type* type, const Value* val); + ir::Bitcast* Bitcast(const type::Type* type, Value* val); /// @returns a unique temp id Temp::Id AllocateTempId(); diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc index 115b6d7d79..517e09b58f 100644 --- a/src/tint/ir/builder_impl.cc +++ b/src/tint/ir/builder_impl.cc @@ -518,7 +518,7 @@ bool BuilderImpl::EmitBreakIf(const ast::BreakIfStatement* stmt) { return true; } -utils::Result BuilderImpl::EmitExpression(const ast::Expression* expr) { +utils::Result BuilderImpl::EmitExpression(const ast::Expression* expr) { return tint::Switch( expr, // [&](const ast::IndexAccessorExpression* a) { return EmitIndexAccessor(a); }, @@ -553,7 +553,7 @@ bool BuilderImpl::EmitVariable(const ast::Variable* var) { }); } -utils::Result BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) { +utils::Result BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) { auto lhs = EmitExpression(expr->lhs); if (!lhs) { return utils::Failure; @@ -565,7 +565,7 @@ utils::Result BuilderImpl::EmitBinary(const ast::BinaryExpression* } auto* sem = builder.ir.program->Sem().Get(expr); - const Binary* instr = nullptr; + Binary* instr = nullptr; switch (expr->op) { case ast::BinaryOp::kAnd: instr = builder.And(sem->Type(), lhs.Get(), rhs.Get()); @@ -627,10 +627,10 @@ utils::Result BuilderImpl::EmitBinary(const ast::BinaryExpression* } current_flow_block->instructions.Push(instr); - return utils::Result(instr->Result()); + return instr->Result(); } -utils::Result BuilderImpl::EmitBitcast(const ast::BitcastExpression* expr) { +utils::Result BuilderImpl::EmitBitcast(const ast::BitcastExpression* expr) { auto val = EmitExpression(expr->expr); if (!val) { return utils::Failure; @@ -640,10 +640,10 @@ utils::Result BuilderImpl::EmitBitcast(const ast::BitcastExpressio auto* instr = builder.Bitcast(sem->Type(), val.Get()); current_flow_block->instructions.Push(instr); - return utils::Result(instr->Result()); + return instr->Result(); } -utils::Result BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) { +utils::Result BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) { auto* sem = builder.ir.program->Sem().Get(lit); if (!sem) { diagnostics_.add_error( @@ -661,7 +661,7 @@ utils::Result BuilderImpl::EmitLiteral(const ast::LiteralExpressio lit->source); return utils::Failure; } - return utils::Result(builder.Constant(cv)); + return builder.Constant(cv); } bool BuilderImpl::EmitType(const ast::Type* ty) { diff --git a/src/tint/ir/builder_impl.h b/src/tint/ir/builder_impl.h index 35476ebeca..5d6fbd76c0 100644 --- a/src/tint/ir/builder_impl.h +++ b/src/tint/ir/builder_impl.h @@ -141,7 +141,7 @@ class BuilderImpl { /// Emits an expression /// @param expr the expression to emit /// @returns true if successful, false otherwise - utils::Result EmitExpression(const ast::Expression* expr); + utils::Result EmitExpression(const ast::Expression* expr); /// Emits a variable /// @param var the variable to emit @@ -151,17 +151,17 @@ class BuilderImpl { /// Emits a binary expression /// @param expr the binary expression /// @returns the value storing the result if successful, utils::Failure otherwise - utils::Result EmitBinary(const ast::BinaryExpression* expr); + utils::Result EmitBinary(const ast::BinaryExpression* expr); /// Emits a bitcast expression /// @param expr the bitcast expression /// @returns the value storing the result if successful, utils::Failure otherwise - utils::Result EmitBitcast(const ast::BitcastExpression* expr); + utils::Result EmitBitcast(const ast::BitcastExpression* expr); /// Emits a literal expression /// @param lit the literal to emit /// @returns true if successful, false otherwise - utils::Result EmitLiteral(const ast::LiteralExpression* lit); + utils::Result EmitLiteral(const ast::LiteralExpression* lit); /// Emits a type /// @param ty the type to emit diff --git a/src/tint/ir/instruction.cc b/src/tint/ir/instruction.cc index e54b13ff3e..46644dd5b8 100644 --- a/src/tint/ir/instruction.cc +++ b/src/tint/ir/instruction.cc @@ -18,7 +18,10 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Instruction); namespace tint::ir { -Instruction::Instruction() = default; +Instruction::Instruction(Value* result) : result_(result) { + TINT_ASSERT(IR, result_); + result_->AddUsage(this); +} Instruction::~Instruction() = default; diff --git a/src/tint/ir/instruction.h b/src/tint/ir/instruction.h index 82842ba37a..8cd9ba87ac 100644 --- a/src/tint/ir/instruction.h +++ b/src/tint/ir/instruction.h @@ -18,6 +18,7 @@ #include #include "src/tint/castable.h" +#include "src/tint/ir/value.h" #include "src/tint/symbol_table.h" namespace tint::ir { @@ -33,6 +34,9 @@ class Instruction : public Castable { Instruction& operator=(const Instruction& instr) = delete; Instruction& operator=(Instruction&& instr) = delete; + /// @returns the result value for the instruction + Value* Result() const { return result_; } + /// Write the instruction to the given stream /// @param out the stream to write to /// @param st the symbol table @@ -41,7 +45,11 @@ class Instruction : public Castable { protected: /// Constructor - Instruction(); + /// @param result the result value + explicit Instruction(Value* result); + + private: + Value* result_ = nullptr; }; } // namespace tint::ir diff --git a/src/tint/ir/instruction_test.cc b/src/tint/ir/instruction_test.cc deleted file mode 100644 index c9307f0f23..0000000000 --- a/src/tint/ir/instruction_test.cc +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright 2022 The Tint Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "src/tint/ir/instruction.h" -#include "src/tint/ir/test_helper.h" - -namespace tint::ir { -namespace { - -using IR_BinaryTest = TestHelper; - -TEST_F(IR_BinaryTest, CreateAnd) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.And(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kAnd); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 & 2"); -} - -TEST_F(IR_BinaryTest, CreateOr) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Or(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kOr); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 | 2"); -} - -TEST_F(IR_BinaryTest, CreateXor) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Xor(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kXor); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 ^ 2"); -} - -TEST_F(IR_BinaryTest, CreateLogicalAnd) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = - b.builder.LogicalAnd(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLogicalAnd); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 && 2"); -} - -TEST_F(IR_BinaryTest, CreateLogicalOr) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.LogicalOr(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLogicalOr); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 || 2"); -} - -TEST_F(IR_BinaryTest, CreateEqual) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Equal(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kEqual); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 == 2"); -} - -TEST_F(IR_BinaryTest, CreateNotEqual) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.NotEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kNotEqual); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 != 2"); -} - -TEST_F(IR_BinaryTest, CreateLessThan) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.LessThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLessThan); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 < 2"); -} - -TEST_F(IR_BinaryTest, CreateGreaterThan) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = - b.builder.GreaterThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kGreaterThan); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 > 2"); -} - -TEST_F(IR_BinaryTest, CreateLessThanEqual) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = - b.builder.LessThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLessThanEqual); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 <= 2"); -} - -TEST_F(IR_BinaryTest, CreateGreaterThanEqual) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = - b.builder.GreaterThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kGreaterThanEqual); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 >= 2"); -} - -TEST_F(IR_BinaryTest, CreateShiftLeft) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.ShiftLeft(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kShiftLeft); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 << 2"); -} - -TEST_F(IR_BinaryTest, CreateShiftRight) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = - b.builder.ShiftRight(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kShiftRight); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 >> 2"); -} - -TEST_F(IR_BinaryTest, CreateAdd) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Add(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kAdd); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 + 2"); -} - -TEST_F(IR_BinaryTest, CreateSubtract) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Subtract(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kSubtract); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 - 2"); -} - -TEST_F(IR_BinaryTest, CreateMultiply) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Multiply(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kMultiply); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 * 2"); -} - -TEST_F(IR_BinaryTest, CreateDivide) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Divide(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kDivide); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 / 2"); -} - -TEST_F(IR_BinaryTest, CreateModulo) { - auto& b = CreateEmptyBuilder(); - - b.builder.next_temp_id = Temp::Id(42); - const auto* instr = b.builder.Modulo(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); - - EXPECT_EQ(instr->GetKind(), Instruction::Kind::kModulo); - - ASSERT_TRUE(instr->Result()->Is()); - EXPECT_EQ(Temp::Id(42), instr->Result()->As()->AsId()); - - ASSERT_TRUE(instr->LHS()->Is()); - auto lhs = instr->LHS()->As(); - ASSERT_TRUE(lhs->IsI32()); - EXPECT_EQ(i32(4), lhs->AsI32()); - - ASSERT_TRUE(instr->RHS()->Is()); - auto rhs = instr->RHS()->As(); - ASSERT_TRUE(rhs->IsI32()); - EXPECT_EQ(i32(2), rhs->AsI32()); - - std::stringstream str; - instr->ToString(str, program->Symbols()); - EXPECT_EQ(str.str(), "%42 = 4 % 2"); -} - -} // namespace -} // namespace tint::ir diff --git a/src/tint/ir/value.h b/src/tint/ir/value.h index 3b3965311b..1f9619f903 100644 --- a/src/tint/ir/value.h +++ b/src/tint/ir/value.h @@ -20,6 +20,12 @@ #include "src/tint/castable.h" #include "src/tint/symbol_table.h" #include "src/tint/type/type.h" +#include "src/tint/utils/unique_vector.h" + +// Forward declarations +namespace tint::ir { +class Instruction; +} // namespace tint::ir namespace tint::ir { @@ -35,6 +41,14 @@ class Value : public Castable { Value& operator=(const Value&) = delete; Value& operator=(Value&&) = delete; + /// Adds an instruction which uses this value. + /// @param instr the instruction + void AddUsage(const Instruction* instr) { uses_.Add(instr); } + + /// @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 Usage() const { return uses_; } + /// @returns the type of the value virtual const type::Type* Type() const = 0; @@ -47,6 +61,9 @@ class Value : public Castable { protected: /// Constructor Value(); + + private: + utils::UniqueVector uses_; }; } // namespace tint::ir