[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 <dsinclair@chromium.org> Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
b70d610bae
commit
afd7f2aa21
|
@ -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;
|
||||
|
|
|
@ -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<Binary, Instruction> {
|
|||
/// @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<Binary, Instruction> {
|
|||
/// @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<Binary, Instruction> {
|
|||
|
||||
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&);
|
||||
|
|
|
@ -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<type::I32>(), 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<type::I32>(), 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Bitcast, Instruction> {
|
|||
/// 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, Instruction> {
|
|||
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<Bitcast, Instruction> {
|
|||
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&);
|
||||
|
|
|
@ -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<type::I32>(), 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
|
||||
|
|
|
@ -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<ir::Binary>(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<ir::Bitcast>(Temp(type), val);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ir::Constant>(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<constant::Scalar<i32>>(ir.types.Get<type::I32>(), 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<constant::Scalar<u32>>(ir.types.Get<type::U32>(), 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<constant::Scalar<f32>>(ir.types.Get<type::F32>(), 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<constant::Scalar<f16>>(ir.types.Get<type::F16>(), 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<constant::Scalar<bool>>(ir.types.Get<type::Bool>(), 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<ir::Temp>(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();
|
||||
|
|
|
@ -518,7 +518,7 @@ bool BuilderImpl::EmitBreakIf(const ast::BreakIfStatement* stmt) {
|
|||
return true;
|
||||
}
|
||||
|
||||
utils::Result<const Value*> BuilderImpl::EmitExpression(const ast::Expression* expr) {
|
||||
utils::Result<Value*> 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<const Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) {
|
||||
utils::Result<Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) {
|
||||
auto lhs = EmitExpression(expr->lhs);
|
||||
if (!lhs) {
|
||||
return utils::Failure;
|
||||
|
@ -565,7 +565,7 @@ utils::Result<const Value*> 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<const Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression*
|
|||
}
|
||||
|
||||
current_flow_block->instructions.Push(instr);
|
||||
return utils::Result<const Value*>(instr->Result());
|
||||
return instr->Result();
|
||||
}
|
||||
|
||||
utils::Result<const Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* expr) {
|
||||
utils::Result<Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* expr) {
|
||||
auto val = EmitExpression(expr->expr);
|
||||
if (!val) {
|
||||
return utils::Failure;
|
||||
|
@ -640,10 +640,10 @@ utils::Result<const Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpressio
|
|||
auto* instr = builder.Bitcast(sem->Type(), val.Get());
|
||||
|
||||
current_flow_block->instructions.Push(instr);
|
||||
return utils::Result<const Value*>(instr->Result());
|
||||
return instr->Result();
|
||||
}
|
||||
|
||||
utils::Result<const Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
|
||||
utils::Result<Value*> 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<const Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpressio
|
|||
lit->source);
|
||||
return utils::Failure;
|
||||
}
|
||||
return utils::Result<const Value*>(builder.Constant(cv));
|
||||
return builder.Constant(cv);
|
||||
}
|
||||
|
||||
bool BuilderImpl::EmitType(const ast::Type* ty) {
|
||||
|
|
|
@ -141,7 +141,7 @@ class BuilderImpl {
|
|||
/// Emits an expression
|
||||
/// @param expr the expression to emit
|
||||
/// @returns true if successful, false otherwise
|
||||
utils::Result<const Value*> EmitExpression(const ast::Expression* expr);
|
||||
utils::Result<Value*> 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<const Value*> EmitBinary(const ast::BinaryExpression* expr);
|
||||
utils::Result<Value*> 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<const Value*> EmitBitcast(const ast::BitcastExpression* expr);
|
||||
utils::Result<Value*> EmitBitcast(const ast::BitcastExpression* expr);
|
||||
|
||||
/// Emits a literal expression
|
||||
/// @param lit the literal to emit
|
||||
/// @returns true if successful, false otherwise
|
||||
utils::Result<const Value*> EmitLiteral(const ast::LiteralExpression* lit);
|
||||
utils::Result<Value*> EmitLiteral(const ast::LiteralExpression* lit);
|
||||
|
||||
/// Emits a type
|
||||
/// @param ty the type to emit
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <ostream>
|
||||
|
||||
#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> {
|
|||
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<Instruction> {
|
|||
|
||||
protected:
|
||||
/// Constructor
|
||||
Instruction();
|
||||
/// @param result the result value
|
||||
explicit Instruction(Value* result);
|
||||
|
||||
private:
|
||||
Value* result_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace tint::ir
|
||||
|
|
|
@ -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 <sstream>
|
||||
|
||||
#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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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<Temp>());
|
||||
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->LHS()->Is<Constant>());
|
||||
auto lhs = instr->LHS()->As<Constant>();
|
||||
ASSERT_TRUE(lhs->IsI32());
|
||||
EXPECT_EQ(i32(4), lhs->AsI32());
|
||||
|
||||
ASSERT_TRUE(instr->RHS()->Is<Constant>());
|
||||
auto rhs = instr->RHS()->As<Constant>();
|
||||
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
|
|
@ -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> {
|
|||
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<const Instruction*> 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<Value> {
|
|||
protected:
|
||||
/// Constructor
|
||||
Value();
|
||||
|
||||
private:
|
||||
utils::UniqueVector<const Instruction*, 4> uses_;
|
||||
};
|
||||
|
||||
} // namespace tint::ir
|
||||
|
|
Loading…
Reference in New Issue