[ir] Make ir::Instruction a ir::Value.

This CL removes the `ir::Runtime` and inherits `ir::Instruction` from
`ir::Value`. This means that any `Value` can be an `Instruction`. The
instruction id is used for debugging purposes.

Bug: tint:1895
Change-Id: I2b79cd6721268712d78a47d383a30f82aa3aa07e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/129660
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2023-04-27 14:00:06 +00:00 committed by Dawn LUCI CQ
parent 5e4aad952e
commit f00679fd72
42 changed files with 280 additions and 507 deletions

View File

@ -1160,8 +1160,6 @@ libtint_source_set("libtint_ir_src") {
"ir/loop.h",
"ir/module.cc",
"ir/module.h",
"ir/runtime.cc",
"ir/runtime.h",
"ir/store.cc",
"ir/store.h",
"ir/switch.cc",
@ -2122,7 +2120,6 @@ if (tint_build_unittests) {
"ir/builder_impl_test.cc",
"ir/constant_test.cc",
"ir/discard_test.cc",
"ir/runtime_test.cc",
"ir/store_test.cc",
"ir/test_helper.h",
"ir/unary_test.cc",

View File

@ -738,8 +738,6 @@ if(${TINT_BUILD_IR})
ir/loop.h
ir/module.cc
ir/module.h
ir/runtime.cc
ir/runtime.h
ir/store.cc
ir/store.h
ir/switch.cc
@ -1425,7 +1423,6 @@ if(TINT_BUILD_TESTS)
ir/builder_impl_test.cc
ir/constant_test.cc
ir/discard_test.cc
ir/runtime_test.cc
ir/store_test.cc
ir/test_helper.h
ir/unary_test.cc

View File

@ -19,8 +19,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Binary);
namespace tint::ir {
Binary::Binary(Kind kind, Value* result, Value* lhs, Value* rhs)
: Base(result), kind_(kind), lhs_(lhs), rhs_(rhs) {
Binary::Binary(uint32_t id, Kind kind, const type::Type* ty, Value* lhs, Value* rhs)
: Base(id, ty), kind_(kind), lhs_(lhs), rhs_(rhs) {
TINT_ASSERT(IR, lhs_);
TINT_ASSERT(IR, rhs_);
lhs_->AddUsage(this);
@ -29,9 +29,9 @@ Binary::Binary(Kind kind, Value* result, Value* lhs, Value* rhs)
Binary::~Binary() = default;
utils::StringStream& Binary::ToString(utils::StringStream& out) const {
Result()->ToString(out) << " = ";
lhs_->ToString(out) << " ";
utils::StringStream& Binary::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = ";
lhs_->ToValue(out) << " ";
switch (GetKind()) {
case Binary::Kind::kAdd:
@ -90,7 +90,7 @@ utils::StringStream& Binary::ToString(utils::StringStream& out) const {
break;
}
out << " ";
rhs_->ToString(out);
rhs_->ToValue(out);
return out;
}

View File

@ -51,11 +51,12 @@ class Binary : public utils::Castable<Binary, Instruction> {
};
/// Constructor
/// @param id the instruction id
/// @param kind the kind of binary instruction
/// @param result the result value
/// @param type the result type
/// @param lhs the lhs of the instruction
/// @param rhs the rhs of the instruction
Binary(Kind kind, Value* result, Value* lhs, Value* rhs);
Binary(uint32_t id, Kind kind, const type::Type* type, Value* lhs, Value* rhs);
Binary(const Binary& inst) = delete;
Binary(Binary&& inst) = delete;
~Binary() override;
@ -75,7 +76,7 @@ class Binary : public utils::Castable<Binary, Instruction> {
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Kind kind_;

View File

@ -20,21 +20,18 @@ namespace tint::ir {
namespace {
using namespace tint::number_suffixes; // NOLINT
//
using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, CreateAnd) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kAnd);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
ASSERT_NE(inst->Result()->Type(), nullptr);
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_NE(inst->Type(), nullptr);
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
@ -47,22 +44,19 @@ TEST_F(IR_InstructionTest, CreateAnd) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 & 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 & 2");
}
TEST_F(IR_InstructionTest, CreateOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Or(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kOr);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -74,22 +68,19 @@ TEST_F(IR_InstructionTest, CreateOr) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 | 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 | 2");
}
TEST_F(IR_InstructionTest, CreateXor) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Xor(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kXor);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -101,22 +92,19 @@ TEST_F(IR_InstructionTest, CreateXor) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 ^ 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 ^ 2");
}
TEST_F(IR_InstructionTest, CreateLogicalAnd) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.LogicalAnd(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kLogicalAnd);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -128,22 +116,19 @@ TEST_F(IR_InstructionTest, CreateLogicalAnd) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 && 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 && 2");
}
TEST_F(IR_InstructionTest, CreateLogicalOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.LogicalOr(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kLogicalOr);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -155,22 +140,19 @@ TEST_F(IR_InstructionTest, CreateLogicalOr) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 || 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 || 2");
}
TEST_F(IR_InstructionTest, CreateEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Equal(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kEqual);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -182,22 +164,19 @@ TEST_F(IR_InstructionTest, CreateEqual) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 == 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 == 2");
}
TEST_F(IR_InstructionTest, CreateNotEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.NotEqual(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kNotEqual);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -209,22 +188,19 @@ TEST_F(IR_InstructionTest, CreateNotEqual) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 != 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 != 2");
}
TEST_F(IR_InstructionTest, CreateLessThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.LessThan(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kLessThan);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -236,22 +212,19 @@ TEST_F(IR_InstructionTest, CreateLessThan) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 < 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 < 2");
}
TEST_F(IR_InstructionTest, CreateGreaterThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.GreaterThan(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kGreaterThan);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -263,22 +236,19 @@ TEST_F(IR_InstructionTest, CreateGreaterThan) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 > 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 > 2");
}
TEST_F(IR_InstructionTest, CreateLessThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.LessThanEqual(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kLessThanEqual);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -290,22 +260,19 @@ TEST_F(IR_InstructionTest, CreateLessThanEqual) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 <= 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 <= 2");
}
TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.GreaterThanEqual(b.builder.ir.types.Get<type::Bool>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kGreaterThanEqual);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -317,22 +284,19 @@ TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = 4 >= 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 >= 2");
}
TEST_F(IR_InstructionTest, CreateShiftLeft) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.ShiftLeft(b.builder.ir.types.Get<type::I32>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kShiftLeft);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -344,22 +308,19 @@ TEST_F(IR_InstructionTest, CreateShiftLeft) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 << 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 << 2");
}
TEST_F(IR_InstructionTest, CreateShiftRight) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.ShiftRight(b.builder.ir.types.Get<type::I32>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kShiftRight);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -371,22 +332,19 @@ TEST_F(IR_InstructionTest, CreateShiftRight) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 >> 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 >> 2");
}
TEST_F(IR_InstructionTest, CreateAdd) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Add(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kAdd);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -398,22 +356,19 @@ TEST_F(IR_InstructionTest, CreateAdd) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 + 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 + 2");
}
TEST_F(IR_InstructionTest, CreateSubtract) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Subtract(b.builder.ir.types.Get<type::I32>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kSubtract);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -425,22 +380,19 @@ TEST_F(IR_InstructionTest, CreateSubtract) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 - 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 - 2");
}
TEST_F(IR_InstructionTest, CreateMultiply) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Multiply(b.builder.ir.types.Get<type::I32>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kMultiply);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -452,22 +404,19 @@ TEST_F(IR_InstructionTest, CreateMultiply) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 * 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 * 2");
}
TEST_F(IR_InstructionTest, CreateDivide) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Divide(b.builder.ir.types.Get<type::I32>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kDivide);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -479,22 +428,19 @@ TEST_F(IR_InstructionTest, CreateDivide) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 / 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 / 2");
}
TEST_F(IR_InstructionTest, CreateModulo) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Modulo(b.builder.ir.types.Get<type::I32>(),
b.builder.Constant(4_i), b.builder.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
EXPECT_EQ(inst->GetKind(), Binary::Kind::kModulo);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->LHS()->Is<Constant>());
auto lhs = inst->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
@ -506,23 +452,17 @@ TEST_F(IR_InstructionTest, CreateModulo) {
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4 % 2");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 % 2");
}
TEST_F(IR_InstructionTest, Binary_Usage) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
b.builder.Constant(2_i));
EXPECT_EQ(inst->GetKind(), Binary::Kind::kAnd);
ASSERT_NE(inst->Result(), nullptr);
ASSERT_EQ(inst->Result()->Usage().Length(), 1u);
EXPECT_EQ(inst->Result()->Usage()[0], inst);
ASSERT_NE(inst->LHS(), nullptr);
ASSERT_EQ(inst->LHS()->Usage().Length(), 1u);
EXPECT_EQ(inst->LHS()->Usage()[0], inst);
@ -534,18 +474,10 @@ TEST_F(IR_InstructionTest, Binary_Usage) {
TEST_F(IR_InstructionTest, Binary_Usage_DuplicateValue) {
auto& b = CreateEmptyBuilder();
auto val = b.builder.Constant(4_i);
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.And(b.builder.ir.types.Get<type::I32>(), val, val);
EXPECT_EQ(inst->GetKind(), Binary::Kind::kAnd);
ASSERT_NE(inst->Result(), nullptr);
ASSERT_EQ(inst->Result()->Usage().Length(), 1u);
EXPECT_EQ(inst->Result()->Usage()[0], inst);
ASSERT_EQ(inst->LHS(), inst->RHS());
ASSERT_NE(inst->LHS(), nullptr);

View File

@ -19,17 +19,16 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Bitcast);
namespace tint::ir {
Bitcast::Bitcast(Value* result, Value* val) : Base(result), val_(val) {
Bitcast::Bitcast(uint32_t id, const type::Type* type, Value* val) : Base(id, type), val_(val) {
TINT_ASSERT(IR, val_);
val_->AddUsage(this);
}
Bitcast::~Bitcast() = default;
utils::StringStream& Bitcast::ToString(utils::StringStream& out) const {
Result()->ToString(out);
out << " = bitcast(";
val_->ToString(out);
utils::StringStream& Bitcast::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = bitcast(";
val_->ToValue(out);
out << ")";
return out;
}

View File

@ -25,9 +25,10 @@ namespace tint::ir {
class Bitcast : public utils::Castable<Bitcast, Instruction> {
public:
/// Constructor
/// @param result the result value
/// @param id the instruction id
/// @param type the result type
/// @param val the value being bitcast
Bitcast(Value* result, Value* val);
Bitcast(uint32_t id, const type::Type* type, Value* val);
Bitcast(const Bitcast& inst) = delete;
Bitcast(Bitcast&& inst) = delete;
~Bitcast() override;
@ -41,7 +42,7 @@ class Bitcast : public utils::Castable<Bitcast, Instruction> {
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Value* val_ = nullptr;

View File

@ -20,19 +20,16 @@ namespace tint::ir {
namespace {
using namespace tint::number_suffixes; // NOLINT
//
using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, Bitcast) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst =
b.builder.Bitcast(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_NE(inst->Result()->Type(), nullptr);
ASSERT_TRUE(inst->Is<ir::Bitcast>());
ASSERT_NE(inst->Type(), nullptr);
ASSERT_TRUE(inst->Val()->Is<Constant>());
auto val = inst->Val()->As<Constant>()->value;
@ -40,21 +37,15 @@ TEST_F(IR_InstructionTest, Bitcast) {
EXPECT_EQ(4_i, val->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = bitcast(4)");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = bitcast(4)");
}
TEST_F(IR_InstructionTest, Bitcast_Usage) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst =
b.builder.Bitcast(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
ASSERT_NE(inst->Result(), nullptr);
ASSERT_EQ(inst->Result()->Usage().Length(), 1u);
EXPECT_EQ(inst->Result()->Usage()[0], inst);
ASSERT_NE(inst->Val(), nullptr);
ASSERT_EQ(inst->Val()->Usage().Length(), 1u);
EXPECT_EQ(inst->Val()->Usage()[0], inst);

View File

@ -91,12 +91,8 @@ void Builder::Branch(Block* from, FlowNode* to, utils::VectorRef<Value*> args) {
to->inbound_branches.Push(from);
}
Runtime::Id Builder::AllocateRuntimeId() {
return next_runtime_id++;
}
Binary* Builder::CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs) {
return ir.instructions.Create<ir::Binary>(kind, Runtime(type), lhs, rhs);
return ir.instructions.Create<ir::Binary>(next_inst_id(), kind, type, lhs, rhs);
}
Binary* Builder::And(const type::Type* type, Value* lhs, Value* rhs) {
@ -172,7 +168,7 @@ Binary* Builder::Modulo(const type::Type* type, Value* lhs, Value* rhs) {
}
Unary* Builder::CreateUnary(Unary::Kind kind, const type::Type* type, Value* val) {
return ir.instructions.Create<ir::Unary>(kind, Runtime(type), val);
return ir.instructions.Create<ir::Unary>(next_inst_id(), kind, type, val);
}
Unary* Builder::AddressOf(const type::Type* type, Value* val) {
@ -196,33 +192,33 @@ Unary* Builder::Not(const type::Type* type, Value* val) {
}
ir::Bitcast* Builder::Bitcast(const type::Type* type, Value* val) {
return ir.instructions.Create<ir::Bitcast>(Runtime(type), val);
return ir.instructions.Create<ir::Bitcast>(next_inst_id(), type, val);
}
ir::Discard* Builder::Discard() {
return ir.instructions.Create<ir::Discard>(Runtime(ir.types.Get<type::Void>()));
return ir.instructions.Create<ir::Discard>();
}
ir::UserCall* Builder::UserCall(const type::Type* type,
Symbol name,
utils::VectorRef<Value*> args) {
return ir.instructions.Create<ir::UserCall>(Runtime(type), name, std::move(args));
return ir.instructions.Create<ir::UserCall>(next_inst_id(), type, name, std::move(args));
}
ir::Convert* Builder::Convert(const type::Type* to,
const type::Type* from,
utils::VectorRef<Value*> args) {
return ir.instructions.Create<ir::Convert>(Runtime(to), from, std::move(args));
return ir.instructions.Create<ir::Convert>(next_inst_id(), to, from, std::move(args));
}
ir::Construct* Builder::Construct(const type::Type* to, utils::VectorRef<Value*> args) {
return ir.instructions.Create<ir::Construct>(Runtime(to), std::move(args));
return ir.instructions.Create<ir::Construct>(next_inst_id(), to, std::move(args));
}
ir::Builtin* Builder::Builtin(const type::Type* type,
builtin::Function func,
utils::VectorRef<Value*> args) {
return ir.instructions.Create<ir::Builtin>(Runtime(type), func, args);
return ir.instructions.Create<ir::Builtin>(next_inst_id(), type, func, args);
}
ir::Store* Builder::Store(Value* to, Value* from) {

View File

@ -29,7 +29,6 @@
#include "src/tint/ir/if.h"
#include "src/tint/ir/loop.h"
#include "src/tint/ir/module.h"
#include "src/tint/ir/runtime.h"
#include "src/tint/ir/store.h"
#include "src/tint/ir/switch.h"
#include "src/tint/ir/terminator.h"
@ -141,13 +140,6 @@ class Builder {
return Constant(create<constant::Scalar<bool>>(ir.types.Get<type::Bool>(), v));
}
/// Creates a new Runtime value
/// @param type the type of the temporary
/// @returns the new temporary
ir::Runtime* Runtime(const type::Type* type) {
return ir.values.Create<ir::Runtime>(type, AllocateRuntimeId());
}
/// Creates an op for `lhs kind rhs`
/// @param kind the kind of operation
/// @param type the result type of the binary expression
@ -366,14 +358,13 @@ class Builder {
/// @returns the instruction
ir::Store* Store(Value* to, Value* from);
/// @returns a unique runtime id
Runtime::Id AllocateRuntimeId();
/// The IR module.
Module ir;
/// The next temporary number to allocate
Runtime::Id next_runtime_id = 1;
private:
uint32_t next_inst_id() { return next_instruction_id_++; }
uint32_t next_instruction_id_ = 1;
};
} // namespace tint::ir

View File

@ -353,7 +353,7 @@ void BuilderImpl::EmitCompoundAssignment(const ast::CompoundAssignmentStatement*
}
current_flow_block->instructions.Push(inst);
auto store = builder.Store(lhs.Get(), inst->Result());
auto store = builder.Store(lhs.Get(), inst);
current_flow_block->instructions.Push(store);
}
@ -738,7 +738,7 @@ utils::Result<Value*> BuilderImpl::EmitUnary(const ast::UnaryOpExpression* expr)
}
current_flow_block->instructions.Push(inst);
return inst->Result();
return inst;
}
utils::Result<Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) {
@ -817,7 +817,7 @@ utils::Result<Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr)
}
current_flow_block->instructions.Push(inst);
return inst->Result();
return inst;
}
utils::Result<Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* expr) {
@ -831,7 +831,7 @@ utils::Result<Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* exp
auto* inst = builder.Bitcast(ty, val.Get());
current_flow_block->instructions.Push(inst);
return inst->Result();
return inst;
}
void BuilderImpl::EmitCall(const ast::CallStatement* stmt) {
@ -896,7 +896,7 @@ utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallExpression* expr) {
return utils::Failure;
}
current_flow_block->instructions.Push(inst);
return inst->Result();
return inst;
}
utils::Result<Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {

View File

@ -1564,7 +1564,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Add) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 + 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 + 4
)");
}
@ -1580,7 +1580,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Subtract) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 - 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 - 4
)");
}
@ -1596,7 +1596,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Multiply) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 * 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 * 4
)");
}
@ -1612,7 +1612,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Div) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 / 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 / 4
)");
}
@ -1628,7 +1628,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Modulo) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 % 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 % 4
)");
}
@ -1644,7 +1644,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_And) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 & 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 & 4
)");
}
@ -1660,7 +1660,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Or) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 | 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 | 4
)");
}
@ -1676,7 +1676,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Xor) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 ^ 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 ^ 4
)");
}
@ -1692,7 +1692,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalAnd) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = true && false
EXPECT_EQ(d.AsString(), R"(%1(bool) = true && false
)");
}
@ -1708,7 +1708,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalOr) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = false || true
EXPECT_EQ(d.AsString(), R"(%1(bool) = false || true
)");
}
@ -1724,7 +1724,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Equal) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 == 4
EXPECT_EQ(d.AsString(), R"(%1(bool) = 3 == 4
)");
}
@ -1740,7 +1740,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_NotEqual) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 != 4
EXPECT_EQ(d.AsString(), R"(%1(bool) = 3 != 4
)");
}
@ -1756,7 +1756,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThan) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 < 4
EXPECT_EQ(d.AsString(), R"(%1(bool) = 3 < 4
)");
}
@ -1772,7 +1772,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThan) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 > 4
EXPECT_EQ(d.AsString(), R"(%1(bool) = 3 > 4
)");
}
@ -1788,7 +1788,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThanEqual) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 <= 4
EXPECT_EQ(d.AsString(), R"(%1(bool) = 3 <= 4
)");
}
@ -1804,7 +1804,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThanEqual) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 >= 4
EXPECT_EQ(d.AsString(), R"(%1(bool) = 3 >= 4
)");
}
@ -1820,7 +1820,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftLeft) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 << 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 << 4
)");
}
@ -1836,7 +1836,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftRight) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 >> 4
)");
}
@ -1853,13 +1853,13 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
%2 (u32) = %1 (u32) + 9
%3 (bool) = 1 < %2 (u32)
%4 (f32) = 2.29999995231628417969 * 5.5
%5 (f32) = 6.69999980926513671875 / %4 (f32)
%6 (bool) = 2.5 > %5 (f32)
%7 (bool) = %3 (bool) && %6 (bool)
EXPECT_EQ(d.AsString(), R"(%1(u32) = 3 >> 4
%2(u32) = %1(u32) + 9
%3(bool) = 1 < %2(u32)
%4(f32) = 2.29999995231628417969 * 5.5
%5(f32) = 6.69999980926513671875 / %4(f32)
%6(bool) = 2.5 > %5(f32)
%7(bool) = %3(bool) && %6(bool)
)");
}
@ -1875,7 +1875,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Bitcast) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (f32) = bitcast(3)
EXPECT_EQ(d.AsString(), R"(%1(f32) = bitcast(3)
)");
}
@ -1893,7 +1893,7 @@ TEST_F(IR_BuilderImplTest, EmitStatement_Discard) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (void) = discard
EXPECT_EQ(d.AsString(), R"(discard
)");
}
@ -1910,8 +1910,8 @@ TEST_F(IR_BuilderImplTest, EmitStatement_UserFunction) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (f32) = 2.0 * 3.0
%2 (void) = call(my_func, %1 (f32))
EXPECT_EQ(d.AsString(), R"(%1(f32) = 2.0 * 3.0
%2(void) = call(my_func, %1(f32))
)");
}
@ -1930,7 +1930,7 @@ TEST_F(IR_BuilderImplTest, DISABLED_EmitExpression_ConstructEmpty) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (vec3<f32>) = construct(vec3<f32>)
EXPECT_EQ(d.AsString(), R"(%1(vec3<f32>) = construct()
)");
}
@ -1948,7 +1948,7 @@ TEST_F(IR_BuilderImplTest, DISABLED_EmitExpression_Construct) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%2 (vec3<f32>) = construct(vec3<f32>, 2.0, 3.0, %1 (void))
EXPECT_EQ(d.AsString(), R"(%2(vec3<f32>) = construct(2.0, 3.0, %1(void))
)");
}
@ -1966,7 +1966,7 @@ TEST_F(IR_BuilderImplTest, DISABLED_EmitExpression_Convert) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%2 (f32) = convert(f32, i32, %1 (void))
EXPECT_EQ(d.AsString(), R"(%2(f32) = convert(i32, %1(void))
)");
}
@ -2001,7 +2001,7 @@ TEST_F(IR_BuilderImplTest, DISABLED_EmitExpression_Builtin) {
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%2 (f32) = asin(%1 (void))
EXPECT_EQ(d.AsString(), R"(%2(f32) = asin(%1(void))
)");
}

View File

@ -20,14 +20,16 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Builtin);
// \cond DO_NOT_DOCUMENT
namespace tint::ir {
Builtin::Builtin(Value* result, builtin::Function func, utils::VectorRef<Value*> args)
: Base(result, args), func_(func) {}
Builtin::Builtin(uint32_t id,
const type::Type* type,
builtin::Function func,
utils::VectorRef<Value*> args)
: Base(id, type, args), func_(func) {}
Builtin::~Builtin() = default;
utils::StringStream& Builtin::ToString(utils::StringStream& out) const {
Result()->ToString(out);
out << " = " << builtin::str(func_) << "(";
utils::StringStream& Builtin::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = " << builtin::str(func_) << "(";
EmitArgs(out);
out << ")";
return out;

View File

@ -26,10 +26,14 @@ namespace tint::ir {
class Builtin : public utils::Castable<Builtin, Call> {
public:
/// Constructor
/// @param result the result value
/// @param id the instruction id
/// @param type the result type
/// @param func the builtin function
/// @param args the conversion arguments
Builtin(Value* result, builtin::Function func, utils::VectorRef<Value*> args);
Builtin(uint32_t id,
const type::Type* type,
builtin::Function func,
utils::VectorRef<Value*> args);
Builtin(const Builtin& inst) = delete;
Builtin(Builtin&& inst) = delete;
~Builtin() override;
@ -43,7 +47,7 @@ class Builtin : public utils::Castable<Builtin, Call> {
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
const builtin::Function func_;

View File

@ -18,7 +18,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Call);
namespace tint::ir {
Call::Call(Value* result, utils::VectorRef<Value*> args) : Base(result), args_(args) {
Call::Call(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args)
: Base(id, type), args_(args) {
for (auto* arg : args) {
arg->AddUsage(this);
}
@ -33,7 +34,7 @@ void Call::EmitArgs(utils::StringStream& out) const {
out << ", ";
}
first = false;
arg->ToString(out);
arg->ToValue(out);
}
}

View File

@ -25,9 +25,10 @@ namespace tint::ir {
class Call : public utils::Castable<Call, Instruction> {
public:
/// Constructor
/// @param result the result value
/// @param id the instruction id
/// @param type the result type
/// @param args the constructor arguments
Call(Value* result, utils::VectorRef<Value*> args);
Call(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args);
Call(const Call& inst) = delete;
Call(Call&& inst) = delete;
~Call() override;

View File

@ -29,7 +29,7 @@ Constant::Constant(const constant::Value* val) : value(val) {}
Constant::~Constant() = default;
utils::StringStream& Constant::ToString(utils::StringStream& out) const {
utils::StringStream& Constant::ToValue(utils::StringStream& out) const {
std::function<void(const constant::Value*)> emit = [&](const constant::Value* c) {
Switch(
c,

View File

@ -35,7 +35,7 @@ class Constant : public utils::Castable<Constant, Value> {
/// Write the constant to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToValue(utils::StringStream& out) const override;
/// The constants value
const constant::Value* const value;

View File

@ -31,7 +31,7 @@ TEST_F(IR_ConstantTest, f32) {
auto* c = b.builder.Constant(1.2_f);
EXPECT_EQ(1.2_f, c->value->As<constant::Scalar<f32>>()->ValueAs<f32>());
c->ToString(str);
c->ToValue(str);
EXPECT_EQ("1.20000004768371582031", str.str());
EXPECT_TRUE(c->value->Is<constant::Scalar<f32>>());
@ -49,7 +49,7 @@ TEST_F(IR_ConstantTest, f16) {
auto* c = b.builder.Constant(1.1_h);
EXPECT_EQ(1.1_h, c->value->As<constant::Scalar<f16>>()->ValueAs<f16>());
c->ToString(str);
c->ToValue(str);
EXPECT_EQ("1.099609375", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
@ -67,7 +67,7 @@ TEST_F(IR_ConstantTest, i32) {
auto* c = b.builder.Constant(1_i);
EXPECT_EQ(1_i, c->value->As<constant::Scalar<i32>>()->ValueAs<i32>());
c->ToString(str);
c->ToValue(str);
EXPECT_EQ("1", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
@ -85,7 +85,7 @@ TEST_F(IR_ConstantTest, u32) {
auto* c = b.builder.Constant(2_u);
EXPECT_EQ(2_u, c->value->As<constant::Scalar<u32>>()->ValueAs<u32>());
c->ToString(str);
c->ToValue(str);
EXPECT_EQ("2", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
@ -104,7 +104,7 @@ TEST_F(IR_ConstantTest, bool) {
auto* c = b.builder.Constant(false);
EXPECT_FALSE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
c->ToString(str);
c->ToValue(str);
EXPECT_EQ("false", str.str());
}
@ -113,7 +113,7 @@ TEST_F(IR_ConstantTest, bool) {
auto c = b.builder.Constant(true);
EXPECT_TRUE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
c->ToString(str);
c->ToValue(str);
EXPECT_EQ("true", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());

View File

@ -19,13 +19,13 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Construct);
namespace tint::ir {
Construct::Construct(Value* result, utils::VectorRef<Value*> args) : Base(result, args) {}
Construct::Construct(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args)
: Base(id, type, args) {}
Construct::~Construct() = default;
utils::StringStream& Construct::ToString(utils::StringStream& out) const {
Result()->ToString(out);
out << " = construct(" << Result()->Type()->FriendlyName();
utils::StringStream& Construct::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = construct(";
if (!Args().IsEmpty()) {
out << ", ";
EmitArgs(out);

View File

@ -25,9 +25,10 @@ namespace tint::ir {
class Construct : public utils::Castable<Construct, Call> {
public:
/// Constructor
/// @param result the result value
/// @param id the instruction id
/// @param type the result type
/// @param args the constructor arguments
Construct(Value* result, utils::VectorRef<Value*> args);
Construct(uint32_t id, const type::Type* type, utils::VectorRef<Value*> args);
Construct(const Construct& inst) = delete;
Construct(Construct&& inst) = delete;
~Construct() override;
@ -38,7 +39,7 @@ class Construct : public utils::Castable<Construct, Call> {
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
};
} // namespace tint::ir

View File

@ -19,15 +19,16 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Convert);
namespace tint::ir {
Convert::Convert(Value* result, const type::Type* from, utils::VectorRef<Value*> args)
: Base(result, args), from_(from) {}
Convert::Convert(uint32_t id,
const type::Type* to_type,
const type::Type* from_type,
utils::VectorRef<Value*> args)
: Base(id, to_type, args), from_type_(from_type) {}
Convert::~Convert() = default;
utils::StringStream& Convert::ToString(utils::StringStream& out) const {
Result()->ToString(out);
out << " = convert(" << Result()->Type()->FriendlyName() << ", " << from_->FriendlyName()
<< ", ";
utils::StringStream& Convert::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = convert(" << from_type_->FriendlyName() << ", ";
EmitArgs(out);
out << ")";
return out;

View File

@ -26,10 +26,14 @@ namespace tint::ir {
class Convert : public utils::Castable<Convert, Call> {
public:
/// Constructor
/// @param result the result value
/// @param from the type being converted from
/// @param id the instruction id
/// @param result_type the result type
/// @param from_type the type being converted from
/// @param args the conversion arguments
Convert(Value* result, const type::Type* from, utils::VectorRef<Value*> args);
Convert(uint32_t id,
const type::Type* result_type,
const type::Type* from_type,
utils::VectorRef<Value*> args);
Convert(const Convert& inst) = delete;
Convert(Convert&& inst) = delete;
~Convert() override;
@ -38,17 +42,17 @@ class Convert : public utils::Castable<Convert, Call> {
Convert& operator=(Convert&& inst) = delete;
/// @returns the from type
const type::Type* From() const { return from_; }
const type::Type* FromType() const { return from_type_; }
/// @returns the to type
const type::Type* To() const { return Result()->Type(); }
const type::Type* ToType() const { return Type(); }
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
const type::Type* from_ = nullptr;
const type::Type* from_type_ = nullptr;
};
} // namespace tint::ir

View File

@ -64,7 +64,7 @@ utils::StringStream& Disassembler::Indent() {
void Disassembler::EmitBlockInstructions(const Block* b) {
for (const auto* inst : b->instructions) {
Indent();
inst->ToString(out_) << std::endl;
inst->ToInstruction(out_) << std::endl;
}
}
@ -119,7 +119,7 @@ void Disassembler::Walk(const FlowNode* node) {
if (v != b->branch.args.Front()) {
out_ << ", ";
}
v->ToString(out_);
v->ToValue(out_);
}
out_ << ")" << std::endl;
@ -131,7 +131,7 @@ void Disassembler::Walk(const FlowNode* node) {
},
[&](const ir::Switch* s) {
Indent() << "%bb" << GetIdForNode(s) << " = Switch (";
s->condition->ToString(out_);
s->condition->ToValue(out_);
out_ << ")" << std::endl;
{
@ -147,7 +147,7 @@ void Disassembler::Walk(const FlowNode* node) {
if (selector.IsDefault()) {
out_ << "default";
} else {
selector.val->ToString(out_);
selector.val->ToValue(out_);
}
}
out_ << std::endl;
@ -160,7 +160,7 @@ void Disassembler::Walk(const FlowNode* node) {
},
[&](const ir::If* i) {
Indent() << "%bb" << GetIdForNode(i) << " = if (";
i->condition->ToString(out_);
i->condition->ToValue(out_);
out_ << ")" << std::endl;
{

View File

@ -19,13 +19,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Discard);
namespace tint::ir {
Discard::Discard(Value* result) : Base(result) {}
Discard::Discard() : Base() {}
Discard::~Discard() = default;
utils::StringStream& Discard::ToString(utils::StringStream& out) const {
Result()->ToString(out);
out << " = discard";
utils::StringStream& Discard::ToInstruction(utils::StringStream& out) const {
out << "discard";
return out;
}

View File

@ -15,6 +15,7 @@
#ifndef SRC_TINT_IR_DISCARD_H_
#define SRC_TINT_IR_DISCARD_H_
#include "src/tint/debug.h"
#include "src/tint/ir/instruction.h"
#include "src/tint/utils/castable.h"
#include "src/tint/utils/string_stream.h"
@ -25,8 +26,7 @@ namespace tint::ir {
class Discard : public utils::Castable<Discard, Instruction> {
public:
/// Constructor
/// @param result the result id
explicit Discard(Value* result);
Discard();
Discard(const Discard& inst) = delete;
Discard(Discard&& inst) = delete;
~Discard() override;
@ -37,7 +37,7 @@ class Discard : public utils::Castable<Discard, Instruction> {
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
};
} // namespace tint::ir

View File

@ -24,17 +24,12 @@ using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, Discard) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst = b.builder.Discard();
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_NE(inst->Result()->Type(), nullptr);
ASSERT_NE(inst->Result()->Type()->As<type::Void>(), nullptr);
ASSERT_TRUE(inst->Is<ir::Discard>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (void) = discard");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "discard");
}
} // namespace

View File

@ -18,10 +18,9 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Instruction);
namespace tint::ir {
Instruction::Instruction(Value* result) : result_(result) {
TINT_ASSERT(IR, result_);
result_->AddUsage(this);
}
Instruction::Instruction() = default;
Instruction::Instruction(uint32_t id, const type::Type* ty) : id_(id), type_(ty) {}
Instruction::~Instruction() = default;

View File

@ -22,7 +22,7 @@
namespace tint::ir {
/// An instruction in the IR.
class Instruction : public utils::Castable<Instruction> {
class Instruction : public utils::Castable<Instruction, Value> {
public:
Instruction(const Instruction& inst) = delete;
Instruction(Instruction&& inst) = delete;
@ -32,21 +32,36 @@ class Instruction : public utils::Castable<Instruction> {
Instruction& operator=(const Instruction& inst) = delete;
Instruction& operator=(Instruction&& inst) = delete;
/// @returns the result value for the instruction
Value* Result() const { return result_; }
/// @returns the type of the value
const type::Type* Type() const override { return type_; }
/// Write the value to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToValue(utils::StringStream& out) const override {
out << "%" << std::to_string(id_);
if (type_ != nullptr) {
out << "(" << Type()->FriendlyName() << ")";
}
return out;
}
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
virtual utils::StringStream& ToString(utils::StringStream& out) const = 0;
virtual utils::StringStream& ToInstruction(utils::StringStream& out) const = 0;
protected:
/// Constructor
/// @param result the result value
explicit Instruction(Value* result);
Instruction();
/// Constructor
/// @param id the instruction id
/// @param type the result type
Instruction(uint32_t id, const type::Type* type);
private:
Value* result_ = nullptr;
uint32_t id_ = 0;
const type::Type* type_ = nullptr;
};
} // namespace tint::ir

View File

@ -1,32 +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 "src/tint/ir/runtime.h"
#include <string>
TINT_INSTANTIATE_TYPEINFO(tint::ir::Runtime);
namespace tint::ir {
Runtime::Runtime(const type::Type* type, Id id) : type_(type), id_(id) {}
Runtime::~Runtime() = default;
utils::StringStream& Runtime::ToString(utils::StringStream& out) const {
out << "%" << std::to_string(AsId()) << " (" << type_->FriendlyName() << ")";
return out;
}
} // namespace tint::ir

View File

@ -1,61 +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.
#ifndef SRC_TINT_IR_RUNTIME_H_
#define SRC_TINT_IR_RUNTIME_H_
#include "src/tint/ir/value.h"
#include "src/tint/utils/string_stream.h"
namespace tint::ir {
/// Runtime value in the IR.
class Runtime : public utils::Castable<Runtime, Value> {
public:
/// A value id.
using Id = uint32_t;
/// Constructor
/// @param type the type of the value
/// @param id the id for the value
Runtime(const type::Type* type, Id id);
/// Destructor
~Runtime() override;
Runtime(const Runtime&) = delete;
Runtime(Runtime&&) = delete;
Runtime& operator=(const Runtime&) = delete;
Runtime& operator=(Runtime&&) = delete;
/// @returns the value data as an `Id`.
Id AsId() const { return id_; }
/// @returns the type of the value
const type::Type* Type() const override { return type_; }
/// Write the id to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
private:
const type::Type* type_ = nullptr;
Id id_ = 0;
};
} // namespace tint::ir
#endif // SRC_TINT_IR_RUNTIME_H_

View File

@ -1,40 +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 "src/tint/ir/runtime.h"
#include "src/tint/ir/test_helper.h"
#include "src/tint/utils/string_stream.h"
namespace tint::ir {
namespace {
using namespace tint::number_suffixes; // NOLINT
using IR_RuntimeTest = TestHelper;
TEST_F(IR_RuntimeTest, id) {
auto& b = CreateEmptyBuilder();
utils::StringStream str;
b.builder.next_runtime_id = Runtime::Id(4);
auto* val = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
EXPECT_EQ(4u, val->AsId());
val->ToString(str);
EXPECT_EQ("%4 (i32)", str.str());
}
} // namespace
} // namespace tint::ir

View File

@ -19,17 +19,19 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Store);
namespace tint::ir {
Store::Store(Value* to, Value* from) : Base(to), from_(from) {
Store::Store(Value* to, Value* from) : Base(), to_(to), from_(from) {
TINT_ASSERT(IR, to_);
TINT_ASSERT(IR, from_);
to_->AddUsage(this);
from_->AddUsage(this);
}
Store::~Store() = default;
utils::StringStream& Store::ToString(utils::StringStream& out) const {
Result()->ToString(out);
out << " = ";
from_->ToString(out);
utils::StringStream& Store::ToInstruction(utils::StringStream& out) const {
out << "store(";
to_->ToValue(out) << ", ";
from_->ToValue(out) << ")";
return out;
}

View File

@ -35,15 +35,18 @@ class Store : public utils::Castable<Store, Instruction> {
Store& operator=(const Store& inst) = delete;
Store& operator=(Store&& inst) = delete;
/// @returns the value being stored too
const Value* to() const { return to_; }
/// @returns the value being stored
const Value* from() const { return from_; }
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Value* to_ = nullptr;
Value* from_ = nullptr;
};

View File

@ -26,14 +26,13 @@ using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, CreateStore) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
// TODO(dsinclair): This is wrong, but we don't have anything correct to store too at the
// moment.
auto* to = b.builder.Discard();
const auto* inst = b.builder.Store(to, b.builder.Constant(4_i));
auto* rt = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
const auto* inst = b.builder.Store(rt, b.builder.Constant(4_i));
ASSERT_TRUE(inst->Result()->Is<Runtime>());
ASSERT_NE(inst->Result()->Type(), nullptr);
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->Is<Store>());
ASSERT_EQ(inst->to(), to);
ASSERT_TRUE(inst->from()->Is<Constant>());
auto lhs = inst->from()->As<Constant>()->value;
@ -41,20 +40,19 @@ TEST_F(IR_InstructionTest, CreateStore) {
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = 4");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "store(%0, 4)");
}
TEST_F(IR_InstructionTest, Store_Usage) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
auto* rt = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
const auto* inst = b.builder.Store(rt, b.builder.Constant(4_i));
auto* to = b.builder.Discard();
const auto* inst = b.builder.Store(to, b.builder.Constant(4_i));
ASSERT_NE(inst->Result(), nullptr);
ASSERT_EQ(inst->Result()->Usage().Length(), 1u);
EXPECT_EQ(inst->Result()->Usage()[0], inst);
ASSERT_NE(inst->to(), nullptr);
ASSERT_EQ(inst->to()->Usage().Length(), 1u);
EXPECT_EQ(inst->to()->Usage()[0], inst);
ASSERT_NE(inst->from(), nullptr);
ASSERT_EQ(inst->from()->Usage().Length(), 1u);

View File

@ -19,15 +19,16 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Unary);
namespace tint::ir {
Unary::Unary(Kind kind, Value* result, Value* val) : Base(result), kind_(kind), val_(val) {
Unary::Unary(uint32_t id, Kind kind, const type::Type* type, Value* val)
: Base(id, type), kind_(kind), val_(val) {
TINT_ASSERT(IR, val_);
val_->AddUsage(this);
}
Unary::~Unary() = default;
utils::StringStream& Unary::ToString(utils::StringStream& out) const {
Result()->ToString(out) << " = ";
utils::StringStream& Unary::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = ";
switch (GetKind()) {
case Unary::Kind::kAddressOf:
out << "&";
@ -45,8 +46,7 @@ utils::StringStream& Unary::ToString(utils::StringStream& out) const {
out << "!";
break;
}
val_->ToString(out);
val_->ToValue(out);
return out;
}

View File

@ -34,10 +34,11 @@ class Unary : public utils::Castable<Unary, Instruction> {
};
/// Constructor
/// @param id the instruction id
/// @param kind the kind of unary instruction
/// @param result the result value
/// @param type the result type
/// @param val the lhs of the instruction
Unary(Kind kind, Value* result, Value* val);
Unary(uint32_t id, Kind kind, const type::Type* type, Value* val);
Unary(const Unary& inst) = delete;
Unary(Unary&& inst) = delete;
~Unary() override;
@ -54,7 +55,7 @@ class Unary : public utils::Castable<Unary, Instruction> {
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Kind kind_;

View File

@ -26,7 +26,6 @@ using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, CreateAddressOf) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
// TODO(dsinclair): This would be better as an identifier, but works for now.
const auto* inst =
b.builder.AddressOf(b.builder.ir.types.Get<type::Pointer>(
@ -34,11 +33,10 @@ TEST_F(IR_InstructionTest, CreateAddressOf) {
builtin::AddressSpace::kPrivate, builtin::Access::kReadWrite),
b.builder.Constant(4_i));
ASSERT_TRUE(inst->Is<Unary>());
EXPECT_EQ(inst->GetKind(), Unary::Kind::kAddressOf);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
ASSERT_NE(inst->Result()->Type(), nullptr);
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_NE(inst->Type(), nullptr);
ASSERT_TRUE(inst->Val()->Is<Constant>());
auto lhs = inst->Val()->As<Constant>()->value;
@ -46,112 +44,91 @@ TEST_F(IR_InstructionTest, CreateAddressOf) {
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (ptr<private, i32, read_write>) = &4");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(ptr<private, i32, read_write>) = &4");
}
TEST_F(IR_InstructionTest, CreateComplement) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst =
b.builder.Complement(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
ASSERT_TRUE(inst->Is<Unary>());
EXPECT_EQ(inst->GetKind(), Unary::Kind::kComplement);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->Val()->Is<Constant>());
auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = ~4");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = ~4");
}
TEST_F(IR_InstructionTest, CreateIndirection) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
// TODO(dsinclair): This would be better as an identifier, but works for now.
const auto* inst =
b.builder.Indirection(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
ASSERT_TRUE(inst->Is<Unary>());
EXPECT_EQ(inst->GetKind(), Unary::Kind::kIndirection);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->Val()->Is<Constant>());
auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = *4");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = *4");
}
TEST_F(IR_InstructionTest, CreateNegation) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst =
b.builder.Negation(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
ASSERT_TRUE(inst->Is<Unary>());
EXPECT_EQ(inst->GetKind(), Unary::Kind::kNegation);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->Val()->Is<Constant>());
auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (i32) = -4");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = -4");
}
TEST_F(IR_InstructionTest, CreateNot) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst =
b.builder.Not(b.builder.ir.types.Get<type::Bool>(), b.builder.Constant(true));
ASSERT_TRUE(inst->Is<Unary>());
EXPECT_EQ(inst->GetKind(), Unary::Kind::kNot);
ASSERT_TRUE(inst->Result()->Is<Runtime>());
EXPECT_EQ(Runtime::Id(42), inst->Result()->As<Runtime>()->AsId());
ASSERT_TRUE(inst->Val()->Is<Constant>());
auto lhs = inst->Val()->As<Constant>()->value;
ASSERT_TRUE(lhs->Is<constant::Scalar<bool>>());
EXPECT_TRUE(lhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
utils::StringStream str;
inst->ToString(str);
EXPECT_EQ(str.str(), "%42 (bool) = !true");
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = !true");
}
TEST_F(IR_InstructionTest, Unary_Usage) {
auto& b = CreateEmptyBuilder();
b.builder.next_runtime_id = Runtime::Id(42);
const auto* inst =
b.builder.Negation(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
EXPECT_EQ(inst->GetKind(), Unary::Kind::kNegation);
ASSERT_NE(inst->Result(), nullptr);
ASSERT_EQ(inst->Result()->Usage().Length(), 1u);
EXPECT_EQ(inst->Result()->Usage()[0], inst);
ASSERT_NE(inst->Val(), nullptr);
ASSERT_EQ(inst->Val()->Usage().Length(), 1u);
EXPECT_EQ(inst->Val()->Usage()[0], inst);

View File

@ -19,15 +19,13 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::UserCall);
namespace tint::ir {
UserCall::UserCall(Value* result, Symbol name, utils::VectorRef<Value*> args)
: Base(result, args), name_(name) {}
UserCall::UserCall(uint32_t id, const type::Type* type, Symbol name, utils::VectorRef<Value*> args)
: Base(id, type, args), name_(name) {}
UserCall::~UserCall() = default;
utils::StringStream& UserCall::ToString(utils::StringStream& out) const {
Result()->ToString(out);
out << " = call(";
out << name_.Name() << ", ";
utils::StringStream& UserCall::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = call(" << name_.Name() << ", ";
EmitArgs(out);
out << ")";
return out;

View File

@ -26,10 +26,11 @@ namespace tint::ir {
class UserCall : public utils::Castable<UserCall, Call> {
public:
/// Constructor
/// @param result the result value
/// @param id the instruction id
/// @param type the result type
/// @param name the function name
/// @param args the function arguments
UserCall(Value* result, Symbol name, utils::VectorRef<Value*> args);
UserCall(uint32_t id, const type::Type* type, Symbol name, utils::VectorRef<Value*> args);
UserCall(const UserCall& inst) = delete;
UserCall(UserCall&& inst) = delete;
~UserCall() override;
@ -43,7 +44,7 @@ class UserCall : public utils::Castable<UserCall, Call> {
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @returns the stream
utils::StringStream& ToString(utils::StringStream& out) const override;
utils::StringStream& ToInstruction(utils::StringStream& out) const override;
private:
Symbol name_{};

View File

@ -15,7 +15,6 @@
#include "src/tint/ir/value.h"
#include "src/tint/ir/constant.h"
#include "src/tint/ir/runtime.h"
TINT_INSTANTIATE_TYPEINFO(tint::ir::Value);

View File

@ -53,7 +53,7 @@ class Value : public utils::Castable<Value> {
/// Write the value to the given stream
/// @param out the stream to write to
/// @returns the stream
virtual utils::StringStream& ToString(utils::StringStream& out) const = 0;
virtual utils::StringStream& ToValue(utils::StringStream& out) const = 0;
protected:
/// Constructor