mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-13 19:01:24 +00:00
[ir] Shift back to accessors.
Some of the IR classes require setters in order to update dependant information. In order to keep the IR access symmetrical this CL moves the IR back to using accessors and private fields. Bug: tint:1718 Change-Id: I101edda004671e07c4594bdcae4b1576e5771782 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/133640 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
3cd9b53e88
commit
24cb81116d
@ -2265,6 +2265,7 @@ if (tint_build_unittests) {
|
|||||||
"ir/store_test.cc",
|
"ir/store_test.cc",
|
||||||
"ir/test_helper.h",
|
"ir/test_helper.h",
|
||||||
"ir/to_program_roundtrip_test.cc",
|
"ir/to_program_roundtrip_test.cc",
|
||||||
|
"ir/transform/add_empty_entry_point_test.cc",
|
||||||
"ir/unary_test.cc",
|
"ir/unary_test.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1476,6 +1476,7 @@ if(TINT_BUILD_TESTS)
|
|||||||
ir/module_test.cc
|
ir/module_test.cc
|
||||||
ir/store_test.cc
|
ir/store_test.cc
|
||||||
ir/test_helper.h
|
ir/test_helper.h
|
||||||
|
ir/transform/add_empty_entry_point_test.cc
|
||||||
ir/unary_test.cc
|
ir/unary_test.cc
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
@ -19,8 +19,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Binary);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Binary::Binary(Kind k, const type::Type* res_ty, Value* lhs, Value* rhs)
|
Binary::Binary(enum Kind kind, const type::Type* res_ty, Value* lhs, Value* rhs)
|
||||||
: kind(k), result_type(res_ty), lhs_(lhs), rhs_(rhs) {
|
: kind_(kind), result_type_(res_ty), lhs_(lhs), rhs_(rhs) {
|
||||||
TINT_ASSERT(IR, lhs);
|
TINT_ASSERT(IR, lhs);
|
||||||
TINT_ASSERT(IR, rhs);
|
TINT_ASSERT(IR, rhs);
|
||||||
lhs_->AddUsage(this);
|
lhs_->AddUsage(this);
|
||||||
|
@ -51,7 +51,7 @@ class Binary : public utils::Castable<Binary, Instruction> {
|
|||||||
/// @param type the result type
|
/// @param type the result type
|
||||||
/// @param lhs the lhs of the instruction
|
/// @param lhs the lhs of the instruction
|
||||||
/// @param rhs the rhs of the instruction
|
/// @param rhs the rhs of the instruction
|
||||||
Binary(Kind kind, const type::Type* type, Value* lhs, Value* rhs);
|
Binary(enum Kind kind, const type::Type* type, Value* lhs, Value* rhs);
|
||||||
Binary(const Binary& inst) = delete;
|
Binary(const Binary& inst) = delete;
|
||||||
Binary(Binary&& inst) = delete;
|
Binary(Binary&& inst) = delete;
|
||||||
~Binary() override;
|
~Binary() override;
|
||||||
@ -59,8 +59,11 @@ class Binary : public utils::Castable<Binary, Instruction> {
|
|||||||
Binary& operator=(const Binary& inst) = delete;
|
Binary& operator=(const Binary& inst) = delete;
|
||||||
Binary& operator=(Binary&& inst) = delete;
|
Binary& operator=(Binary&& inst) = delete;
|
||||||
|
|
||||||
|
/// @returns the kind of the binary instruction
|
||||||
|
enum Kind Kind() const { return kind_; }
|
||||||
|
|
||||||
/// @returns the type of the value
|
/// @returns the type of the value
|
||||||
const type::Type* Type() const override { return result_type; }
|
const type::Type* Type() const override { return result_type_; }
|
||||||
|
|
||||||
/// @returns the left-hand-side value for the instruction
|
/// @returns the left-hand-side value for the instruction
|
||||||
const Value* LHS() const { return lhs_; }
|
const Value* LHS() const { return lhs_; }
|
||||||
@ -68,15 +71,11 @@ class Binary : public utils::Castable<Binary, Instruction> {
|
|||||||
/// @returns the right-hand-side value for the instruction
|
/// @returns the right-hand-side value for the instruction
|
||||||
const Value* RHS() const { return rhs_; }
|
const Value* RHS() const { return rhs_; }
|
||||||
|
|
||||||
/// the kind of binary instruction
|
|
||||||
Kind kind = Kind::kAdd;
|
|
||||||
|
|
||||||
/// the result type of the instruction
|
|
||||||
const type::Type* result_type = nullptr;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Value* lhs_ = nullptr;
|
enum Kind kind_;
|
||||||
Value* rhs_ = nullptr;
|
const type::Type* result_type_;
|
||||||
|
Value* lhs_;
|
||||||
|
Value* rhs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -30,17 +30,16 @@ TEST_F(IR_InstructionTest, CreateAnd) {
|
|||||||
const auto* inst = b.And(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.And(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kAnd);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kAnd);
|
||||||
ASSERT_NE(inst->result_type, nullptr);
|
|
||||||
ASSERT_NE(inst->Type(), nullptr);
|
ASSERT_NE(inst->Type(), nullptr);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -52,15 +51,15 @@ TEST_F(IR_InstructionTest, CreateOr) {
|
|||||||
const auto* inst = b.Or(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Or(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kOr);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kOr);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -72,15 +71,15 @@ TEST_F(IR_InstructionTest, CreateXor) {
|
|||||||
const auto* inst = b.Xor(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Xor(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kXor);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kXor);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -92,15 +91,15 @@ TEST_F(IR_InstructionTest, CreateEqual) {
|
|||||||
const auto* inst = b.Equal(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Equal(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kEqual);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kEqual);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -112,15 +111,15 @@ TEST_F(IR_InstructionTest, CreateNotEqual) {
|
|||||||
const auto* inst = b.NotEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.NotEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kNotEqual);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kNotEqual);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -132,15 +131,15 @@ TEST_F(IR_InstructionTest, CreateLessThan) {
|
|||||||
const auto* inst = b.LessThan(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.LessThan(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kLessThan);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kLessThan);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -153,15 +152,15 @@ TEST_F(IR_InstructionTest, CreateGreaterThan) {
|
|||||||
b.GreaterThan(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
b.GreaterThan(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kGreaterThan);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kGreaterThan);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -174,15 +173,15 @@ TEST_F(IR_InstructionTest, CreateLessThanEqual) {
|
|||||||
b.LessThanEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
b.LessThanEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kLessThanEqual);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kLessThanEqual);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -195,15 +194,15 @@ TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
|
|||||||
b.GreaterThanEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
b.GreaterThanEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kGreaterThanEqual);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kGreaterThanEqual);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -214,15 +213,15 @@ TEST_F(IR_InstructionTest, CreateNot) {
|
|||||||
const auto* inst = b.Not(b.ir.types.Get<type::Bool>(), b.Constant(true));
|
const auto* inst = b.Not(b.ir.types.Get<type::Bool>(), b.Constant(true));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kEqual);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kEqual);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<bool>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<bool>>());
|
||||||
EXPECT_TRUE(lhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
EXPECT_TRUE(lhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<bool>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<bool>>());
|
||||||
EXPECT_FALSE(rhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
EXPECT_FALSE(rhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
||||||
}
|
}
|
||||||
@ -234,15 +233,15 @@ TEST_F(IR_InstructionTest, CreateShiftLeft) {
|
|||||||
const auto* inst = b.ShiftLeft(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.ShiftLeft(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kShiftLeft);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kShiftLeft);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -254,15 +253,15 @@ TEST_F(IR_InstructionTest, CreateShiftRight) {
|
|||||||
const auto* inst = b.ShiftRight(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.ShiftRight(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kShiftRight);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kShiftRight);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -274,15 +273,15 @@ TEST_F(IR_InstructionTest, CreateAdd) {
|
|||||||
const auto* inst = b.Add(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Add(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kAdd);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kAdd);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -294,15 +293,15 @@ TEST_F(IR_InstructionTest, CreateSubtract) {
|
|||||||
const auto* inst = b.Subtract(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Subtract(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kSubtract);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kSubtract);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -314,15 +313,15 @@ TEST_F(IR_InstructionTest, CreateMultiply) {
|
|||||||
const auto* inst = b.Multiply(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Multiply(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kMultiply);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kMultiply);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -334,15 +333,15 @@ TEST_F(IR_InstructionTest, CreateDivide) {
|
|||||||
const auto* inst = b.Divide(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Divide(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kDivide);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kDivide);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -354,15 +353,15 @@ TEST_F(IR_InstructionTest, CreateModulo) {
|
|||||||
const auto* inst = b.Modulo(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.Modulo(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Binary>());
|
ASSERT_TRUE(inst->Is<Binary>());
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kModulo);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kModulo);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
ASSERT_TRUE(inst->LHS()->Is<Constant>());
|
||||||
auto lhs = inst->LHS()->As<Constant>()->value;
|
auto lhs = inst->LHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
ASSERT_TRUE(inst->RHS()->Is<Constant>());
|
||||||
auto rhs = inst->RHS()->As<Constant>()->value;
|
auto rhs = inst->RHS()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -372,7 +371,7 @@ TEST_F(IR_InstructionTest, Binary_Usage) {
|
|||||||
Builder b{mod};
|
Builder b{mod};
|
||||||
const auto* inst = b.And(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
const auto* inst = b.And(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
|
||||||
|
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kAnd);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kAnd);
|
||||||
|
|
||||||
ASSERT_NE(inst->LHS(), nullptr);
|
ASSERT_NE(inst->LHS(), nullptr);
|
||||||
ASSERT_EQ(inst->LHS()->Usage().Length(), 1u);
|
ASSERT_EQ(inst->LHS()->Usage().Length(), 1u);
|
||||||
@ -389,7 +388,7 @@ TEST_F(IR_InstructionTest, Binary_Usage_DuplicateValue) {
|
|||||||
auto val = b.Constant(4_i);
|
auto val = b.Constant(4_i);
|
||||||
const auto* inst = b.And(b.ir.types.Get<type::I32>(), val, val);
|
const auto* inst = b.And(b.ir.types.Get<type::I32>(), val, val);
|
||||||
|
|
||||||
EXPECT_EQ(inst->kind, Binary::Kind::kAnd);
|
EXPECT_EQ(inst->Kind(), Binary::Kind::kAnd);
|
||||||
ASSERT_EQ(inst->LHS(), inst->RHS());
|
ASSERT_EQ(inst->LHS(), inst->RHS());
|
||||||
|
|
||||||
ASSERT_NE(inst->LHS(), nullptr);
|
ASSERT_NE(inst->LHS(), nullptr);
|
||||||
|
@ -32,9 +32,10 @@ TEST_F(IR_InstructionTest, Bitcast) {
|
|||||||
ASSERT_TRUE(inst->Is<ir::Bitcast>());
|
ASSERT_TRUE(inst->Is<ir::Bitcast>());
|
||||||
ASSERT_NE(inst->Type(), nullptr);
|
ASSERT_NE(inst->Type(), nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(inst->args.Length(), 1u);
|
const auto args = inst->Args();
|
||||||
ASSERT_TRUE(inst->args[0]->Is<Constant>());
|
ASSERT_EQ(args.Length(), 1u);
|
||||||
auto val = inst->args[0]->As<Constant>()->value;
|
ASSERT_TRUE(args[0]->Is<Constant>());
|
||||||
|
auto val = args[0]->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(val->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(val->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, val->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, val->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -44,10 +45,11 @@ TEST_F(IR_InstructionTest, Bitcast_Usage) {
|
|||||||
Builder b{mod};
|
Builder b{mod};
|
||||||
const auto* inst = b.Bitcast(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
const auto* inst = b.Bitcast(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
||||||
|
|
||||||
ASSERT_EQ(inst->args.Length(), 1u);
|
const auto args = inst->Args();
|
||||||
ASSERT_NE(inst->args[0], nullptr);
|
ASSERT_EQ(args.Length(), 1u);
|
||||||
ASSERT_EQ(inst->args[0]->Usage().Length(), 1u);
|
ASSERT_NE(args[0], nullptr);
|
||||||
EXPECT_EQ(inst->args[0]->Usage()[0], inst);
|
ASSERT_EQ(args[0]->Usage().Length(), 1u);
|
||||||
|
EXPECT_EQ(args[0]->Usage()[0], inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -22,4 +22,13 @@ Block::Block() : Base() {}
|
|||||||
|
|
||||||
Block::~Block() = default;
|
Block::~Block() = default;
|
||||||
|
|
||||||
|
void Block::BranchTo(FlowNode* to, utils::VectorRef<Value*> args) {
|
||||||
|
TINT_ASSERT(IR, to);
|
||||||
|
branch_.target = to;
|
||||||
|
branch_.args = args;
|
||||||
|
if (to) {
|
||||||
|
to->AddInboundBranch(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
#ifndef SRC_TINT_IR_BLOCK_H_
|
#ifndef SRC_TINT_IR_BLOCK_H_
|
||||||
#define SRC_TINT_IR_BLOCK_H_
|
#define SRC_TINT_IR_BLOCK_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "src/tint/ir/block_param.h"
|
#include "src/tint/ir/block_param.h"
|
||||||
#include "src/tint/ir/branch.h"
|
#include "src/tint/ir/branch.h"
|
||||||
#include "src/tint/ir/flow_node.h"
|
#include "src/tint/ir/flow_node.h"
|
||||||
@ -30,20 +32,48 @@ class Block : public utils::Castable<Block, FlowNode> {
|
|||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
Block();
|
Block();
|
||||||
|
Block(const Block&) = delete;
|
||||||
|
Block(Block&&) = delete;
|
||||||
~Block() override;
|
~Block() override;
|
||||||
|
|
||||||
/// @returns true if this is a dead block. This can happen in the case like a loop merge block
|
Block& operator=(const Block&) = delete;
|
||||||
/// which is never reached.
|
Block& operator=(Block&&) = delete;
|
||||||
bool IsDead() const override { return branch.target == nullptr; }
|
|
||||||
|
|
||||||
/// The node this block branches too.
|
/// Sets the blocks branch target to the given node.
|
||||||
Branch branch = {};
|
/// @param to the node to branch too
|
||||||
|
/// @param args the branch arguments
|
||||||
|
void BranchTo(FlowNode* to, utils::VectorRef<Value*> args = {});
|
||||||
|
|
||||||
/// The instructions in the block
|
/// @returns true if this is block has a branch target set
|
||||||
utils::Vector<const Instruction*, 16> instructions;
|
bool HasBranchTarget() const override { return branch_.target != nullptr; }
|
||||||
|
|
||||||
/// The parameters passed into the block
|
/// @return the node this block branches too.
|
||||||
utils::Vector<const BlockParam*, 0> params;
|
const ir::Branch& Branch() const { return branch_; }
|
||||||
|
|
||||||
|
/// Sets the instructions in the block
|
||||||
|
/// @param instructions the instructions to set
|
||||||
|
void SetInstructions(utils::VectorRef<const Instruction*> instructions) {
|
||||||
|
instructions_ = std::move(instructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns the instructions in the block
|
||||||
|
utils::VectorRef<const Instruction*> Instructions() const { return instructions_; }
|
||||||
|
/// @returns the instructions in the block
|
||||||
|
utils::Vector<const Instruction*, 16>& Instructions() { return instructions_; }
|
||||||
|
|
||||||
|
/// Sets the params to the block
|
||||||
|
/// @param params the params for the block
|
||||||
|
void SetParams(utils::VectorRef<const BlockParam*> params) { params_ = std::move(params); }
|
||||||
|
/// @returns the params to the block
|
||||||
|
utils::Vector<const BlockParam*, 0>& Params() { return params_; }
|
||||||
|
|
||||||
|
/// @return the parameters passed into the block
|
||||||
|
utils::VectorRef<const BlockParam*> Params() const { return params_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ir::Branch branch_ = {};
|
||||||
|
utils::Vector<const Instruction*, 16> instructions_;
|
||||||
|
utils::Vector<const BlockParam*, 0> params_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -18,7 +18,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::BlockParam);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
BlockParam::BlockParam(const type::Type* ty) : type(ty) {}
|
BlockParam::BlockParam(const type::Type* ty) : type_(ty) {}
|
||||||
|
|
||||||
BlockParam::~BlockParam() = default;
|
BlockParam::~BlockParam() = default;
|
||||||
|
|
||||||
|
@ -34,10 +34,11 @@ class BlockParam : public utils::Castable<BlockParam, Value> {
|
|||||||
BlockParam& operator=(BlockParam&& inst) = delete;
|
BlockParam& operator=(BlockParam&& inst) = delete;
|
||||||
|
|
||||||
/// @returns the type of the var
|
/// @returns the type of the var
|
||||||
const type::Type* Type() const override { return type; }
|
const type::Type* Type() const override { return type_; }
|
||||||
|
|
||||||
|
private:
|
||||||
/// the result type of the instruction
|
/// the result type of the instruction
|
||||||
const type::Type* type = nullptr;
|
const type::Type* type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -32,7 +32,7 @@ ir::Block* Builder::CreateRootBlockIfNeeded() {
|
|||||||
|
|
||||||
// Everything in the module scope must have been const-eval's, so everything will go into a
|
// Everything in the module scope must have been const-eval's, so everything will go into a
|
||||||
// single block. So, we can create the root terminator for the root-block now.
|
// single block. So, we can create the root terminator for the root-block now.
|
||||||
ir.root_block->branch.target = CreateRootTerminator();
|
ir.root_block->BranchTo(CreateRootTerminator());
|
||||||
}
|
}
|
||||||
return ir.root_block;
|
return ir.root_block;
|
||||||
}
|
}
|
||||||
@ -56,11 +56,11 @@ Function* Builder::CreateFunction(Symbol name,
|
|||||||
TINT_ASSERT(IR, return_type);
|
TINT_ASSERT(IR, return_type);
|
||||||
|
|
||||||
auto* ir_func = ir.flow_nodes.Create<Function>(name, return_type, stage, wg_size);
|
auto* ir_func = ir.flow_nodes.Create<Function>(name, return_type, stage, wg_size);
|
||||||
ir_func->start_target = CreateBlock();
|
ir_func->SetStartTarget(CreateBlock());
|
||||||
ir_func->end_target = CreateFunctionTerminator();
|
ir_func->SetEndTarget(CreateFunctionTerminator());
|
||||||
|
|
||||||
// Function is always branching into the start target
|
// Function is always branching into the Start().target
|
||||||
ir_func->start_target->inbound_branches.Push(ir_func);
|
ir_func->StartTarget()->AddInboundBranch(ir_func);
|
||||||
|
|
||||||
return ir_func;
|
return ir_func;
|
||||||
}
|
}
|
||||||
@ -69,53 +69,48 @@ If* Builder::CreateIf(Value* condition) {
|
|||||||
TINT_ASSERT(IR, condition);
|
TINT_ASSERT(IR, condition);
|
||||||
|
|
||||||
auto* ir_if = ir.flow_nodes.Create<If>(condition);
|
auto* ir_if = ir.flow_nodes.Create<If>(condition);
|
||||||
ir_if->true_.target = CreateBlock();
|
ir_if->True().target = CreateBlock();
|
||||||
ir_if->false_.target = CreateBlock();
|
ir_if->False().target = CreateBlock();
|
||||||
ir_if->merge.target = CreateBlock();
|
ir_if->Merge().target = CreateBlock();
|
||||||
|
|
||||||
// An if always branches to both the true and false block.
|
// An if always branches to both the true and false block.
|
||||||
ir_if->true_.target->inbound_branches.Push(ir_if);
|
ir_if->True().target->AddInboundBranch(ir_if);
|
||||||
ir_if->false_.target->inbound_branches.Push(ir_if);
|
ir_if->False().target->AddInboundBranch(ir_if);
|
||||||
|
|
||||||
return ir_if;
|
return ir_if;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loop* Builder::CreateLoop() {
|
Loop* Builder::CreateLoop() {
|
||||||
auto* ir_loop = ir.flow_nodes.Create<Loop>();
|
auto* ir_loop = ir.flow_nodes.Create<Loop>();
|
||||||
ir_loop->start.target = CreateBlock();
|
ir_loop->Start().target = CreateBlock();
|
||||||
ir_loop->continuing.target = CreateBlock();
|
ir_loop->Continuing().target = CreateBlock();
|
||||||
ir_loop->merge.target = CreateBlock();
|
ir_loop->Merge().target = CreateBlock();
|
||||||
|
|
||||||
// A loop always branches to the start block.
|
// A loop always branches to the start block.
|
||||||
ir_loop->start.target->inbound_branches.Push(ir_loop);
|
ir_loop->Start().target->AddInboundBranch(ir_loop);
|
||||||
|
|
||||||
return ir_loop;
|
return ir_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
Switch* Builder::CreateSwitch(Value* condition) {
|
Switch* Builder::CreateSwitch(Value* condition) {
|
||||||
auto* ir_switch = ir.flow_nodes.Create<Switch>(condition);
|
auto* ir_switch = ir.flow_nodes.Create<Switch>(condition);
|
||||||
ir_switch->merge.target = CreateBlock();
|
ir_switch->Merge().target = CreateBlock();
|
||||||
return ir_switch;
|
return ir_switch;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block* Builder::CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> selectors) {
|
Block* Builder::CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> selectors) {
|
||||||
s->cases.Push(Switch::Case{selectors, {CreateBlock(), utils::Empty}});
|
s->Cases().Push(Switch::Case{selectors, {CreateBlock(), utils::Empty}});
|
||||||
|
|
||||||
Block* b = s->cases.Back().start.target->As<Block>();
|
Block* b = s->Cases().Back().Start().target->As<Block>();
|
||||||
// Switch branches into the case block
|
// Switch branches into the case block
|
||||||
b->inbound_branches.Push(s);
|
b->AddInboundBranch(s);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::Branch(Block* from, FlowNode* to, utils::VectorRef<Value*> args) {
|
Binary* Builder::CreateBinary(enum Binary::Kind kind,
|
||||||
TINT_ASSERT(IR, from);
|
const type::Type* type,
|
||||||
TINT_ASSERT(IR, to);
|
Value* lhs,
|
||||||
from->branch.target = to;
|
Value* rhs) {
|
||||||
from->branch.args = args;
|
|
||||||
to->inbound_branches.Push(from);
|
|
||||||
}
|
|
||||||
|
|
||||||
Binary* Builder::CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs) {
|
|
||||||
return ir.values.Create<ir::Binary>(kind, type, lhs, rhs);
|
return ir.values.Create<ir::Binary>(kind, type, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +178,7 @@ Binary* Builder::Modulo(const type::Type* type, Value* lhs, Value* rhs) {
|
|||||||
return CreateBinary(Binary::Kind::kModulo, type, lhs, rhs);
|
return CreateBinary(Binary::Kind::kModulo, type, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Unary* Builder::CreateUnary(Unary::Kind kind, const type::Type* type, Value* val) {
|
Unary* Builder::CreateUnary(enum Unary::Kind kind, const type::Type* type, Value* val) {
|
||||||
return ir.values.Create<ir::Unary>(kind, type, val);
|
return ir.values.Create<ir::Unary>(kind, type, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,12 +98,6 @@ class Builder {
|
|||||||
/// @returns the start block for the case flow node
|
/// @returns the start block for the case flow node
|
||||||
Block* CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> selectors);
|
Block* CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> selectors);
|
||||||
|
|
||||||
/// Branches the given block to the given flow node.
|
|
||||||
/// @param from the block to branch from
|
|
||||||
/// @param to the node to branch too
|
|
||||||
/// @param args arguments to the branch
|
|
||||||
void Branch(Block* from, FlowNode* to, utils::VectorRef<Value*> args = {});
|
|
||||||
|
|
||||||
/// Creates a constant::Value
|
/// Creates a constant::Value
|
||||||
/// @param args the arguments
|
/// @param args the arguments
|
||||||
/// @returns the new constant value
|
/// @returns the new constant value
|
||||||
@ -161,7 +155,7 @@ class Builder {
|
|||||||
/// @param lhs the left-hand-side of the operation
|
/// @param lhs the left-hand-side of the operation
|
||||||
/// @param rhs the right-hand-side of the operation
|
/// @param rhs the right-hand-side of the operation
|
||||||
/// @returns the operation
|
/// @returns the operation
|
||||||
Binary* CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs);
|
Binary* CreateBinary(enum Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs);
|
||||||
|
|
||||||
/// Creates an And operation
|
/// Creates an And operation
|
||||||
/// @param type the result type of the expression
|
/// @param type the result type of the expression
|
||||||
@ -280,7 +274,7 @@ class Builder {
|
|||||||
/// @param type the result type of the binary expression
|
/// @param type the result type of the binary expression
|
||||||
/// @param val the value of the operation
|
/// @param val the value of the operation
|
||||||
/// @returns the operation
|
/// @returns the operation
|
||||||
Unary* CreateUnary(Unary::Kind kind, const type::Type* type, Value* val);
|
Unary* CreateUnary(enum Unary::Kind kind, const type::Type* type, Value* val);
|
||||||
|
|
||||||
/// Creates a Complement operation
|
/// Creates a Complement operation
|
||||||
/// @param type the result type of the expression
|
/// @param type the result type of the expression
|
||||||
|
@ -21,8 +21,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Call);
|
|||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Call::Call(const type::Type* res_ty, utils::VectorRef<Value*> arguments)
|
Call::Call(const type::Type* res_ty, utils::VectorRef<Value*> arguments)
|
||||||
: result_type(res_ty), args(std::move(arguments)) {
|
: result_type_(res_ty), args_(std::move(arguments)) {
|
||||||
for (auto* arg : args) {
|
for (auto* arg : args_) {
|
||||||
arg->AddUsage(this);
|
arg->AddUsage(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,10 @@ class Call : public utils::Castable<Call, Instruction> {
|
|||||||
Call& operator=(Call&& inst) = delete;
|
Call& operator=(Call&& inst) = delete;
|
||||||
|
|
||||||
/// @returns the type of the value
|
/// @returns the type of the value
|
||||||
const type::Type* Type() const override { return result_type; }
|
const type::Type* Type() const override { return result_type_; }
|
||||||
|
|
||||||
/// The instruction type
|
/// @returns the call arguments
|
||||||
const type::Type* result_type = nullptr;
|
utils::VectorRef<Value*> Args() const { return args_; }
|
||||||
|
|
||||||
/// The constructor arguments
|
|
||||||
utils::Vector<Value*, 1> args;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
@ -46,6 +43,10 @@ class Call : public utils::Castable<Call, Instruction> {
|
|||||||
/// @param result_type the result type
|
/// @param result_type the result type
|
||||||
/// @param args the constructor arguments
|
/// @param args the constructor arguments
|
||||||
Call(const type::Type* result_type, utils::VectorRef<Value*> args);
|
Call(const type::Type* result_type, utils::VectorRef<Value*> args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const type::Type* result_type_;
|
||||||
|
utils::Vector<Value*, 1> args_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -18,7 +18,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Constant);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Constant::Constant(const constant::Value* val) : value(val) {}
|
Constant::Constant(const constant::Value* val) : value_(val) {}
|
||||||
|
|
||||||
Constant::~Constant() = default;
|
Constant::~Constant() = default;
|
||||||
|
|
||||||
|
@ -26,13 +26,21 @@ class Constant : public utils::Castable<Constant, Value> {
|
|||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param val the value stored in the constant
|
/// @param val the value stored in the constant
|
||||||
explicit Constant(const constant::Value* val);
|
explicit Constant(const constant::Value* val);
|
||||||
|
Constant(const Constant&) = delete;
|
||||||
|
Constant(Constant&&) = delete;
|
||||||
~Constant() override;
|
~Constant() override;
|
||||||
|
|
||||||
/// @returns the type of the constant
|
Constant& operator=(const Constant&) = delete;
|
||||||
const type::Type* Type() const override { return value->Type(); }
|
Constant& operator=(Constant&&) = delete;
|
||||||
|
|
||||||
/// The constants value
|
/// @returns the constants value
|
||||||
const constant::Value* const value;
|
const constant::Value* Value() const { return value_; }
|
||||||
|
|
||||||
|
/// @returns the type of the constant
|
||||||
|
const type::Type* Type() const override { return value_->Type(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const constant::Value* const value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -30,13 +30,13 @@ TEST_F(IR_ConstantTest, f32) {
|
|||||||
utils::StringStream str;
|
utils::StringStream str;
|
||||||
|
|
||||||
auto* c = b.Constant(1.2_f);
|
auto* c = b.Constant(1.2_f);
|
||||||
EXPECT_EQ(1.2_f, c->value->As<constant::Scalar<f32>>()->ValueAs<f32>());
|
EXPECT_EQ(1.2_f, c->Value()->As<constant::Scalar<f32>>()->ValueAs<f32>());
|
||||||
|
|
||||||
EXPECT_TRUE(c->value->Is<constant::Scalar<f32>>());
|
EXPECT_TRUE(c->Value()->Is<constant::Scalar<f32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_ConstantTest, f16) {
|
TEST_F(IR_ConstantTest, f16) {
|
||||||
@ -46,13 +46,13 @@ TEST_F(IR_ConstantTest, f16) {
|
|||||||
utils::StringStream str;
|
utils::StringStream str;
|
||||||
|
|
||||||
auto* c = b.Constant(1.1_h);
|
auto* c = b.Constant(1.1_h);
|
||||||
EXPECT_EQ(1.1_h, c->value->As<constant::Scalar<f16>>()->ValueAs<f16>());
|
EXPECT_EQ(1.1_h, c->Value()->As<constant::Scalar<f16>>()->ValueAs<f16>());
|
||||||
|
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
|
||||||
EXPECT_TRUE(c->value->Is<constant::Scalar<f16>>());
|
EXPECT_TRUE(c->Value()->Is<constant::Scalar<f16>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_ConstantTest, i32) {
|
TEST_F(IR_ConstantTest, i32) {
|
||||||
@ -62,13 +62,13 @@ TEST_F(IR_ConstantTest, i32) {
|
|||||||
utils::StringStream str;
|
utils::StringStream str;
|
||||||
|
|
||||||
auto* c = b.Constant(1_i);
|
auto* c = b.Constant(1_i);
|
||||||
EXPECT_EQ(1_i, c->value->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(1_i, c->Value()->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
|
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
|
||||||
EXPECT_TRUE(c->value->Is<constant::Scalar<i32>>());
|
EXPECT_TRUE(c->Value()->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_ConstantTest, u32) {
|
TEST_F(IR_ConstantTest, u32) {
|
||||||
@ -78,13 +78,13 @@ TEST_F(IR_ConstantTest, u32) {
|
|||||||
utils::StringStream str;
|
utils::StringStream str;
|
||||||
|
|
||||||
auto* c = b.Constant(2_u);
|
auto* c = b.Constant(2_u);
|
||||||
EXPECT_EQ(2_u, c->value->As<constant::Scalar<u32>>()->ValueAs<u32>());
|
EXPECT_EQ(2_u, c->Value()->As<constant::Scalar<u32>>()->ValueAs<u32>());
|
||||||
|
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_TRUE(c->value->Is<constant::Scalar<u32>>());
|
EXPECT_TRUE(c->Value()->Is<constant::Scalar<u32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_ConstantTest, bool) {
|
TEST_F(IR_ConstantTest, bool) {
|
||||||
@ -95,19 +95,19 @@ TEST_F(IR_ConstantTest, bool) {
|
|||||||
utils::StringStream str;
|
utils::StringStream str;
|
||||||
|
|
||||||
auto* c = b.Constant(false);
|
auto* c = b.Constant(false);
|
||||||
EXPECT_FALSE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
EXPECT_FALSE(c->Value()->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
utils::StringStream str;
|
utils::StringStream str;
|
||||||
auto c = b.Constant(true);
|
auto c = b.Constant(true);
|
||||||
EXPECT_TRUE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
EXPECT_TRUE(c->Value()->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
||||||
|
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
|
EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
|
||||||
EXPECT_TRUE(c->value->Is<constant::Scalar<bool>>());
|
EXPECT_TRUE(c->Value()->Is<constant::Scalar<bool>>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,81 +60,81 @@ std::string Debug::AsDotGraph(const Module* mod) {
|
|||||||
if (node_to_name.count(b) == 0) {
|
if (node_to_name.count(b) == 0) {
|
||||||
out << name_for(b) << R"( [label="block"])" << std::endl;
|
out << name_for(b) << R"( [label="block"])" << std::endl;
|
||||||
}
|
}
|
||||||
out << name_for(b) << " -> " << name_for(b->branch.target);
|
out << name_for(b) << " -> " << name_for(b->Branch().target);
|
||||||
|
|
||||||
// Dashed lines to merge blocks
|
// Dashed lines to merge blocks
|
||||||
if (merge_nodes.count(b->branch.target) != 0) {
|
if (merge_nodes.count(b->Branch().target) != 0) {
|
||||||
out << " [style=dashed]";
|
out << " [style=dashed]";
|
||||||
}
|
}
|
||||||
|
|
||||||
out << std::endl;
|
out << std::endl;
|
||||||
Graph(b->branch.target);
|
Graph(b->Branch().target);
|
||||||
},
|
},
|
||||||
[&](const ir::Switch* s) {
|
[&](const ir::Switch* s) {
|
||||||
out << name_for(s) << R"( [label="switch"])" << std::endl;
|
out << name_for(s) << R"( [label="switch"])" << std::endl;
|
||||||
out << name_for(s->merge.target) << R"( [label="switch merge"])" << std::endl;
|
out << name_for(s->Merge().target) << R"( [label="switch merge"])" << std::endl;
|
||||||
merge_nodes.insert(s->merge.target);
|
merge_nodes.insert(s->Merge().target);
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (const auto& c : s->cases) {
|
for (const auto& c : s->Cases()) {
|
||||||
out << name_for(c.start.target)
|
out << name_for(c.Start().target)
|
||||||
<< R"( [label="case )" + std::to_string(i++) + R"("])" << std::endl;
|
<< R"( [label="case )" + std::to_string(i++) + R"("])" << std::endl;
|
||||||
}
|
}
|
||||||
out << name_for(s) << " -> {";
|
out << name_for(s) << " -> {";
|
||||||
for (const auto& c : s->cases) {
|
for (const auto& c : s->Cases()) {
|
||||||
if (&c != &(s->cases[0])) {
|
if (&c != &(s->Cases().Front())) {
|
||||||
out << ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
out << name_for(c.start.target);
|
out << name_for(c.Start().target);
|
||||||
}
|
}
|
||||||
out << "}" << std::endl;
|
out << "}" << std::endl;
|
||||||
|
|
||||||
for (const auto& c : s->cases) {
|
for (const auto& c : s->Cases()) {
|
||||||
Graph(c.start.target);
|
Graph(c.Start().target);
|
||||||
}
|
}
|
||||||
Graph(s->merge.target);
|
Graph(s->Merge().target);
|
||||||
},
|
},
|
||||||
[&](const ir::If* i) {
|
[&](const ir::If* i) {
|
||||||
out << name_for(i) << R"( [label="if"])" << std::endl;
|
out << name_for(i) << R"( [label="if"])" << std::endl;
|
||||||
out << name_for(i->true_.target) << R"( [label="true"])" << std::endl;
|
out << name_for(i->True().target) << R"( [label="true"])" << std::endl;
|
||||||
out << name_for(i->false_.target) << R"( [label="false"])" << std::endl;
|
out << name_for(i->False().target) << R"( [label="false"])" << std::endl;
|
||||||
out << name_for(i->merge.target) << R"( [label="if merge"])" << std::endl;
|
out << name_for(i->Merge().target) << R"( [label="if merge"])" << std::endl;
|
||||||
merge_nodes.insert(i->merge.target);
|
merge_nodes.insert(i->Merge().target);
|
||||||
|
|
||||||
out << name_for(i) << " -> {";
|
out << name_for(i) << " -> {";
|
||||||
out << name_for(i->true_.target) << ", " << name_for(i->false_.target);
|
out << name_for(i->True().target) << ", " << name_for(i->False().target);
|
||||||
out << "}" << std::endl;
|
out << "}" << std::endl;
|
||||||
|
|
||||||
// Subgraph if true/false branches so they draw on the same line
|
// Subgraph if true/false branches so they draw on the same line
|
||||||
out << "subgraph sub_" << name_for(i) << " {" << std::endl;
|
out << "subgraph sub_" << name_for(i) << " {" << std::endl;
|
||||||
out << R"(rank="same")" << std::endl;
|
out << R"(rank="same")" << std::endl;
|
||||||
out << name_for(i->true_.target) << std::endl;
|
out << name_for(i->True().target) << std::endl;
|
||||||
out << name_for(i->false_.target) << std::endl;
|
out << name_for(i->False().target) << std::endl;
|
||||||
out << "}" << std::endl;
|
out << "}" << std::endl;
|
||||||
|
|
||||||
Graph(i->true_.target);
|
Graph(i->True().target);
|
||||||
Graph(i->false_.target);
|
Graph(i->False().target);
|
||||||
Graph(i->merge.target);
|
Graph(i->Merge().target);
|
||||||
},
|
},
|
||||||
[&](const ir::Loop* l) {
|
[&](const ir::Loop* l) {
|
||||||
out << name_for(l) << R"( [label="loop"])" << std::endl;
|
out << name_for(l) << R"( [label="loop"])" << std::endl;
|
||||||
out << name_for(l->start.target) << R"( [label="start"])" << std::endl;
|
out << name_for(l->Start().target) << R"( [label="start"])" << std::endl;
|
||||||
out << name_for(l->continuing.target) << R"( [label="continuing"])" << std::endl;
|
out << name_for(l->Continuing().target) << R"( [label="continuing"])" << std::endl;
|
||||||
out << name_for(l->merge.target) << R"( [label="loop merge"])" << std::endl;
|
out << name_for(l->Merge().target) << R"( [label="loop merge"])" << std::endl;
|
||||||
merge_nodes.insert(l->merge.target);
|
merge_nodes.insert(l->Merge().target);
|
||||||
|
|
||||||
// Subgraph the continuing and merge so they get drawn on the same line
|
// Subgraph the continuing and merge so they get drawn on the same line
|
||||||
out << "subgraph sub_" << name_for(l) << " {" << std::endl;
|
out << "subgraph sub_" << name_for(l) << " {" << std::endl;
|
||||||
out << R"(rank="same")" << std::endl;
|
out << R"(rank="same")" << std::endl;
|
||||||
out << name_for(l->continuing.target) << std::endl;
|
out << name_for(l->Continuing().target) << std::endl;
|
||||||
out << name_for(l->merge.target) << std::endl;
|
out << name_for(l->Merge().target) << std::endl;
|
||||||
out << "}" << std::endl;
|
out << "}" << std::endl;
|
||||||
|
|
||||||
out << name_for(l) << " -> " << name_for(l->start.target) << std::endl;
|
out << name_for(l) << " -> " << name_for(l->Start().target) << std::endl;
|
||||||
|
|
||||||
Graph(l->start.target);
|
Graph(l->Start().target);
|
||||||
Graph(l->continuing.target);
|
Graph(l->Continuing().target);
|
||||||
Graph(l->merge.target);
|
Graph(l->Merge().target);
|
||||||
},
|
},
|
||||||
[&](const ir::FunctionTerminator*) {
|
[&](const ir::FunctionTerminator*) {
|
||||||
// Already done
|
// Already done
|
||||||
@ -145,10 +145,10 @@ std::string Debug::AsDotGraph(const Module* mod) {
|
|||||||
for (const auto* func : mod->functions) {
|
for (const auto* func : mod->functions) {
|
||||||
// Cluster each function to label and draw a box around it.
|
// Cluster each function to label and draw a box around it.
|
||||||
out << "subgraph cluster_" << name_for(func) << " {" << std::endl;
|
out << "subgraph cluster_" << name_for(func) << " {" << std::endl;
|
||||||
out << R"(label=")" << func->name.Name() << R"(")" << std::endl;
|
out << R"(label=")" << func->Name().Name() << R"(")" << std::endl;
|
||||||
out << name_for(func->start_target) << R"( [label="start"])" << std::endl;
|
out << name_for(func->StartTarget()) << R"( [label="start"])" << std::endl;
|
||||||
out << name_for(func->end_target) << R"( [label="end"])" << std::endl;
|
out << name_for(func->EndTarget()) << R"( [label="end"])" << std::endl;
|
||||||
Graph(func->start_target);
|
Graph(func->StartTarget());
|
||||||
out << "}" << std::endl;
|
out << "}" << std::endl;
|
||||||
}
|
}
|
||||||
out << "}";
|
out << "}";
|
||||||
|
@ -81,7 +81,7 @@ utils::StringStream& Disassembler::Indent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Disassembler::EmitBlockInstructions(const Block* b) {
|
void Disassembler::EmitBlockInstructions(const Block* b) {
|
||||||
for (const auto* inst : b->instructions) {
|
for (const auto* inst : b->Instructions()) {
|
||||||
Indent();
|
Indent();
|
||||||
EmitInstruction(inst);
|
EmitInstruction(inst);
|
||||||
out_ << std::endl;
|
out_ << std::endl;
|
||||||
@ -114,31 +114,31 @@ void Disassembler::Walk(const FlowNode* node) {
|
|||||||
[&](const ir::Function* f) {
|
[&](const ir::Function* f) {
|
||||||
TINT_SCOPED_ASSIGNMENT(in_function_, true);
|
TINT_SCOPED_ASSIGNMENT(in_function_, true);
|
||||||
|
|
||||||
Indent() << "%fn" << IdOf(f) << " = func " << f->name.Name() << "(";
|
Indent() << "%fn" << IdOf(f) << " = func " << f->Name().Name() << "(";
|
||||||
for (auto* p : f->params) {
|
for (auto* p : f->Params()) {
|
||||||
if (p != f->params.Front()) {
|
if (p != f->Params().Front()) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
}
|
}
|
||||||
out_ << "%" << IdOf(p) << ":" << p->type->FriendlyName();
|
out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName();
|
||||||
}
|
}
|
||||||
out_ << "):" << f->return_type->FriendlyName();
|
out_ << "):" << f->ReturnType()->FriendlyName();
|
||||||
|
|
||||||
if (f->pipeline_stage != Function::PipelineStage::kUndefined) {
|
if (f->Stage() != Function::PipelineStage::kUndefined) {
|
||||||
out_ << " [@" << f->pipeline_stage;
|
out_ << " [@" << f->Stage();
|
||||||
|
|
||||||
if (f->workgroup_size) {
|
if (f->WorkgroupSize()) {
|
||||||
auto arr = f->workgroup_size.value();
|
auto arr = f->WorkgroupSize().value();
|
||||||
out_ << " @workgroup_size(" << arr[0] << ", " << arr[1] << ", " << arr[2]
|
out_ << " @workgroup_size(" << arr[0] << ", " << arr[1] << ", " << arr[2]
|
||||||
<< ")";
|
<< ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!f->return_attributes.IsEmpty()) {
|
if (!f->ReturnAttributes().IsEmpty()) {
|
||||||
out_ << " ra:";
|
out_ << " ra:";
|
||||||
|
|
||||||
for (auto attr : f->return_attributes) {
|
for (auto attr : f->ReturnAttributes()) {
|
||||||
out_ << " @" << attr;
|
out_ << " @" << attr;
|
||||||
if (attr == Function::ReturnAttribute::kLocation) {
|
if (attr == Function::ReturnAttribute::kLocation) {
|
||||||
out_ << "(" << f->return_location.value() << ")";
|
out_ << "(" << f->ReturnLocation().value() << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,23 +149,23 @@ void Disassembler::Walk(const FlowNode* node) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
ScopedIndent func_indent(indent_size_);
|
ScopedIndent func_indent(indent_size_);
|
||||||
ScopedStopNode scope(stop_nodes_, f->end_target);
|
ScopedStopNode scope(stop_nodes_, f->EndTarget());
|
||||||
Walk(f->start_target);
|
Walk(f->StartTarget());
|
||||||
}
|
}
|
||||||
out_ << "} ";
|
out_ << "} ";
|
||||||
Walk(f->end_target);
|
Walk(f->EndTarget());
|
||||||
},
|
},
|
||||||
[&](const ir::Block* b) {
|
[&](const ir::Block* b) {
|
||||||
// If this block is dead, nothing to do
|
// If this block is dead, nothing to do
|
||||||
if (b->IsDead()) {
|
if (!b->HasBranchTarget()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Indent() << "%fn" << IdOf(b) << " = block";
|
Indent() << "%fn" << IdOf(b) << " = block";
|
||||||
if (!b->params.IsEmpty()) {
|
if (!b->Params().IsEmpty()) {
|
||||||
out_ << " (";
|
out_ << " (";
|
||||||
for (auto* p : b->params) {
|
for (const auto* p : b->Params()) {
|
||||||
if (p != b->params.Front()) {
|
if (p != b->Params().Front()) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
}
|
}
|
||||||
EmitValue(p);
|
EmitValue(p);
|
||||||
@ -181,20 +181,20 @@ void Disassembler::Walk(const FlowNode* node) {
|
|||||||
Indent() << "}";
|
Indent() << "}";
|
||||||
|
|
||||||
std::string suffix = "";
|
std::string suffix = "";
|
||||||
if (b->branch.target->Is<FunctionTerminator>()) {
|
if (b->Branch().target->Is<FunctionTerminator>()) {
|
||||||
out_ << " -> %func_end";
|
out_ << " -> %func_end";
|
||||||
suffix = "return";
|
suffix = "return";
|
||||||
} else if (b->branch.target->Is<RootTerminator>()) {
|
} else if (b->Branch().target->Is<RootTerminator>()) {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
} else {
|
} else {
|
||||||
out_ << " -> "
|
out_ << " -> "
|
||||||
<< "%fn" << IdOf(b->branch.target);
|
<< "%fn" << IdOf(b->Branch().target);
|
||||||
suffix = "branch";
|
suffix = "branch";
|
||||||
}
|
}
|
||||||
if (!b->branch.args.IsEmpty()) {
|
if (!b->Branch().args.IsEmpty()) {
|
||||||
out_ << " ";
|
out_ << " ";
|
||||||
for (const auto* v : b->branch.args) {
|
for (const auto* v : b->Branch().args) {
|
||||||
if (v != b->branch.args.Front()) {
|
if (v != b->Branch().args.Front()) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
}
|
}
|
||||||
EmitValue(v);
|
EmitValue(v);
|
||||||
@ -205,18 +205,18 @@ void Disassembler::Walk(const FlowNode* node) {
|
|||||||
}
|
}
|
||||||
out_ << std::endl;
|
out_ << std::endl;
|
||||||
|
|
||||||
if (!b->branch.target->Is<FunctionTerminator>()) {
|
if (!b->Branch().target->Is<FunctionTerminator>()) {
|
||||||
out_ << std::endl;
|
out_ << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
Walk(b->branch.target);
|
Walk(b->Branch().target);
|
||||||
},
|
},
|
||||||
[&](const ir::Switch* s) {
|
[&](const ir::Switch* s) {
|
||||||
Indent() << "%fn" << IdOf(s) << " = switch ";
|
Indent() << "%fn" << IdOf(s) << " = switch ";
|
||||||
EmitValue(s->condition);
|
EmitValue(s->Condition());
|
||||||
out_ << " [";
|
out_ << " [";
|
||||||
for (const auto& c : s->cases) {
|
for (const auto& c : s->Cases()) {
|
||||||
if (&c != &s->cases.Front()) {
|
if (&c != &s->Cases().Front()) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
}
|
}
|
||||||
out_ << "c: (";
|
out_ << "c: (";
|
||||||
@ -231,17 +231,17 @@ void Disassembler::Walk(const FlowNode* node) {
|
|||||||
EmitValue(selector.val);
|
EmitValue(selector.val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out_ << ", %fn" << IdOf(c.start.target) << ")";
|
out_ << ", %fn" << IdOf(c.Start().target) << ")";
|
||||||
}
|
}
|
||||||
if (s->merge.target->IsConnected()) {
|
if (s->Merge().target->IsConnected()) {
|
||||||
out_ << ", m: %fn" << IdOf(s->merge.target);
|
out_ << ", m: %fn" << IdOf(s->Merge().target);
|
||||||
}
|
}
|
||||||
out_ << "]" << std::endl;
|
out_ << "]" << std::endl;
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopedIndent switch_indent(indent_size_);
|
ScopedIndent switch_indent(indent_size_);
|
||||||
ScopedStopNode scope(stop_nodes_, s->merge.target);
|
ScopedStopNode scope(stop_nodes_, s->Merge().target);
|
||||||
for (const auto& c : s->cases) {
|
for (const auto& c : s->Cases()) {
|
||||||
Indent() << "# case ";
|
Indent() << "# case ";
|
||||||
for (const auto& selector : c.selectors) {
|
for (const auto& selector : c.selectors) {
|
||||||
if (&selector != &c.selectors.Front()) {
|
if (&selector != &c.selectors.Front()) {
|
||||||
@ -255,86 +255,86 @@ void Disassembler::Walk(const FlowNode* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
out_ << std::endl;
|
out_ << std::endl;
|
||||||
Walk(c.start.target);
|
Walk(c.Start().target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->merge.target->IsConnected()) {
|
if (s->Merge().target->IsConnected()) {
|
||||||
Indent() << "# switch merge" << std::endl;
|
Indent() << "# switch merge" << std::endl;
|
||||||
Walk(s->merge.target);
|
Walk(s->Merge().target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](const ir::If* i) {
|
[&](const ir::If* i) {
|
||||||
Indent() << "%fn" << IdOf(i) << " = if ";
|
Indent() << "%fn" << IdOf(i) << " = if ";
|
||||||
EmitValue(i->condition);
|
EmitValue(i->Condition());
|
||||||
|
|
||||||
bool has_true = !i->true_.target->IsDead();
|
bool has_true = i->True().target->HasBranchTarget();
|
||||||
bool has_false = !i->false_.target->IsDead();
|
bool has_false = i->False().target->HasBranchTarget();
|
||||||
|
|
||||||
out_ << " [";
|
out_ << " [";
|
||||||
if (has_true) {
|
if (has_true) {
|
||||||
out_ << "t: %fn" << IdOf(i->true_.target);
|
out_ << "t: %fn" << IdOf(i->True().target);
|
||||||
}
|
}
|
||||||
if (has_false) {
|
if (has_false) {
|
||||||
if (has_true) {
|
if (has_true) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
}
|
}
|
||||||
out_ << "f: %fn" << IdOf(i->false_.target);
|
out_ << "f: %fn" << IdOf(i->False().target);
|
||||||
}
|
}
|
||||||
if (i->merge.target->IsConnected()) {
|
if (i->Merge().target->IsConnected()) {
|
||||||
out_ << ", m: %fn" << IdOf(i->merge.target);
|
out_ << ", m: %fn" << IdOf(i->Merge().target);
|
||||||
}
|
}
|
||||||
out_ << "]" << std::endl;
|
out_ << "]" << std::endl;
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopedIndent if_indent(indent_size_);
|
ScopedIndent if_indent(indent_size_);
|
||||||
ScopedStopNode scope(stop_nodes_, i->merge.target);
|
ScopedStopNode scope(stop_nodes_, i->Merge().target);
|
||||||
|
|
||||||
if (has_true) {
|
if (has_true) {
|
||||||
Indent() << "# true branch" << std::endl;
|
Indent() << "# true branch" << std::endl;
|
||||||
Walk(i->true_.target);
|
Walk(i->True().target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_false) {
|
if (has_false) {
|
||||||
Indent() << "# false branch" << std::endl;
|
Indent() << "# false branch" << std::endl;
|
||||||
Walk(i->false_.target);
|
Walk(i->False().target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i->merge.target->IsConnected()) {
|
if (i->Merge().target->IsConnected()) {
|
||||||
Indent() << "# if merge" << std::endl;
|
Indent() << "# if merge" << std::endl;
|
||||||
Walk(i->merge.target);
|
Walk(i->Merge().target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](const ir::Loop* l) {
|
[&](const ir::Loop* l) {
|
||||||
Indent() << "%fn" << IdOf(l) << " = loop [s: %fn" << IdOf(l->start.target);
|
Indent() << "%fn" << IdOf(l) << " = loop [s: %fn" << IdOf(l->Start().target);
|
||||||
|
|
||||||
if (l->continuing.target->IsConnected()) {
|
if (l->Continuing().target->IsConnected()) {
|
||||||
out_ << ", c: %fn" << IdOf(l->continuing.target);
|
out_ << ", c: %fn" << IdOf(l->Continuing().target);
|
||||||
}
|
}
|
||||||
if (l->merge.target->IsConnected()) {
|
if (l->Merge().target->IsConnected()) {
|
||||||
out_ << ", m: %fn" << IdOf(l->merge.target);
|
out_ << ", m: %fn" << IdOf(l->Merge().target);
|
||||||
}
|
}
|
||||||
out_ << "]" << std::endl;
|
out_ << "]" << std::endl;
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopedStopNode loop_scope(stop_nodes_, l->merge.target);
|
ScopedStopNode loop_scope(stop_nodes_, l->Merge().target);
|
||||||
ScopedIndent loop_indent(indent_size_);
|
ScopedIndent loop_indent(indent_size_);
|
||||||
{
|
{
|
||||||
ScopedStopNode inner_scope(stop_nodes_, l->continuing.target);
|
ScopedStopNode inner_scope(stop_nodes_, l->Continuing().target);
|
||||||
Indent() << "# loop start" << std::endl;
|
Indent() << "# loop start" << std::endl;
|
||||||
Walk(l->start.target);
|
Walk(l->Start().target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->continuing.target->IsConnected()) {
|
if (l->Continuing().target->IsConnected()) {
|
||||||
Indent() << "# loop continuing" << std::endl;
|
Indent() << "# loop continuing" << std::endl;
|
||||||
Walk(l->continuing.target);
|
Walk(l->Continuing().target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->merge.target->IsConnected()) {
|
if (l->Merge().target->IsConnected()) {
|
||||||
Indent() << "# loop merge" << std::endl;
|
Indent() << "# loop merge" << std::endl;
|
||||||
Walk(l->merge.target);
|
Walk(l->Merge().target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](const ir::FunctionTerminator*) {
|
[&](const ir::FunctionTerminator*) {
|
||||||
@ -407,7 +407,7 @@ void Disassembler::EmitValue(const Value* val) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
emit(constant->value);
|
emit(constant->Value());
|
||||||
},
|
},
|
||||||
[&](const ir::Instruction* i) { out_ << "%" << IdOf(i); },
|
[&](const ir::Instruction* i) { out_ << "%" << IdOf(i); },
|
||||||
[&](const ir::BlockParam* p) {
|
[&](const ir::BlockParam* p) {
|
||||||
@ -445,18 +445,18 @@ void Disassembler::EmitInstruction(const Instruction* inst) {
|
|||||||
[&](const ir::Load* l) {
|
[&](const ir::Load* l) {
|
||||||
EmitValueWithType(l);
|
EmitValueWithType(l);
|
||||||
out_ << " = load ";
|
out_ << " = load ";
|
||||||
EmitValue(l->from);
|
EmitValue(l->From());
|
||||||
},
|
},
|
||||||
[&](const ir::Store* s) {
|
[&](const ir::Store* s) {
|
||||||
out_ << "store ";
|
out_ << "store ";
|
||||||
EmitValue(s->to);
|
EmitValue(s->To());
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
EmitValue(s->from);
|
EmitValue(s->From());
|
||||||
},
|
},
|
||||||
[&](const ir::UserCall* uc) {
|
[&](const ir::UserCall* uc) {
|
||||||
EmitValueWithType(uc);
|
EmitValueWithType(uc);
|
||||||
out_ << " = call " << uc->name.Name();
|
out_ << " = call " << uc->Name().Name();
|
||||||
if (uc->args.Length() > 0) {
|
if (!uc->Args().IsEmpty()) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
}
|
}
|
||||||
EmitArgs(uc);
|
EmitArgs(uc);
|
||||||
@ -464,16 +464,16 @@ void Disassembler::EmitInstruction(const Instruction* inst) {
|
|||||||
[&](const ir::Var* v) {
|
[&](const ir::Var* v) {
|
||||||
EmitValueWithType(v);
|
EmitValueWithType(v);
|
||||||
out_ << " = var";
|
out_ << " = var";
|
||||||
if (v->initializer) {
|
if (v->Initializer()) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
EmitValue(v->initializer);
|
EmitValue(v->Initializer());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Disassembler::EmitArgs(const Call* call) {
|
void Disassembler::EmitArgs(const Call* call) {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (const auto* arg : call->args) {
|
for (const auto* arg : call->Args()) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
out_ << ", ";
|
out_ << ", ";
|
||||||
}
|
}
|
||||||
@ -485,7 +485,7 @@ void Disassembler::EmitArgs(const Call* call) {
|
|||||||
void Disassembler::EmitBinary(const Binary* b) {
|
void Disassembler::EmitBinary(const Binary* b) {
|
||||||
EmitValueWithType(b);
|
EmitValueWithType(b);
|
||||||
out_ << " = ";
|
out_ << " = ";
|
||||||
switch (b->kind) {
|
switch (b->Kind()) {
|
||||||
case Binary::Kind::kAdd:
|
case Binary::Kind::kAdd:
|
||||||
out_ << "add";
|
out_ << "add";
|
||||||
break;
|
break;
|
||||||
@ -544,7 +544,7 @@ void Disassembler::EmitBinary(const Binary* b) {
|
|||||||
void Disassembler::EmitUnary(const Unary* u) {
|
void Disassembler::EmitUnary(const Unary* u) {
|
||||||
EmitValueWithType(u);
|
EmitValueWithType(u);
|
||||||
out_ << " = ";
|
out_ << " = ";
|
||||||
switch (u->kind) {
|
switch (u->Kind()) {
|
||||||
case Unary::Kind::kComplement:
|
case Unary::Kind::kComplement:
|
||||||
out_ << "complement";
|
out_ << "complement";
|
||||||
break;
|
break;
|
||||||
|
@ -25,22 +25,30 @@ class FlowNode : public utils::Castable<FlowNode> {
|
|||||||
public:
|
public:
|
||||||
~FlowNode() override;
|
~FlowNode() override;
|
||||||
|
|
||||||
/// The list of flow nodes which branch into this node. This list maybe empty for several
|
|
||||||
/// reasons:
|
|
||||||
/// - Node is a start node
|
|
||||||
/// - Node is a merge target outside control flow (if that returns in both branches)
|
|
||||||
/// - Node is a continue target outside control flow (loop that returns)
|
|
||||||
utils::Vector<FlowNode*, 2> inbound_branches;
|
|
||||||
|
|
||||||
/// @returns true if this node has inbound branches and branches out
|
/// @returns true if this node has inbound branches and branches out
|
||||||
bool IsConnected() const { return !IsDead() && !inbound_branches.IsEmpty(); }
|
bool IsConnected() const { return HasBranchTarget() && !inbound_branches_.IsEmpty(); }
|
||||||
|
|
||||||
/// @returns true if the node does not branch out
|
/// @returns true if the node has a branch target
|
||||||
virtual bool IsDead() const { return false; }
|
virtual bool HasBranchTarget() const { return false; }
|
||||||
|
|
||||||
|
/// @returns the inbound branch list for the flow node
|
||||||
|
utils::VectorRef<FlowNode*> InboundBranches() const { return inbound_branches_; }
|
||||||
|
|
||||||
|
/// Adds the given node to the inbound branches
|
||||||
|
/// @param node the node to add
|
||||||
|
void AddInboundBranch(FlowNode* node) { inbound_branches_.Push(node); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
FlowNode();
|
FlowNode();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The list of flow nodes which branch into this node. This list maybe empty for several
|
||||||
|
/// reasons:
|
||||||
|
/// - Node is a start node
|
||||||
|
/// - Node is a merge target outside control flow (e.g. an if that returns in both branches)
|
||||||
|
/// - Node is a continue target outside control flow (e.g. a loop that returns)
|
||||||
|
utils::Vector<FlowNode*, 2> inbound_branches_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -98,17 +98,13 @@ namespace {
|
|||||||
|
|
||||||
using ResultType = utils::Result<Module, diag::List>;
|
using ResultType = utils::Result<Module, diag::List>;
|
||||||
|
|
||||||
bool IsBranched(const Block* b) {
|
|
||||||
return b->branch.target != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsConnected(const FlowNode* b) {
|
bool IsConnected(const FlowNode* b) {
|
||||||
// Function is always connected as it's the start.
|
// Function is always connected as it's the start.
|
||||||
if (b->Is<ir::Function>()) {
|
if (b->Is<ir::Function>()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* parent : b->inbound_branches) {
|
for (auto* parent : b->InboundBranches()) {
|
||||||
if (IsConnected(parent)) {
|
if (IsConnected(parent)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -184,14 +180,14 @@ class Impl {
|
|||||||
|
|
||||||
void BranchTo(FlowNode* node, utils::VectorRef<Value*> args = {}) {
|
void BranchTo(FlowNode* node, utils::VectorRef<Value*> args = {}) {
|
||||||
TINT_ASSERT(IR, current_flow_block_);
|
TINT_ASSERT(IR, current_flow_block_);
|
||||||
TINT_ASSERT(IR, !IsBranched(current_flow_block_));
|
TINT_ASSERT(IR, !current_flow_block_->HasBranchTarget());
|
||||||
|
|
||||||
builder_.Branch(current_flow_block_, node, args);
|
current_flow_block_->BranchTo(node, args);
|
||||||
current_flow_block_ = nullptr;
|
current_flow_block_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BranchToIfNeeded(FlowNode* node) {
|
void BranchToIfNeeded(FlowNode* node) {
|
||||||
if (!current_flow_block_ || IsBranched(current_flow_block_)) {
|
if (!current_flow_block_ || current_flow_block_->HasBranchTarget()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BranchTo(node);
|
BranchTo(node);
|
||||||
@ -271,20 +267,17 @@ class Impl {
|
|||||||
if (ast_func->IsEntryPoint()) {
|
if (ast_func->IsEntryPoint()) {
|
||||||
switch (ast_func->PipelineStage()) {
|
switch (ast_func->PipelineStage()) {
|
||||||
case ast::PipelineStage::kVertex:
|
case ast::PipelineStage::kVertex:
|
||||||
ir_func->pipeline_stage = Function::PipelineStage::kVertex;
|
ir_func->SetStage(Function::PipelineStage::kVertex);
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kFragment:
|
case ast::PipelineStage::kFragment:
|
||||||
ir_func->pipeline_stage = Function::PipelineStage::kFragment;
|
ir_func->SetStage(Function::PipelineStage::kFragment);
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kCompute: {
|
case ast::PipelineStage::kCompute: {
|
||||||
ir_func->pipeline_stage = Function::PipelineStage::kCompute;
|
ir_func->SetStage(Function::PipelineStage::kCompute);
|
||||||
|
|
||||||
auto wg_size = sem->WorkgroupSize();
|
auto wg_size = sem->WorkgroupSize();
|
||||||
ir_func->workgroup_size = {
|
ir_func->SetWorkgroupSize(wg_size[0].value(), wg_size[1].value_or(1),
|
||||||
wg_size[0].value(),
|
wg_size[2].value_or(1));
|
||||||
wg_size[1].value_or(1),
|
|
||||||
wg_size[2].value_or(1),
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -293,14 +286,15 @@ class Impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils::Vector<Function::ReturnAttribute, 1> return_attributes;
|
||||||
for (auto* attr : ast_func->return_type_attributes) {
|
for (auto* attr : ast_func->return_type_attributes) {
|
||||||
tint::Switch(
|
tint::Switch(
|
||||||
attr, //
|
attr, //
|
||||||
[&](const ast::LocationAttribute*) {
|
[&](const ast::LocationAttribute*) {
|
||||||
ir_func->return_attributes.Push(Function::ReturnAttribute::kLocation);
|
return_attributes.Push(Function::ReturnAttribute::kLocation);
|
||||||
},
|
},
|
||||||
[&](const ast::InvariantAttribute*) {
|
[&](const ast::InvariantAttribute*) {
|
||||||
ir_func->return_attributes.Push(Function::ReturnAttribute::kInvariant);
|
return_attributes.Push(Function::ReturnAttribute::kInvariant);
|
||||||
},
|
},
|
||||||
[&](const ast::BuiltinAttribute* b) {
|
[&](const ast::BuiltinAttribute* b) {
|
||||||
if (auto* ident_sem =
|
if (auto* ident_sem =
|
||||||
@ -309,16 +303,13 @@ class Impl {
|
|||||||
->As<sem::BuiltinEnumExpression<builtin::BuiltinValue>>()) {
|
->As<sem::BuiltinEnumExpression<builtin::BuiltinValue>>()) {
|
||||||
switch (ident_sem->Value()) {
|
switch (ident_sem->Value()) {
|
||||||
case builtin::BuiltinValue::kPosition:
|
case builtin::BuiltinValue::kPosition:
|
||||||
ir_func->return_attributes.Push(
|
return_attributes.Push(Function::ReturnAttribute::kPosition);
|
||||||
Function::ReturnAttribute::kPosition);
|
|
||||||
break;
|
break;
|
||||||
case builtin::BuiltinValue::kFragDepth:
|
case builtin::BuiltinValue::kFragDepth:
|
||||||
ir_func->return_attributes.Push(
|
return_attributes.Push(Function::ReturnAttribute::kFragDepth);
|
||||||
Function::ReturnAttribute::kFragDepth);
|
|
||||||
break;
|
break;
|
||||||
case builtin::BuiltinValue::kSampleMask:
|
case builtin::BuiltinValue::kSampleMask:
|
||||||
ir_func->return_attributes.Push(
|
return_attributes.Push(Function::ReturnAttribute::kSampleMask);
|
||||||
Function::ReturnAttribute::kSampleMask);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TINT_ICE(IR, diagnostics_)
|
TINT_ICE(IR, diagnostics_)
|
||||||
@ -332,8 +323,9 @@ class Impl {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
ir_func->SetReturnAttributes(return_attributes);
|
||||||
}
|
}
|
||||||
ir_func->return_location = sem->ReturnLocation();
|
ir_func->SetReturnLocation(sem->ReturnLocation());
|
||||||
|
|
||||||
scopes_.Push();
|
scopes_.Push();
|
||||||
TINT_DEFER(scopes_.Pop());
|
TINT_DEFER(scopes_.Pop());
|
||||||
@ -348,17 +340,17 @@ class Impl {
|
|||||||
builder_.ir.SetName(param, p->name->symbol.NameView());
|
builder_.ir.SetName(param, p->name->symbol.NameView());
|
||||||
params.Push(param);
|
params.Push(param);
|
||||||
}
|
}
|
||||||
ir_func->params = std::move(params);
|
ir_func->SetParams(params);
|
||||||
|
|
||||||
{
|
{
|
||||||
FlowStackScope scope(this, ir_func);
|
FlowStackScope scope(this, ir_func);
|
||||||
|
|
||||||
current_flow_block_ = ir_func->start_target;
|
current_flow_block_ = ir_func->StartTarget();
|
||||||
EmitBlock(ast_func->body);
|
EmitBlock(ast_func->body);
|
||||||
|
|
||||||
// If the branch target has already been set then a `return` was called. Only set in the
|
// If the branch target has already been set then a `return` was called. Only set in the
|
||||||
// case where `return` wasn't called.
|
// case where `return` wasn't called.
|
||||||
BranchToIfNeeded(current_function_->end_target);
|
BranchToIfNeeded(current_function_->EndTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
TINT_ASSERT(IR, flow_stack_.IsEmpty());
|
TINT_ASSERT(IR, flow_stack_.IsEmpty());
|
||||||
@ -372,7 +364,7 @@ class Impl {
|
|||||||
|
|
||||||
// If the current flow block has a branch target then the rest of the statements in this
|
// If the current flow block has a branch target then the rest of the statements in this
|
||||||
// block are dead code. Skip them.
|
// block are dead code. Skip them.
|
||||||
if (!current_flow_block_ || IsBranched(current_flow_block_)) {
|
if (!current_flow_block_ || current_flow_block_->HasBranchTarget()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -427,7 +419,7 @@ class Impl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto store = builder_.Store(lhs.Get(), rhs.Get());
|
auto store = builder_.Store(lhs.Get(), rhs.Get());
|
||||||
current_flow_block_->instructions.Push(store);
|
current_flow_block_->Instructions().Push(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitIncrementDecrement(const ast::IncrementDecrementStatement* stmt) {
|
void EmitIncrementDecrement(const ast::IncrementDecrementStatement* stmt) {
|
||||||
@ -438,7 +430,7 @@ class Impl {
|
|||||||
|
|
||||||
// Load from the LHS.
|
// Load from the LHS.
|
||||||
auto* lhs_value = builder_.Load(lhs.Get());
|
auto* lhs_value = builder_.Load(lhs.Get());
|
||||||
current_flow_block_->instructions.Push(lhs_value);
|
current_flow_block_->Instructions().Push(lhs_value);
|
||||||
|
|
||||||
auto* ty = lhs_value->Type();
|
auto* ty = lhs_value->Type();
|
||||||
|
|
||||||
@ -451,10 +443,10 @@ class Impl {
|
|||||||
} else {
|
} else {
|
||||||
inst = builder_.Subtract(ty, lhs_value, rhs);
|
inst = builder_.Subtract(ty, lhs_value, rhs);
|
||||||
}
|
}
|
||||||
current_flow_block_->instructions.Push(inst);
|
current_flow_block_->Instructions().Push(inst);
|
||||||
|
|
||||||
auto store = builder_.Store(lhs.Get(), inst);
|
auto store = builder_.Store(lhs.Get(), inst);
|
||||||
current_flow_block_->instructions.Push(store);
|
current_flow_block_->Instructions().Push(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompoundAssignment(const ast::CompoundAssignmentStatement* stmt) {
|
void EmitCompoundAssignment(const ast::CompoundAssignmentStatement* stmt) {
|
||||||
@ -470,7 +462,7 @@ class Impl {
|
|||||||
|
|
||||||
// Load from the LHS.
|
// Load from the LHS.
|
||||||
auto* lhs_value = builder_.Load(lhs.Get());
|
auto* lhs_value = builder_.Load(lhs.Get());
|
||||||
current_flow_block_->instructions.Push(lhs_value);
|
current_flow_block_->Instructions().Push(lhs_value);
|
||||||
|
|
||||||
auto* ty = lhs_value->Type();
|
auto* ty = lhs_value->Type();
|
||||||
|
|
||||||
@ -520,10 +512,10 @@ class Impl {
|
|||||||
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
|
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
current_flow_block_->instructions.Push(inst);
|
current_flow_block_->Instructions().Push(inst);
|
||||||
|
|
||||||
auto store = builder_.Store(lhs.Get(), inst);
|
auto store = builder_.Store(lhs.Get(), inst);
|
||||||
current_flow_block_->instructions.Push(store);
|
current_flow_block_->Instructions().Push(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitBlock(const ast::BlockStatement* block) {
|
void EmitBlock(const ast::BlockStatement* block) {
|
||||||
@ -551,27 +543,27 @@ class Impl {
|
|||||||
{
|
{
|
||||||
FlowStackScope scope(this, if_node);
|
FlowStackScope scope(this, if_node);
|
||||||
|
|
||||||
current_flow_block_ = if_node->true_.target->As<Block>();
|
current_flow_block_ = if_node->True().target->As<Block>();
|
||||||
EmitBlock(stmt->body);
|
EmitBlock(stmt->body);
|
||||||
|
|
||||||
// If the true branch did not execute control flow, then go to the merge target
|
// If the true branch did not execute control flow, then go to the Merge().target
|
||||||
BranchToIfNeeded(if_node->merge.target);
|
BranchToIfNeeded(if_node->Merge().target);
|
||||||
|
|
||||||
current_flow_block_ = if_node->false_.target->As<Block>();
|
current_flow_block_ = if_node->False().target->As<Block>();
|
||||||
if (stmt->else_statement) {
|
if (stmt->else_statement) {
|
||||||
EmitStatement(stmt->else_statement);
|
EmitStatement(stmt->else_statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the false branch did not execute control flow, then go to the merge target
|
// If the false branch did not execute control flow, then go to the Merge().target
|
||||||
BranchToIfNeeded(if_node->merge.target);
|
BranchToIfNeeded(if_node->Merge().target);
|
||||||
}
|
}
|
||||||
current_flow_block_ = nullptr;
|
current_flow_block_ = nullptr;
|
||||||
|
|
||||||
// If both branches went somewhere, then they both returned, continued or broke. So, there
|
// If both branches went somewhere, then they both returned, continued or broke. So, there
|
||||||
// is no need for the if merge-block and there is nothing to branch to the merge block
|
// is no need for the if merge-block and there is nothing to branch to the merge block
|
||||||
// anyway.
|
// anyway.
|
||||||
if (IsConnected(if_node->merge.target)) {
|
if (IsConnected(if_node->Merge().target)) {
|
||||||
current_flow_block_ = if_node->merge.target->As<Block>();
|
current_flow_block_ = if_node->Merge().target->As<Block>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +577,7 @@ class Impl {
|
|||||||
{
|
{
|
||||||
FlowStackScope scope(this, loop_node);
|
FlowStackScope scope(this, loop_node);
|
||||||
|
|
||||||
current_flow_block_ = loop_node->start.target->As<Block>();
|
current_flow_block_ = loop_node->Start().target->As<Block>();
|
||||||
|
|
||||||
// The loop doesn't use EmitBlock because it needs the scope stack to not get popped
|
// The loop doesn't use EmitBlock because it needs the scope stack to not get popped
|
||||||
// until after the continuing block.
|
// until after the continuing block.
|
||||||
@ -594,21 +586,22 @@ class Impl {
|
|||||||
EmitStatements(stmt->body->statements);
|
EmitStatements(stmt->body->statements);
|
||||||
|
|
||||||
// The current block didn't `break`, `return` or `continue`, go to the continuing block.
|
// The current block didn't `break`, `return` or `continue`, go to the continuing block.
|
||||||
BranchToIfNeeded(loop_node->continuing.target);
|
BranchToIfNeeded(loop_node->Continuing().target);
|
||||||
|
|
||||||
current_flow_block_ = loop_node->continuing.target->As<Block>();
|
current_flow_block_ = loop_node->Continuing().target->As<Block>();
|
||||||
if (stmt->continuing) {
|
if (stmt->continuing) {
|
||||||
EmitBlock(stmt->continuing);
|
EmitBlock(stmt->continuing);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Branch back to the start node if the continue target didn't branch out already
|
// Branch back to the start node if the continue target didn't branch out already
|
||||||
BranchToIfNeeded(loop_node->start.target);
|
BranchToIfNeeded(loop_node->Start().target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The loop merge can get disconnected if the loop returns directly, or the continuing
|
// The loop merge can get disconnected if the loop returns directly, or the continuing
|
||||||
// target branches, eventually, to the merge, but nothing branched to the continuing target.
|
// target branches, eventually, to the merge, but nothing branched to the
|
||||||
current_flow_block_ = loop_node->merge.target->As<Block>();
|
// Continuing().target.
|
||||||
if (!IsConnected(loop_node->merge.target)) {
|
current_flow_block_ = loop_node->Merge().target->As<Block>();
|
||||||
|
if (!IsConnected(loop_node->Merge().target)) {
|
||||||
current_flow_block_ = nullptr;
|
current_flow_block_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -616,9 +609,8 @@ class Impl {
|
|||||||
void EmitWhile(const ast::WhileStatement* stmt) {
|
void EmitWhile(const ast::WhileStatement* stmt) {
|
||||||
auto* loop_node = builder_.CreateLoop();
|
auto* loop_node = builder_.CreateLoop();
|
||||||
// Continue is always empty, just go back to the start
|
// Continue is always empty, just go back to the start
|
||||||
TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>());
|
TINT_ASSERT(IR, loop_node->Continuing().target->Is<Block>());
|
||||||
builder_.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
|
loop_node->Continuing().target->As<Block>()->BranchTo(loop_node->Start().target);
|
||||||
utils::Empty);
|
|
||||||
|
|
||||||
BranchTo(loop_node);
|
BranchTo(loop_node);
|
||||||
|
|
||||||
@ -627,9 +619,9 @@ class Impl {
|
|||||||
{
|
{
|
||||||
FlowStackScope scope(this, loop_node);
|
FlowStackScope scope(this, loop_node);
|
||||||
|
|
||||||
current_flow_block_ = loop_node->start.target->As<Block>();
|
current_flow_block_ = loop_node->Start().target->As<Block>();
|
||||||
|
|
||||||
// Emit the while condition into the start target of the loop
|
// Emit the while condition into the Start().target of the loop
|
||||||
auto reg = EmitExpression(stmt->condition);
|
auto reg = EmitExpression(stmt->condition);
|
||||||
if (!reg) {
|
if (!reg) {
|
||||||
return;
|
return;
|
||||||
@ -637,31 +629,24 @@ class Impl {
|
|||||||
|
|
||||||
// Create an `if (cond) {} else {break;}` control flow
|
// Create an `if (cond) {} else {break;}` control flow
|
||||||
auto* if_node = builder_.CreateIf(reg.Get());
|
auto* if_node = builder_.CreateIf(reg.Get());
|
||||||
TINT_ASSERT(IR, if_node->true_.target->Is<Block>());
|
if_node->True().target->As<Block>()->BranchTo(if_node->Merge().target);
|
||||||
builder_.Branch(if_node->true_.target->As<Block>(), if_node->merge.target,
|
if_node->False().target->As<Block>()->BranchTo(loop_node->Merge().target);
|
||||||
utils::Empty);
|
|
||||||
|
|
||||||
TINT_ASSERT(IR, if_node->false_.target->Is<Block>());
|
|
||||||
builder_.Branch(if_node->false_.target->As<Block>(), loop_node->merge.target,
|
|
||||||
utils::Empty);
|
|
||||||
|
|
||||||
BranchTo(if_node);
|
BranchTo(if_node);
|
||||||
|
|
||||||
current_flow_block_ = if_node->merge.target->As<Block>();
|
current_flow_block_ = if_node->Merge().target->As<Block>();
|
||||||
EmitBlock(stmt->body);
|
EmitBlock(stmt->body);
|
||||||
|
|
||||||
BranchToIfNeeded(loop_node->continuing.target);
|
BranchToIfNeeded(loop_node->Continuing().target);
|
||||||
}
|
}
|
||||||
// The while loop always has a path to the merge target as the break statement comes before
|
// The while loop always has a path to the Merge().target as the break statement comes
|
||||||
// anything inside the loop.
|
// before anything inside the loop.
|
||||||
current_flow_block_ = loop_node->merge.target->As<Block>();
|
current_flow_block_ = loop_node->Merge().target->As<Block>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitForLoop(const ast::ForLoopStatement* stmt) {
|
void EmitForLoop(const ast::ForLoopStatement* stmt) {
|
||||||
auto* loop_node = builder_.CreateLoop();
|
auto* loop_node = builder_.CreateLoop();
|
||||||
TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>());
|
loop_node->Continuing().target->As<Block>()->BranchTo(loop_node->Start().target);
|
||||||
builder_.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
|
|
||||||
utils::Empty);
|
|
||||||
|
|
||||||
// Make sure the initializer ends up in a contained scope
|
// Make sure the initializer ends up in a contained scope
|
||||||
scopes_.Push();
|
scopes_.Push();
|
||||||
@ -679,7 +664,7 @@ class Impl {
|
|||||||
{
|
{
|
||||||
FlowStackScope scope(this, loop_node);
|
FlowStackScope scope(this, loop_node);
|
||||||
|
|
||||||
current_flow_block_ = loop_node->start.target->As<Block>();
|
current_flow_block_ = loop_node->Start().target->As<Block>();
|
||||||
|
|
||||||
if (stmt->condition) {
|
if (stmt->condition) {
|
||||||
// Emit the condition into the target target of the loop
|
// Emit the condition into the target target of the loop
|
||||||
@ -690,30 +675,25 @@ class Impl {
|
|||||||
|
|
||||||
// Create an `if (cond) {} else {break;}` control flow
|
// Create an `if (cond) {} else {break;}` control flow
|
||||||
auto* if_node = builder_.CreateIf(reg.Get());
|
auto* if_node = builder_.CreateIf(reg.Get());
|
||||||
TINT_ASSERT(IR, if_node->true_.target->Is<Block>());
|
if_node->True().target->As<Block>()->BranchTo(if_node->Merge().target);
|
||||||
builder_.Branch(if_node->true_.target->As<Block>(), if_node->merge.target,
|
if_node->False().target->As<Block>()->BranchTo(loop_node->Merge().target);
|
||||||
utils::Empty);
|
|
||||||
|
|
||||||
TINT_ASSERT(IR, if_node->false_.target->Is<Block>());
|
|
||||||
builder_.Branch(if_node->false_.target->As<Block>(), loop_node->merge.target,
|
|
||||||
utils::Empty);
|
|
||||||
|
|
||||||
BranchTo(if_node);
|
BranchTo(if_node);
|
||||||
current_flow_block_ = if_node->merge.target->As<Block>();
|
current_flow_block_ = if_node->Merge().target->As<Block>();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitBlock(stmt->body);
|
EmitBlock(stmt->body);
|
||||||
BranchToIfNeeded(loop_node->continuing.target);
|
BranchToIfNeeded(loop_node->Continuing().target);
|
||||||
|
|
||||||
if (stmt->continuing) {
|
if (stmt->continuing) {
|
||||||
current_flow_block_ = loop_node->continuing.target->As<Block>();
|
current_flow_block_ = loop_node->Continuing().target->As<Block>();
|
||||||
EmitStatement(stmt->continuing);
|
EmitStatement(stmt->continuing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The while loop always has a path to the merge target as the break statement comes before
|
// The while loop always has a path to the Merge().target as the break statement comes
|
||||||
// anything inside the loop.
|
// before anything inside the loop.
|
||||||
current_flow_block_ = loop_node->merge.target->As<Block>();
|
current_flow_block_ = loop_node->Merge().target->As<Block>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSwitch(const ast::SwitchStatement* stmt) {
|
void EmitSwitch(const ast::SwitchStatement* stmt) {
|
||||||
@ -745,13 +725,13 @@ class Impl {
|
|||||||
current_flow_block_ = builder_.CreateCase(switch_node, selectors);
|
current_flow_block_ = builder_.CreateCase(switch_node, selectors);
|
||||||
EmitBlock(c->Body()->Declaration());
|
EmitBlock(c->Body()->Declaration());
|
||||||
|
|
||||||
BranchToIfNeeded(switch_node->merge.target);
|
BranchToIfNeeded(switch_node->Merge().target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_flow_block_ = nullptr;
|
current_flow_block_ = nullptr;
|
||||||
|
|
||||||
if (IsConnected(switch_node->merge.target)) {
|
if (IsConnected(switch_node->Merge().target)) {
|
||||||
current_flow_block_ = switch_node->merge.target->As<Block>();
|
current_flow_block_ = switch_node->Merge().target->As<Block>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,7 +745,7 @@ class Impl {
|
|||||||
ret_value.Push(ret.Get());
|
ret_value.Push(ret.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
BranchTo(current_function_->end_target, std::move(ret_value));
|
BranchTo(current_function_->EndTarget(), std::move(ret_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitBreak(const ast::BreakStatement*) {
|
void EmitBreak(const ast::BreakStatement*) {
|
||||||
@ -773,9 +753,9 @@ class Impl {
|
|||||||
TINT_ASSERT(IR, current_control);
|
TINT_ASSERT(IR, current_control);
|
||||||
|
|
||||||
if (auto* c = current_control->As<Loop>()) {
|
if (auto* c = current_control->As<Loop>()) {
|
||||||
BranchTo(c->merge.target);
|
BranchTo(c->Merge().target);
|
||||||
} else if (auto* s = current_control->As<Switch>()) {
|
} else if (auto* s = current_control->As<Switch>()) {
|
||||||
BranchTo(s->merge.target);
|
BranchTo(s->Merge().target);
|
||||||
} else {
|
} else {
|
||||||
TINT_UNREACHABLE(IR, diagnostics_);
|
TINT_UNREACHABLE(IR, diagnostics_);
|
||||||
}
|
}
|
||||||
@ -786,7 +766,7 @@ class Impl {
|
|||||||
TINT_ASSERT(IR, current_control);
|
TINT_ASSERT(IR, current_control);
|
||||||
|
|
||||||
if (auto* c = current_control->As<Loop>()) {
|
if (auto* c = current_control->As<Loop>()) {
|
||||||
BranchTo(c->continuing.target);
|
BranchTo(c->Continuing().target);
|
||||||
} else {
|
} else {
|
||||||
TINT_UNREACHABLE(IR, diagnostics_);
|
TINT_UNREACHABLE(IR, diagnostics_);
|
||||||
}
|
}
|
||||||
@ -798,7 +778,7 @@ class Impl {
|
|||||||
// figuring out the multi-level exit that is triggered.
|
// figuring out the multi-level exit that is triggered.
|
||||||
void EmitDiscard(const ast::DiscardStatement*) {
|
void EmitDiscard(const ast::DiscardStatement*) {
|
||||||
auto* inst = builder_.Discard();
|
auto* inst = builder_.Discard();
|
||||||
current_flow_block_->instructions.Push(inst);
|
current_flow_block_->Instructions().Push(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitBreakIf(const ast::BreakIfStatement* stmt) {
|
void EmitBreakIf(const ast::BreakIfStatement* stmt) {
|
||||||
@ -819,17 +799,17 @@ class Impl {
|
|||||||
|
|
||||||
auto* loop = current_control->As<Loop>();
|
auto* loop = current_control->As<Loop>();
|
||||||
|
|
||||||
current_flow_block_ = if_node->true_.target->As<Block>();
|
current_flow_block_ = if_node->True().target->As<Block>();
|
||||||
BranchTo(loop->merge.target);
|
BranchTo(loop->Merge().target);
|
||||||
|
|
||||||
current_flow_block_ = if_node->false_.target->As<Block>();
|
current_flow_block_ = if_node->False().target->As<Block>();
|
||||||
BranchTo(if_node->merge.target);
|
BranchTo(if_node->Merge().target);
|
||||||
|
|
||||||
current_flow_block_ = if_node->merge.target->As<Block>();
|
current_flow_block_ = if_node->Merge().target->As<Block>();
|
||||||
|
|
||||||
// The `break-if` has to be the last item in the continuing block. The false branch of the
|
// The `break-if` has to be the last item in the continuing block. The false branch of the
|
||||||
// `break-if` will always take us back to the start of the loop.
|
// `break-if` will always take us back to the start of the loop.
|
||||||
BranchTo(loop->start.target);
|
BranchTo(loop->Start().target);
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::Result<Value*> EmitExpression(const ast::Expression* expr) {
|
utils::Result<Value*> EmitExpression(const ast::Expression* expr) {
|
||||||
@ -876,7 +856,7 @@ class Impl {
|
|||||||
// If this expression maps to sem::Load, insert a load instruction to get the result.
|
// If this expression maps to sem::Load, insert a load instruction to get the result.
|
||||||
if (result && sem->Is<sem::Load>()) {
|
if (result && sem->Is<sem::Load>()) {
|
||||||
auto* load = builder_.Load(result.Get());
|
auto* load = builder_.Load(result.Get());
|
||||||
current_flow_block_->instructions.Push(load);
|
current_flow_block_->Instructions().Push(load);
|
||||||
return load;
|
return load;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,14 +875,14 @@ class Impl {
|
|||||||
ref->Access());
|
ref->Access());
|
||||||
|
|
||||||
auto* val = builder_.Declare(ty);
|
auto* val = builder_.Declare(ty);
|
||||||
current_flow_block_->instructions.Push(val);
|
current_flow_block_->Instructions().Push(val);
|
||||||
|
|
||||||
if (v->initializer) {
|
if (v->initializer) {
|
||||||
auto init = EmitExpression(v->initializer);
|
auto init = EmitExpression(v->initializer);
|
||||||
if (!init) {
|
if (!init) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
val->initializer = init.Get();
|
val->SetInitializer(init.Get());
|
||||||
}
|
}
|
||||||
// Store the declaration so we can get the instruction to store too
|
// Store the declaration so we can get the instruction to store too
|
||||||
scopes_.Set(v->name->symbol, val);
|
scopes_.Set(v->name->symbol, val);
|
||||||
@ -969,7 +949,7 @@ class Impl {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_flow_block_->instructions.Push(inst);
|
current_flow_block_->Instructions().Push(inst);
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,7 +976,7 @@ class Impl {
|
|||||||
BranchTo(if_node);
|
BranchTo(if_node);
|
||||||
|
|
||||||
auto* result = builder_.BlockParam(builder_.ir.types.Get<type::Bool>());
|
auto* result = builder_.BlockParam(builder_.ir.types.Get<type::Bool>());
|
||||||
if_node->merge.target->As<Block>()->params.Push(result);
|
if_node->Merge().target->As<Block>()->SetParams(utils::Vector{result});
|
||||||
|
|
||||||
utils::Result<Value*> rhs;
|
utils::Result<Value*> rhs;
|
||||||
{
|
{
|
||||||
@ -1010,17 +990,17 @@ class Impl {
|
|||||||
if (expr->op == ast::BinaryOp::kLogicalAnd) {
|
if (expr->op == ast::BinaryOp::kLogicalAnd) {
|
||||||
// If the lhs is false, then that is the result we want to pass to the merge block
|
// If the lhs is false, then that is the result we want to pass to the merge block
|
||||||
// as our argument
|
// as our argument
|
||||||
current_flow_block_ = if_node->false_.target->As<Block>();
|
current_flow_block_ = if_node->False().target->As<Block>();
|
||||||
BranchTo(if_node->merge.target, std::move(alt_args));
|
BranchTo(if_node->Merge().target, std::move(alt_args));
|
||||||
|
|
||||||
current_flow_block_ = if_node->true_.target->As<Block>();
|
current_flow_block_ = if_node->True().target->As<Block>();
|
||||||
} else {
|
} else {
|
||||||
// If the lhs is true, then that is the result we want to pass to the merge block
|
// If the lhs is true, then that is the result we want to pass to the merge block
|
||||||
// as our argument
|
// as our argument
|
||||||
current_flow_block_ = if_node->true_.target->As<Block>();
|
current_flow_block_ = if_node->True().target->As<Block>();
|
||||||
BranchTo(if_node->merge.target, std::move(alt_args));
|
BranchTo(if_node->Merge().target, std::move(alt_args));
|
||||||
|
|
||||||
current_flow_block_ = if_node->false_.target->As<Block>();
|
current_flow_block_ = if_node->False().target->As<Block>();
|
||||||
}
|
}
|
||||||
|
|
||||||
rhs = EmitExpression(expr->rhs);
|
rhs = EmitExpression(expr->rhs);
|
||||||
@ -1030,9 +1010,9 @@ class Impl {
|
|||||||
utils::Vector<Value*, 1> args;
|
utils::Vector<Value*, 1> args;
|
||||||
args.Push(rhs.Get());
|
args.Push(rhs.Get());
|
||||||
|
|
||||||
BranchTo(if_node->merge.target, std::move(args));
|
BranchTo(if_node->Merge().target, std::move(args));
|
||||||
}
|
}
|
||||||
current_flow_block_ = if_node->merge.target->As<Block>();
|
current_flow_block_ = if_node->Merge().target->As<Block>();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1114,7 +1094,7 @@ class Impl {
|
|||||||
return utils::Failure;
|
return utils::Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_flow_block_->instructions.Push(inst);
|
current_flow_block_->Instructions().Push(inst);
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1128,7 +1108,7 @@ class Impl {
|
|||||||
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
|
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
|
||||||
auto* inst = builder_.Bitcast(ty, val.Get());
|
auto* inst = builder_.Bitcast(ty, val.Get());
|
||||||
|
|
||||||
current_flow_block_->instructions.Push(inst);
|
current_flow_block_->Instructions().Push(inst);
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1191,7 +1171,7 @@ class Impl {
|
|||||||
if (inst == nullptr) {
|
if (inst == nullptr) {
|
||||||
return utils::Failure;
|
return utils::Failure;
|
||||||
}
|
}
|
||||||
current_flow_block_->instructions.Push(inst);
|
current_flow_block_->Instructions().Push(inst);
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,17 +25,19 @@
|
|||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
Value* GlobalVarInitializer(const Module& m) {
|
const Value* GlobalVarInitializer(const Module& m) {
|
||||||
if (m.root_block->instructions.Length() == 0u) {
|
const auto instr = m.root_block->Instructions();
|
||||||
|
|
||||||
|
if (instr.Length() == 0u) {
|
||||||
ADD_FAILURE() << "m.root_block has no instruction";
|
ADD_FAILURE() << "m.root_block has no instruction";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto* var = m.root_block->instructions[0]->As<ir::Var>();
|
auto* var = instr[0]->As<ir::Var>();
|
||||||
if (!var) {
|
if (!var) {
|
||||||
ADD_FAILURE() << "m.root_block.instructions[0] was not a var";
|
ADD_FAILURE() << "m.root_block.instructions[0] was not a var";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return var->initializer;
|
return var->Initializer();
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace tint::number_suffixes; // NOLINT
|
using namespace tint::number_suffixes; // NOLINT
|
||||||
@ -51,7 +53,7 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) {
|
|||||||
|
|
||||||
auto* init = GlobalVarInitializer(m.Get());
|
auto* init = GlobalVarInitializer(m.Get());
|
||||||
ASSERT_TRUE(Is<Constant>(init));
|
ASSERT_TRUE(Is<Constant>(init));
|
||||||
auto* val = init->As<Constant>()->value;
|
auto* val = init->As<Constant>()->Value();
|
||||||
EXPECT_TRUE(val->Is<constant::Scalar<bool>>());
|
EXPECT_TRUE(val->Is<constant::Scalar<bool>>());
|
||||||
EXPECT_TRUE(val->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
EXPECT_TRUE(val->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
||||||
}
|
}
|
||||||
@ -65,7 +67,7 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_False) {
|
|||||||
|
|
||||||
auto* init = GlobalVarInitializer(m.Get());
|
auto* init = GlobalVarInitializer(m.Get());
|
||||||
ASSERT_TRUE(Is<Constant>(init));
|
ASSERT_TRUE(Is<Constant>(init));
|
||||||
auto* val = init->As<Constant>()->value;
|
auto* val = init->As<Constant>()->Value();
|
||||||
EXPECT_TRUE(val->Is<constant::Scalar<bool>>());
|
EXPECT_TRUE(val->Is<constant::Scalar<bool>>());
|
||||||
EXPECT_FALSE(val->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
EXPECT_FALSE(val->As<constant::Scalar<bool>>()->ValueAs<bool>());
|
||||||
}
|
}
|
||||||
@ -79,18 +81,19 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_Deduped) {
|
|||||||
auto m = Build();
|
auto m = Build();
|
||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* var_a = m.Get().root_block->instructions[0]->As<ir::Var>();
|
auto instr = m.Get().root_block->Instructions();
|
||||||
|
auto* var_a = instr[0]->As<ir::Var>();
|
||||||
ASSERT_NE(var_a, nullptr);
|
ASSERT_NE(var_a, nullptr);
|
||||||
auto* var_b = m.Get().root_block->instructions[1]->As<ir::Var>();
|
auto* var_b = instr[1]->As<ir::Var>();
|
||||||
ASSERT_NE(var_b, nullptr);
|
ASSERT_NE(var_b, nullptr);
|
||||||
auto* var_c = m.Get().root_block->instructions[2]->As<ir::Var>();
|
auto* var_c = instr[2]->As<ir::Var>();
|
||||||
ASSERT_NE(var_c, nullptr);
|
ASSERT_NE(var_c, nullptr);
|
||||||
auto* var_d = m.Get().root_block->instructions[3]->As<ir::Var>();
|
auto* var_d = instr[3]->As<ir::Var>();
|
||||||
ASSERT_NE(var_d, nullptr);
|
ASSERT_NE(var_d, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(var_a->initializer, var_c->initializer);
|
ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
|
||||||
ASSERT_EQ(var_b->initializer, var_d->initializer);
|
ASSERT_EQ(var_b->Initializer(), var_d->Initializer());
|
||||||
ASSERT_NE(var_a->initializer, var_b->initializer);
|
ASSERT_NE(var_a->Initializer(), var_b->Initializer());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_BuilderImplTest, EmitLiteral_F32) {
|
TEST_F(IR_BuilderImplTest, EmitLiteral_F32) {
|
||||||
@ -102,7 +105,7 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F32) {
|
|||||||
|
|
||||||
auto* init = GlobalVarInitializer(m.Get());
|
auto* init = GlobalVarInitializer(m.Get());
|
||||||
ASSERT_TRUE(Is<Constant>(init));
|
ASSERT_TRUE(Is<Constant>(init));
|
||||||
auto* val = init->As<Constant>()->value;
|
auto* val = init->As<Constant>()->Value();
|
||||||
EXPECT_TRUE(val->Is<constant::Scalar<f32>>());
|
EXPECT_TRUE(val->Is<constant::Scalar<f32>>());
|
||||||
EXPECT_EQ(1.2_f, val->As<constant::Scalar<f32>>()->ValueAs<f32>());
|
EXPECT_EQ(1.2_f, val->As<constant::Scalar<f32>>()->ValueAs<f32>());
|
||||||
}
|
}
|
||||||
@ -115,15 +118,16 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F32_Deduped) {
|
|||||||
auto m = Build();
|
auto m = Build();
|
||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* var_a = m.Get().root_block->instructions[0]->As<ir::Var>();
|
auto instr = m.Get().root_block->Instructions();
|
||||||
|
auto* var_a = instr[0]->As<ir::Var>();
|
||||||
ASSERT_NE(var_a, nullptr);
|
ASSERT_NE(var_a, nullptr);
|
||||||
auto* var_b = m.Get().root_block->instructions[1]->As<ir::Var>();
|
auto* var_b = instr[1]->As<ir::Var>();
|
||||||
ASSERT_NE(var_b, nullptr);
|
ASSERT_NE(var_b, nullptr);
|
||||||
auto* var_c = m.Get().root_block->instructions[2]->As<ir::Var>();
|
auto* var_c = instr[2]->As<ir::Var>();
|
||||||
ASSERT_NE(var_c, nullptr);
|
ASSERT_NE(var_c, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(var_a->initializer, var_c->initializer);
|
ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
|
||||||
ASSERT_NE(var_a->initializer, var_b->initializer);
|
ASSERT_NE(var_a->Initializer(), var_b->Initializer());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_BuilderImplTest, EmitLiteral_F16) {
|
TEST_F(IR_BuilderImplTest, EmitLiteral_F16) {
|
||||||
@ -136,7 +140,7 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F16) {
|
|||||||
|
|
||||||
auto* init = GlobalVarInitializer(m.Get());
|
auto* init = GlobalVarInitializer(m.Get());
|
||||||
ASSERT_TRUE(Is<Constant>(init));
|
ASSERT_TRUE(Is<Constant>(init));
|
||||||
auto* val = init->As<Constant>()->value;
|
auto* val = init->As<Constant>()->Value();
|
||||||
EXPECT_TRUE(val->Is<constant::Scalar<f16>>());
|
EXPECT_TRUE(val->Is<constant::Scalar<f16>>());
|
||||||
EXPECT_EQ(1.2_h, val->As<constant::Scalar<f16>>()->ValueAs<f32>());
|
EXPECT_EQ(1.2_h, val->As<constant::Scalar<f16>>()->ValueAs<f32>());
|
||||||
}
|
}
|
||||||
@ -150,15 +154,16 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F16_Deduped) {
|
|||||||
auto m = Build();
|
auto m = Build();
|
||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* var_a = m.Get().root_block->instructions[0]->As<ir::Var>();
|
auto instr = m.Get().root_block->Instructions();
|
||||||
|
auto* var_a = instr[0]->As<ir::Var>();
|
||||||
ASSERT_NE(var_a, nullptr);
|
ASSERT_NE(var_a, nullptr);
|
||||||
auto* var_b = m.Get().root_block->instructions[1]->As<ir::Var>();
|
auto* var_b = instr[1]->As<ir::Var>();
|
||||||
ASSERT_NE(var_b, nullptr);
|
ASSERT_NE(var_b, nullptr);
|
||||||
auto* var_c = m.Get().root_block->instructions[2]->As<ir::Var>();
|
auto* var_c = instr[2]->As<ir::Var>();
|
||||||
ASSERT_NE(var_c, nullptr);
|
ASSERT_NE(var_c, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(var_a->initializer, var_c->initializer);
|
ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
|
||||||
ASSERT_NE(var_a->initializer, var_b->initializer);
|
ASSERT_NE(var_a->Initializer(), var_b->Initializer());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_BuilderImplTest, EmitLiteral_I32) {
|
TEST_F(IR_BuilderImplTest, EmitLiteral_I32) {
|
||||||
@ -170,7 +175,7 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_I32) {
|
|||||||
|
|
||||||
auto* init = GlobalVarInitializer(m.Get());
|
auto* init = GlobalVarInitializer(m.Get());
|
||||||
ASSERT_TRUE(Is<Constant>(init));
|
ASSERT_TRUE(Is<Constant>(init));
|
||||||
auto* val = init->As<Constant>()->value;
|
auto* val = init->As<Constant>()->Value();
|
||||||
EXPECT_TRUE(val->Is<constant::Scalar<i32>>());
|
EXPECT_TRUE(val->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(-2_i, val->As<constant::Scalar<i32>>()->ValueAs<f32>());
|
EXPECT_EQ(-2_i, val->As<constant::Scalar<i32>>()->ValueAs<f32>());
|
||||||
}
|
}
|
||||||
@ -183,15 +188,16 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_I32_Deduped) {
|
|||||||
auto m = Build();
|
auto m = Build();
|
||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* var_a = m.Get().root_block->instructions[0]->As<ir::Var>();
|
auto instr = m.Get().root_block->Instructions();
|
||||||
|
auto* var_a = instr[0]->As<ir::Var>();
|
||||||
ASSERT_NE(var_a, nullptr);
|
ASSERT_NE(var_a, nullptr);
|
||||||
auto* var_b = m.Get().root_block->instructions[1]->As<ir::Var>();
|
auto* var_b = instr[1]->As<ir::Var>();
|
||||||
ASSERT_NE(var_b, nullptr);
|
ASSERT_NE(var_b, nullptr);
|
||||||
auto* var_c = m.Get().root_block->instructions[2]->As<ir::Var>();
|
auto* var_c = instr[2]->As<ir::Var>();
|
||||||
ASSERT_NE(var_c, nullptr);
|
ASSERT_NE(var_c, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(var_a->initializer, var_c->initializer);
|
ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
|
||||||
ASSERT_NE(var_a->initializer, var_b->initializer);
|
ASSERT_NE(var_a->Initializer(), var_b->Initializer());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_BuilderImplTest, EmitLiteral_U32) {
|
TEST_F(IR_BuilderImplTest, EmitLiteral_U32) {
|
||||||
@ -203,7 +209,7 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_U32) {
|
|||||||
|
|
||||||
auto* init = GlobalVarInitializer(m.Get());
|
auto* init = GlobalVarInitializer(m.Get());
|
||||||
ASSERT_TRUE(Is<Constant>(init));
|
ASSERT_TRUE(Is<Constant>(init));
|
||||||
auto* val = init->As<Constant>()->value;
|
auto* val = init->As<Constant>()->Value();
|
||||||
EXPECT_TRUE(val->Is<constant::Scalar<u32>>());
|
EXPECT_TRUE(val->Is<constant::Scalar<u32>>());
|
||||||
EXPECT_EQ(2_u, val->As<constant::Scalar<u32>>()->ValueAs<f32>());
|
EXPECT_EQ(2_u, val->As<constant::Scalar<u32>>()->ValueAs<f32>());
|
||||||
}
|
}
|
||||||
@ -216,15 +222,16 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_U32_Deduped) {
|
|||||||
auto m = Build();
|
auto m = Build();
|
||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* var_a = m.Get().root_block->instructions[0]->As<ir::Var>();
|
auto instr = m.Get().root_block->Instructions();
|
||||||
|
auto* var_a = instr[0]->As<ir::Var>();
|
||||||
ASSERT_NE(var_a, nullptr);
|
ASSERT_NE(var_a, nullptr);
|
||||||
auto* var_b = m.Get().root_block->instructions[1]->As<ir::Var>();
|
auto* var_b = instr[1]->As<ir::Var>();
|
||||||
ASSERT_NE(var_b, nullptr);
|
ASSERT_NE(var_b, nullptr);
|
||||||
auto* var_c = m.Get().root_block->instructions[2]->As<ir::Var>();
|
auto* var_c = instr[2]->As<ir::Var>();
|
||||||
ASSERT_NE(var_c, nullptr);
|
ASSERT_NE(var_c, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(var_a->initializer, var_c->initializer);
|
ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
|
||||||
ASSERT_NE(var_a->initializer, var_b->initializer);
|
ASSERT_NE(var_a->Initializer(), var_b->Initializer());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -63,13 +63,13 @@ TEST_F(IR_BuilderImplTest, Func) {
|
|||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
|
|
||||||
auto* f = m->functions[0];
|
auto* f = m->functions[0];
|
||||||
ASSERT_NE(f->start_target, nullptr);
|
ASSERT_NE(f->StartTarget(), nullptr);
|
||||||
ASSERT_NE(f->end_target, nullptr);
|
ASSERT_NE(f->EndTarget(), nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(1u, f->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, f->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, f->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, f->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(m->functions[0]->pipeline_stage, Function::PipelineStage::kUndefined);
|
EXPECT_EQ(m->functions[0]->Stage(), Function::PipelineStage::kUndefined);
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f():void {
|
EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f():void {
|
||||||
%fn2 = block {
|
%fn2 = block {
|
||||||
@ -88,13 +88,13 @@ TEST_F(IR_BuilderImplTest, Func_WithParam) {
|
|||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
|
|
||||||
auto* f = m->functions[0];
|
auto* f = m->functions[0];
|
||||||
ASSERT_NE(f->start_target, nullptr);
|
ASSERT_NE(f->StartTarget(), nullptr);
|
||||||
ASSERT_NE(f->end_target, nullptr);
|
ASSERT_NE(f->EndTarget(), nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(1u, f->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, f->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, f->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, f->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(m->functions[0]->pipeline_stage, Function::PipelineStage::kUndefined);
|
EXPECT_EQ(m->functions[0]->Stage(), Function::PipelineStage::kUndefined);
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f(%a:u32):u32 {
|
EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f(%a:u32):u32 {
|
||||||
%fn2 = block {
|
%fn2 = block {
|
||||||
@ -114,13 +114,13 @@ TEST_F(IR_BuilderImplTest, Func_WithMultipleParam) {
|
|||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
|
|
||||||
auto* f = m->functions[0];
|
auto* f = m->functions[0];
|
||||||
ASSERT_NE(f->start_target, nullptr);
|
ASSERT_NE(f->StartTarget(), nullptr);
|
||||||
ASSERT_NE(f->end_target, nullptr);
|
ASSERT_NE(f->EndTarget(), nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(1u, f->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, f->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, f->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, f->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(m->functions[0]->pipeline_stage, Function::PipelineStage::kUndefined);
|
EXPECT_EQ(m->functions[0]->Stage(), Function::PipelineStage::kUndefined);
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f(%a:u32, %b:i32, %c:bool):void {
|
EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f(%a:u32, %b:i32, %c:bool):void {
|
||||||
%fn2 = block {
|
%fn2 = block {
|
||||||
@ -137,7 +137,7 @@ TEST_F(IR_BuilderImplTest, EntryPoint) {
|
|||||||
auto m = Build();
|
auto m = Build();
|
||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
EXPECT_EQ(m->functions[0]->pipeline_stage, Function::PipelineStage::kFragment);
|
EXPECT_EQ(m->functions[0]->Stage(), Function::PipelineStage::kFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_BuilderImplTest, IfStatement) {
|
TEST_F(IR_BuilderImplTest, IfStatement) {
|
||||||
@ -148,19 +148,19 @@ TEST_F(IR_BuilderImplTest, IfStatement) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(flow->true_.target, nullptr);
|
ASSERT_NE(flow->True().target, nullptr);
|
||||||
ASSERT_NE(flow->false_.target, nullptr);
|
ASSERT_NE(flow->False().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(2u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -192,19 +192,19 @@ TEST_F(IR_BuilderImplTest, IfStatement_TrueReturns) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(flow->true_.target, nullptr);
|
ASSERT_NE(flow->True().target, nullptr);
|
||||||
ASSERT_NE(flow->false_.target, nullptr);
|
ASSERT_NE(flow->False().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -235,19 +235,19 @@ TEST_F(IR_BuilderImplTest, IfStatement_FalseReturns) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(flow->true_.target, nullptr);
|
ASSERT_NE(flow->True().target, nullptr);
|
||||||
ASSERT_NE(flow->false_.target, nullptr);
|
ASSERT_NE(flow->False().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -278,19 +278,19 @@ TEST_F(IR_BuilderImplTest, IfStatement_BothReturn) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(flow->true_.target, nullptr);
|
ASSERT_NE(flow->True().target, nullptr);
|
||||||
ASSERT_NE(flow->false_.target, nullptr);
|
ASSERT_NE(flow->False().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(0u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -318,15 +318,15 @@ TEST_F(IR_BuilderImplTest, IfStatement_JumpChainToMerge) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(if_flow->true_.target, nullptr);
|
ASSERT_NE(if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow->false_.target, nullptr);
|
ASSERT_NE(if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow->merge.target, nullptr);
|
ASSERT_NE(if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(loop_flow, nullptr);
|
ASSERT_NE(loop_flow, nullptr);
|
||||||
ASSERT_NE(loop_flow->start.target, nullptr);
|
ASSERT_NE(loop_flow->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->continuing.target, nullptr);
|
ASSERT_NE(loop_flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->merge.target, nullptr);
|
ASSERT_NE(loop_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -367,19 +367,19 @@ TEST_F(IR_BuilderImplTest, Loop_WithBreak) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(flow->start.target, nullptr);
|
ASSERT_NE(flow->Start().target, nullptr);
|
||||||
ASSERT_NE(flow->continuing.target, nullptr);
|
ASSERT_NE(flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(0u, flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -408,28 +408,28 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinue) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(loop_flow->start.target, nullptr);
|
ASSERT_NE(loop_flow->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->continuing.target, nullptr);
|
ASSERT_NE(loop_flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->merge.target, nullptr);
|
ASSERT_NE(loop_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(if_flow->true_.target, nullptr);
|
ASSERT_NE(if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow->false_.target, nullptr);
|
ASSERT_NE(if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow->merge.target, nullptr);
|
ASSERT_NE(if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -475,28 +475,28 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinuing_BreakIf) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(loop_flow->start.target, nullptr);
|
ASSERT_NE(loop_flow->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->continuing.target, nullptr);
|
ASSERT_NE(loop_flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->merge.target, nullptr);
|
ASSERT_NE(loop_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* break_if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* break_if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(break_if_flow->true_.target, nullptr);
|
ASSERT_NE(break_if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(break_if_flow->false_.target, nullptr);
|
ASSERT_NE(break_if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(break_if_flow->merge.target, nullptr);
|
ASSERT_NE(break_if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, break_if_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, break_if_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, break_if_flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, break_if_flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, break_if_flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, break_if_flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, break_if_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, break_if_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -586,28 +586,28 @@ TEST_F(IR_BuilderImplTest, Loop_WithReturn) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(loop_flow->start.target, nullptr);
|
ASSERT_NE(loop_flow->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->continuing.target, nullptr);
|
ASSERT_NE(loop_flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->merge.target, nullptr);
|
ASSERT_NE(loop_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(if_flow->true_.target, nullptr);
|
ASSERT_NE(if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow->false_.target, nullptr);
|
ASSERT_NE(if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow->merge.target, nullptr);
|
ASSERT_NE(if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, loop_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(0u, loop_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -648,19 +648,19 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(loop_flow->start.target, nullptr);
|
ASSERT_NE(loop_flow->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->continuing.target, nullptr);
|
ASSERT_NE(loop_flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->merge.target, nullptr);
|
ASSERT_NE(loop_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(0u, loop_flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, loop_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(0u, loop_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -693,25 +693,25 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn_ContinuingBreakIf) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(loop_flow->start.target, nullptr);
|
ASSERT_NE(loop_flow->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->continuing.target, nullptr);
|
ASSERT_NE(loop_flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->merge.target, nullptr);
|
ASSERT_NE(loop_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* break_if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* break_if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(break_if_flow->true_.target, nullptr);
|
ASSERT_NE(break_if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(break_if_flow->false_.target, nullptr);
|
ASSERT_NE(break_if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(break_if_flow->merge.target, nullptr);
|
ASSERT_NE(break_if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(0u, loop_flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
// This is 1 because only the loop branch happens. The subsequent if return is dead code.
|
// This is 1 because only the loop branch happens. The subsequent if return is dead code.
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -736,28 +736,28 @@ TEST_F(IR_BuilderImplTest, Loop_WithIf_BothBranchesBreak) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(loop_flow->start.target, nullptr);
|
ASSERT_NE(loop_flow->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->continuing.target, nullptr);
|
ASSERT_NE(loop_flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow->merge.target, nullptr);
|
ASSERT_NE(loop_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
|
||||||
ASSERT_NE(if_flow->true_.target, nullptr);
|
ASSERT_NE(if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow->false_.target, nullptr);
|
ASSERT_NE(if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow->merge.target, nullptr);
|
ASSERT_NE(if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(0u, loop_flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, if_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(0u, if_flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -807,96 +807,96 @@ TEST_F(IR_BuilderImplTest, Loop_Nested) {
|
|||||||
|
|
||||||
auto block_exit = [&](const ir::FlowNode* node) -> const ir::FlowNode* {
|
auto block_exit = [&](const ir::FlowNode* node) -> const ir::FlowNode* {
|
||||||
if (auto* block = As<ir::Block>(node)) {
|
if (auto* block = As<ir::Block>(node)) {
|
||||||
return block->branch.target;
|
return block->Branch().target;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* loop_flow_a = As<ir::Loop>(m->functions[0]->start_target->branch.target);
|
auto* loop_flow_a = As<ir::Loop>(m->functions[0]->StartTarget()->Branch().target);
|
||||||
ASSERT_NE(loop_flow_a, nullptr);
|
ASSERT_NE(loop_flow_a, nullptr);
|
||||||
ASSERT_NE(loop_flow_a->start.target, nullptr);
|
ASSERT_NE(loop_flow_a->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_a->continuing.target, nullptr);
|
ASSERT_NE(loop_flow_a->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_a->merge.target, nullptr);
|
ASSERT_NE(loop_flow_a->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* loop_flow_b = As<ir::Loop>(block_exit(loop_flow_a->start.target));
|
auto* loop_flow_b = As<ir::Loop>(block_exit(loop_flow_a->Start().target));
|
||||||
ASSERT_NE(loop_flow_b, nullptr);
|
ASSERT_NE(loop_flow_b, nullptr);
|
||||||
ASSERT_NE(loop_flow_b->start.target, nullptr);
|
ASSERT_NE(loop_flow_b->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_b->continuing.target, nullptr);
|
ASSERT_NE(loop_flow_b->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_b->merge.target, nullptr);
|
ASSERT_NE(loop_flow_b->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* if_flow_a = As<ir::If>(block_exit(loop_flow_b->start.target));
|
auto* if_flow_a = As<ir::If>(block_exit(loop_flow_b->Start().target));
|
||||||
ASSERT_NE(if_flow_a, nullptr);
|
ASSERT_NE(if_flow_a, nullptr);
|
||||||
ASSERT_NE(if_flow_a->true_.target, nullptr);
|
ASSERT_NE(if_flow_a->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow_a->false_.target, nullptr);
|
ASSERT_NE(if_flow_a->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow_a->merge.target, nullptr);
|
ASSERT_NE(if_flow_a->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* if_flow_b = As<ir::If>(block_exit(if_flow_a->merge.target));
|
auto* if_flow_b = As<ir::If>(block_exit(if_flow_a->Merge().target));
|
||||||
ASSERT_NE(if_flow_b, nullptr);
|
ASSERT_NE(if_flow_b, nullptr);
|
||||||
ASSERT_NE(if_flow_b->true_.target, nullptr);
|
ASSERT_NE(if_flow_b->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow_b->false_.target, nullptr);
|
ASSERT_NE(if_flow_b->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow_b->merge.target, nullptr);
|
ASSERT_NE(if_flow_b->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* loop_flow_c = As<ir::Loop>(block_exit(loop_flow_b->continuing.target));
|
auto* loop_flow_c = As<ir::Loop>(block_exit(loop_flow_b->Continuing().target));
|
||||||
ASSERT_NE(loop_flow_c, nullptr);
|
ASSERT_NE(loop_flow_c, nullptr);
|
||||||
ASSERT_NE(loop_flow_c->start.target, nullptr);
|
ASSERT_NE(loop_flow_c->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_c->continuing.target, nullptr);
|
ASSERT_NE(loop_flow_c->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_c->merge.target, nullptr);
|
ASSERT_NE(loop_flow_c->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* loop_flow_d = As<ir::Loop>(block_exit(loop_flow_c->merge.target));
|
auto* loop_flow_d = As<ir::Loop>(block_exit(loop_flow_c->Merge().target));
|
||||||
ASSERT_NE(loop_flow_d, nullptr);
|
ASSERT_NE(loop_flow_d, nullptr);
|
||||||
ASSERT_NE(loop_flow_d->start.target, nullptr);
|
ASSERT_NE(loop_flow_d->Start().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_d->continuing.target, nullptr);
|
ASSERT_NE(loop_flow_d->Continuing().target, nullptr);
|
||||||
ASSERT_NE(loop_flow_d->merge.target, nullptr);
|
ASSERT_NE(loop_flow_d->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* if_flow_c = As<ir::If>(block_exit(loop_flow_d->continuing.target));
|
auto* if_flow_c = As<ir::If>(block_exit(loop_flow_d->Continuing().target));
|
||||||
ASSERT_NE(if_flow_c, nullptr);
|
ASSERT_NE(if_flow_c, nullptr);
|
||||||
ASSERT_NE(if_flow_c->true_.target, nullptr);
|
ASSERT_NE(if_flow_c->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow_c->false_.target, nullptr);
|
ASSERT_NE(if_flow_c->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow_c->merge.target, nullptr);
|
ASSERT_NE(if_flow_c->Merge().target, nullptr);
|
||||||
|
|
||||||
auto* if_flow_d = As<ir::If>(block_exit(loop_flow_b->merge.target));
|
auto* if_flow_d = As<ir::If>(block_exit(loop_flow_b->Merge().target));
|
||||||
ASSERT_NE(if_flow_d, nullptr);
|
ASSERT_NE(if_flow_d, nullptr);
|
||||||
ASSERT_NE(if_flow_d->true_.target, nullptr);
|
ASSERT_NE(if_flow_d->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow_d->false_.target, nullptr);
|
ASSERT_NE(if_flow_d->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow_d->merge.target, nullptr);
|
ASSERT_NE(if_flow_d->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, loop_flow_a->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_a->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow_a->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow_a->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_a->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_a->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_a->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_a->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_b->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_b->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow_b->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow_b->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow_b->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow_b->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_b->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_b->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_c->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_c->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow_c->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow_c->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, loop_flow_c->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(0u, loop_flow_c->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_c->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_c->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_d->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_d->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, loop_flow_d->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, loop_flow_d->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_d->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_d->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, loop_flow_d->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, loop_flow_d->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_a->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_a->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_a->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_a->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_a->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_a->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_a->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_a->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_b->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_b->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_b->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_b->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_b->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_b->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_b->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_b->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_c->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_c->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_c->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_c->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_c->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_c->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_c->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_c->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_d->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_d->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_d->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_d->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_d->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_d->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow_d->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow_d->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1015,28 +1015,28 @@ TEST_F(IR_BuilderImplTest, While) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(flow->start.target, nullptr);
|
ASSERT_NE(flow->Start().target, nullptr);
|
||||||
ASSERT_NE(flow->continuing.target, nullptr);
|
ASSERT_NE(flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_NE(flow->start.target->As<ir::Block>()->branch.target, nullptr);
|
ASSERT_NE(flow->Start().target->As<ir::Block>()->Branch().target, nullptr);
|
||||||
ASSERT_TRUE(flow->start.target->As<ir::Block>()->branch.target->Is<ir::If>());
|
ASSERT_TRUE(flow->Start().target->As<ir::Block>()->Branch().target->Is<ir::If>());
|
||||||
auto* if_flow = flow->start.target->As<ir::Block>()->branch.target->As<ir::If>();
|
auto* if_flow = flow->Start().target->As<ir::Block>()->Branch().target->As<ir::If>();
|
||||||
ASSERT_NE(if_flow->true_.target, nullptr);
|
ASSERT_NE(if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow->false_.target, nullptr);
|
ASSERT_NE(if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow->merge.target, nullptr);
|
ASSERT_NE(if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1081,28 +1081,28 @@ TEST_F(IR_BuilderImplTest, While_Return) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(flow->start.target, nullptr);
|
ASSERT_NE(flow->Start().target, nullptr);
|
||||||
ASSERT_NE(flow->continuing.target, nullptr);
|
ASSERT_NE(flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_NE(flow->start.target->As<ir::Block>()->branch.target, nullptr);
|
ASSERT_NE(flow->Start().target->As<ir::Block>()->Branch().target, nullptr);
|
||||||
ASSERT_TRUE(flow->start.target->As<ir::Block>()->branch.target->Is<ir::If>());
|
ASSERT_TRUE(flow->Start().target->As<ir::Block>()->Branch().target->Is<ir::If>());
|
||||||
auto* if_flow = flow->start.target->As<ir::Block>()->branch.target->As<ir::If>();
|
auto* if_flow = flow->Start().target->As<ir::Block>()->Branch().target->As<ir::If>();
|
||||||
ASSERT_NE(if_flow->true_.target, nullptr);
|
ASSERT_NE(if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow->false_.target, nullptr);
|
ASSERT_NE(if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow->merge.target, nullptr);
|
ASSERT_NE(if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(0u, flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1155,28 +1155,28 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(flow->start.target, nullptr);
|
ASSERT_NE(flow->Start().target, nullptr);
|
||||||
ASSERT_NE(flow->continuing.target, nullptr);
|
ASSERT_NE(flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_NE(flow->start.target->As<ir::Block>()->branch.target, nullptr);
|
ASSERT_NE(flow->Start().target->As<ir::Block>()->Branch().target, nullptr);
|
||||||
ASSERT_TRUE(flow->start.target->As<ir::Block>()->branch.target->Is<ir::If>());
|
ASSERT_TRUE(flow->Start().target->As<ir::Block>()->Branch().target->Is<ir::If>());
|
||||||
auto* if_flow = flow->start.target->As<ir::Block>()->branch.target->As<ir::If>();
|
auto* if_flow = flow->Start().target->As<ir::Block>()->Branch().target->As<ir::If>();
|
||||||
ASSERT_NE(if_flow->true_.target, nullptr);
|
ASSERT_NE(if_flow->True().target, nullptr);
|
||||||
ASSERT_NE(if_flow->false_.target, nullptr);
|
ASSERT_NE(if_flow->False().target, nullptr);
|
||||||
ASSERT_NE(if_flow->merge.target, nullptr);
|
ASSERT_NE(if_flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()), R"()");
|
EXPECT_EQ(Disassemble(m.Get()), R"()");
|
||||||
}
|
}
|
||||||
@ -1189,18 +1189,18 @@ TEST_F(IR_BuilderImplTest, For_NoInitCondOrContinuing) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
|
||||||
ASSERT_NE(flow->start.target, nullptr);
|
ASSERT_NE(flow->Start().target, nullptr);
|
||||||
ASSERT_NE(flow->continuing.target, nullptr);
|
ASSERT_NE(flow->Continuing().target, nullptr);
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
|
EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length());
|
EXPECT_EQ(0u, flow->Continuing().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1231,31 +1231,33 @@ TEST_F(IR_BuilderImplTest, Switch) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
ASSERT_EQ(3u, flow->cases.Length());
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[0].selectors.Length());
|
auto cases = flow->Cases();
|
||||||
ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
|
ASSERT_EQ(3u, cases.Length());
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, cases[0].selectors.Length());
|
||||||
|
ASSERT_TRUE(cases[0].selectors[0].val->Value()->Is<constant::Scalar<tint::i32>>());
|
||||||
EXPECT_EQ(0_i,
|
EXPECT_EQ(0_i,
|
||||||
flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
|
cases[0].selectors[0].val->Value()->As<constant::Scalar<tint::i32>>()->ValueOf());
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[1].selectors.Length());
|
ASSERT_EQ(1u, cases[1].selectors.Length());
|
||||||
ASSERT_TRUE(flow->cases[1].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
|
ASSERT_TRUE(cases[1].selectors[0].val->Value()->Is<constant::Scalar<tint::i32>>());
|
||||||
EXPECT_EQ(1_i,
|
EXPECT_EQ(1_i,
|
||||||
flow->cases[1].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
|
cases[1].selectors[0].val->Value()->As<constant::Scalar<tint::i32>>()->ValueOf());
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[2].selectors.Length());
|
ASSERT_EQ(1u, cases[2].selectors.Length());
|
||||||
EXPECT_TRUE(flow->cases[2].selectors[0].IsDefault());
|
EXPECT_TRUE(cases[2].selectors[0].IsDefault());
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[1].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[2].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[2].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(3u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(3u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1295,27 +1297,28 @@ TEST_F(IR_BuilderImplTest, Switch_MultiSelector) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
ASSERT_EQ(1u, flow->cases.Length());
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
ASSERT_EQ(3u, flow->cases[0].selectors.Length());
|
auto cases = flow->Cases();
|
||||||
ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
|
ASSERT_EQ(1u, cases.Length());
|
||||||
|
ASSERT_EQ(3u, cases[0].selectors.Length());
|
||||||
|
ASSERT_TRUE(cases[0].selectors[0].val->Value()->Is<constant::Scalar<tint::i32>>());
|
||||||
EXPECT_EQ(0_i,
|
EXPECT_EQ(0_i,
|
||||||
flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
|
cases[0].selectors[0].val->Value()->As<constant::Scalar<tint::i32>>()->ValueOf());
|
||||||
|
|
||||||
ASSERT_TRUE(flow->cases[0].selectors[1].val->value->Is<constant::Scalar<tint::i32>>());
|
ASSERT_TRUE(cases[0].selectors[1].val->Value()->Is<constant::Scalar<tint::i32>>());
|
||||||
EXPECT_EQ(1_i,
|
EXPECT_EQ(1_i,
|
||||||
flow->cases[0].selectors[1].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
|
cases[0].selectors[1].val->Value()->As<constant::Scalar<tint::i32>>()->ValueOf());
|
||||||
|
|
||||||
EXPECT_TRUE(flow->cases[0].selectors[2].IsDefault());
|
EXPECT_TRUE(cases[0].selectors[2].IsDefault());
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1343,19 +1346,20 @@ TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
ASSERT_EQ(1u, flow->cases.Length());
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[0].selectors.Length());
|
auto cases = flow->Cases();
|
||||||
EXPECT_TRUE(flow->cases[0].selectors[0].IsDefault());
|
ASSERT_EQ(1u, cases.Length());
|
||||||
|
ASSERT_EQ(1u, cases[0].selectors.Length());
|
||||||
|
EXPECT_TRUE(cases[0].selectors[0].IsDefault());
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1385,26 +1389,27 @@ TEST_F(IR_BuilderImplTest, Switch_WithBreak) {
|
|||||||
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
ASSERT_EQ(2u, flow->cases.Length());
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[0].selectors.Length());
|
auto cases = flow->Cases();
|
||||||
ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
|
ASSERT_EQ(2u, cases.Length());
|
||||||
|
ASSERT_EQ(1u, cases[0].selectors.Length());
|
||||||
|
ASSERT_TRUE(cases[0].selectors[0].val->Value()->Is<constant::Scalar<tint::i32>>());
|
||||||
EXPECT_EQ(0_i,
|
EXPECT_EQ(0_i,
|
||||||
flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
|
cases[0].selectors[0].val->Value()->As<constant::Scalar<tint::i32>>()->ValueOf());
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[1].selectors.Length());
|
ASSERT_EQ(1u, cases[1].selectors.Length());
|
||||||
EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
|
EXPECT_TRUE(cases[1].selectors[0].IsDefault());
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[1].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(2u, flow->Merge().target->InboundBranches().Length());
|
||||||
// This is 1 because the if is dead-code eliminated and the return doesn't happen.
|
// This is 1 because the if is dead-code eliminated and the return doesn't happen.
|
||||||
EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
@ -1441,25 +1446,26 @@ TEST_F(IR_BuilderImplTest, Switch_AllReturn) {
|
|||||||
ASSERT_EQ(FindSingleFlowNode<ir::If>(m.Get()), nullptr);
|
ASSERT_EQ(FindSingleFlowNode<ir::If>(m.Get()), nullptr);
|
||||||
|
|
||||||
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
|
||||||
ASSERT_NE(flow->merge.target, nullptr);
|
ASSERT_NE(flow->Merge().target, nullptr);
|
||||||
ASSERT_EQ(2u, flow->cases.Length());
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, m->functions.Length());
|
ASSERT_EQ(1u, m->functions.Length());
|
||||||
auto* func = m->functions[0];
|
auto* func = m->functions[0];
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[0].selectors.Length());
|
auto cases = flow->Cases();
|
||||||
ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
|
ASSERT_EQ(2u, cases.Length());
|
||||||
|
ASSERT_EQ(1u, cases[0].selectors.Length());
|
||||||
|
ASSERT_TRUE(cases[0].selectors[0].val->Value()->Is<constant::Scalar<tint::i32>>());
|
||||||
EXPECT_EQ(0_i,
|
EXPECT_EQ(0_i,
|
||||||
flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
|
cases[0].selectors[0].val->Value()->As<constant::Scalar<tint::i32>>()->ValueOf());
|
||||||
|
|
||||||
ASSERT_EQ(1u, flow->cases[1].selectors.Length());
|
ASSERT_EQ(1u, cases[1].selectors.Length());
|
||||||
EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
|
EXPECT_TRUE(cases[1].selectors[0].IsDefault());
|
||||||
|
|
||||||
EXPECT_EQ(1u, flow->inbound_branches.Length());
|
EXPECT_EQ(1u, flow->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length());
|
EXPECT_EQ(1u, cases[1].Start().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length());
|
EXPECT_EQ(0u, flow->Merge().target->InboundBranches().Length());
|
||||||
EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
|
EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
|
||||||
|
|
||||||
EXPECT_EQ(Disassemble(m.Get()),
|
EXPECT_EQ(Disassemble(m.Get()),
|
||||||
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
|
||||||
|
@ -18,11 +18,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Function);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Function::Function(Symbol n,
|
Function::Function(Symbol name,
|
||||||
type::Type* rt,
|
type::Type* rt,
|
||||||
PipelineStage stage,
|
PipelineStage stage,
|
||||||
std::optional<std::array<uint32_t, 3>> wg_size)
|
std::optional<std::array<uint32_t, 3>> wg_size)
|
||||||
: Base(), name(n), pipeline_stage(stage), workgroup_size(wg_size), return_type(rt) {}
|
: Base(), name_(name), return_type_(rt), pipeline_stage_(stage), workgroup_size_(wg_size) {}
|
||||||
|
|
||||||
Function::~Function() = default;
|
Function::~Function() = default;
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "src/tint/ir/flow_node.h"
|
#include "src/tint/ir/flow_node.h"
|
||||||
#include "src/tint/ir/function_param.h"
|
#include "src/tint/ir/function_param.h"
|
||||||
@ -71,32 +72,81 @@ class Function : public utils::Castable<Function, FlowNode> {
|
|||||||
type::Type* rt,
|
type::Type* rt,
|
||||||
PipelineStage stage = PipelineStage::kUndefined,
|
PipelineStage stage = PipelineStage::kUndefined,
|
||||||
std::optional<std::array<uint32_t, 3>> wg_size = {});
|
std::optional<std::array<uint32_t, 3>> wg_size = {});
|
||||||
|
Function(Function&&) = delete;
|
||||||
|
Function(const Function&) = delete;
|
||||||
~Function() override;
|
~Function() override;
|
||||||
|
|
||||||
/// The function name
|
Function& operator=(Function&&) = delete;
|
||||||
Symbol name;
|
Function& operator=(const Function&) = delete;
|
||||||
|
|
||||||
/// The pipeline stage for the function, `kUndefined` if the function is not an entry point
|
/// @returns the function name
|
||||||
PipelineStage pipeline_stage = PipelineStage::kUndefined;
|
Symbol Name() const { return name_; }
|
||||||
|
|
||||||
/// If this is a `compute` entry point, holds the workgroup size information
|
/// Sets the function stage
|
||||||
std::optional<std::array<uint32_t, 3>> workgroup_size;
|
/// @param stage the stage to set
|
||||||
|
void SetStage(PipelineStage stage) { pipeline_stage_ = stage; }
|
||||||
|
|
||||||
/// The function return type
|
/// @returns the function pipeline stage
|
||||||
const type::Type* return_type = nullptr;
|
PipelineStage Stage() const { return pipeline_stage_; }
|
||||||
/// The function return attributes if any
|
|
||||||
utils::Vector<ReturnAttribute, 1> return_attributes;
|
|
||||||
/// If the return attribute is `kLocation` this stores the location value.
|
|
||||||
std::optional<uint32_t> return_location;
|
|
||||||
|
|
||||||
/// The parameters to the function
|
/// Sets the workgroup size
|
||||||
utils::Vector<FunctionParam*, 1> params;
|
/// @param x the x size
|
||||||
|
/// @param y the y size
|
||||||
|
/// @param z the z size
|
||||||
|
void SetWorkgroupSize(uint32_t x, uint32_t y, uint32_t z) { workgroup_size_ = {x, y, z}; }
|
||||||
|
|
||||||
/// The start target is the first block in a function.
|
/// @returns the workgroup size information
|
||||||
Block* start_target = nullptr;
|
std::optional<std::array<uint32_t, 3>> WorkgroupSize() const { return workgroup_size_; }
|
||||||
/// The end target is the end of the function. It is used as the branch target if a return is
|
|
||||||
/// encountered in the function.
|
/// @returns the return type for the function
|
||||||
FunctionTerminator* end_target = nullptr;
|
const type::Type* ReturnType() const { return return_type_; }
|
||||||
|
|
||||||
|
/// Sets the return attributes
|
||||||
|
/// @param attrs the attributes to set
|
||||||
|
void SetReturnAttributes(utils::VectorRef<ReturnAttribute> attrs) {
|
||||||
|
return_attributes_ = std::move(attrs);
|
||||||
|
}
|
||||||
|
/// @returns the return attributes
|
||||||
|
utils::VectorRef<ReturnAttribute> ReturnAttributes() const { return return_attributes_; }
|
||||||
|
|
||||||
|
/// Sets the return location
|
||||||
|
/// @param loc the location to set
|
||||||
|
void SetReturnLocation(std::optional<uint32_t> loc) { return_location_ = loc; }
|
||||||
|
/// @returns the return location
|
||||||
|
std::optional<uint32_t> ReturnLocation() const { return return_location_; }
|
||||||
|
|
||||||
|
/// Sets the function parameters
|
||||||
|
/// @param params the function paramters
|
||||||
|
void SetParams(utils::VectorRef<FunctionParam*> params) { params_ = std::move(params); }
|
||||||
|
|
||||||
|
/// @returns the function parameters
|
||||||
|
utils::VectorRef<FunctionParam*> Params() const { return params_; }
|
||||||
|
|
||||||
|
/// Sets the start target for the function
|
||||||
|
/// @param target the start target
|
||||||
|
void SetStartTarget(Block* target) { start_target_ = target; }
|
||||||
|
/// @returns the function start target
|
||||||
|
Block* StartTarget() const { return start_target_; }
|
||||||
|
|
||||||
|
/// Sets the end target for the function
|
||||||
|
/// @param target the end target
|
||||||
|
void SetEndTarget(FunctionTerminator* target) { end_target_ = target; }
|
||||||
|
/// @returns the function end target
|
||||||
|
FunctionTerminator* EndTarget() const { return end_target_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Symbol name_;
|
||||||
|
const type::Type* return_type_;
|
||||||
|
PipelineStage pipeline_stage_;
|
||||||
|
std::optional<std::array<uint32_t, 3>> workgroup_size_;
|
||||||
|
|
||||||
|
utils::Vector<ReturnAttribute, 1> return_attributes_;
|
||||||
|
std::optional<uint32_t> return_location_;
|
||||||
|
|
||||||
|
utils::Vector<FunctionParam*, 1> params_;
|
||||||
|
|
||||||
|
Block* start_target_ = nullptr;
|
||||||
|
FunctionTerminator* end_target_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
utils::StringStream& operator<<(utils::StringStream& out, Function::PipelineStage value);
|
utils::StringStream& operator<<(utils::StringStream& out, Function::PipelineStage value);
|
||||||
|
@ -18,7 +18,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::FunctionParam);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
FunctionParam::FunctionParam(const type::Type* ty) : type(ty) {}
|
FunctionParam::FunctionParam(const type::Type* ty) : type_(ty) {}
|
||||||
|
|
||||||
FunctionParam::~FunctionParam() = default;
|
FunctionParam::~FunctionParam() = default;
|
||||||
|
|
||||||
|
@ -34,10 +34,11 @@ class FunctionParam : public utils::Castable<FunctionParam, Value> {
|
|||||||
FunctionParam& operator=(FunctionParam&& inst) = delete;
|
FunctionParam& operator=(FunctionParam&& inst) = delete;
|
||||||
|
|
||||||
/// @returns the type of the var
|
/// @returns the type of the var
|
||||||
const type::Type* Type() const override { return type; }
|
const type::Type* Type() const override { return type_; }
|
||||||
|
|
||||||
|
private:
|
||||||
/// The type of the parameter
|
/// The type of the parameter
|
||||||
const type::Type* type;
|
const type::Type* type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -18,7 +18,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::If);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
If::If(Value* cond) : Base(), condition(cond) {}
|
If::If(Value* cond) : Base(), condition_(cond) {}
|
||||||
|
|
||||||
If::~If() = default;
|
If::~If() = default;
|
||||||
|
|
||||||
|
@ -32,17 +32,36 @@ class If : public utils::Castable<If, FlowNode> {
|
|||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param cond the if condition
|
/// @param cond the if condition
|
||||||
explicit If(Value* cond);
|
explicit If(Value* cond);
|
||||||
|
If(const If&) = delete;
|
||||||
|
If(If&&) = delete;
|
||||||
~If() override;
|
~If() override;
|
||||||
|
|
||||||
/// The true branch block
|
If& operator=(const If&) = delete;
|
||||||
|
If& operator=(If&&) = delete;
|
||||||
|
|
||||||
|
/// @returns the if condition
|
||||||
|
const Value* Condition() const { return condition_; }
|
||||||
|
|
||||||
|
/// @returns the true branch block
|
||||||
|
const Branch& True() const { return true_; }
|
||||||
|
/// @returns the true branch block
|
||||||
|
Branch& True() { return true_; }
|
||||||
|
|
||||||
|
/// @returns the false branch block
|
||||||
|
const Branch& False() const { return false_; }
|
||||||
|
/// @returns the false branch block
|
||||||
|
Branch& False() { return false_; }
|
||||||
|
|
||||||
|
/// @returns the merge branch block
|
||||||
|
const Branch& Merge() const { return merge_; }
|
||||||
|
/// @returns the merge branch block
|
||||||
|
Branch& Merge() { return merge_; }
|
||||||
|
|
||||||
|
private:
|
||||||
Branch true_ = {};
|
Branch true_ = {};
|
||||||
/// The false branch block
|
|
||||||
Branch false_ = {};
|
Branch false_ = {};
|
||||||
/// An block to converge the true/false branches. The block always exists, but there maybe no
|
Branch merge_ = {};
|
||||||
/// branches into it. (e.g. if both branches `return`)
|
Value* condition_;
|
||||||
Branch merge = {};
|
|
||||||
/// Value holding the condition result
|
|
||||||
const Value* condition = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -19,10 +19,10 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Load);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Load::Load(const type::Type* type, Value* f) : Base(), result_type(type), from(f) {
|
Load::Load(const type::Type* type, Value* f) : Base(), result_type_(type), from_(f) {
|
||||||
TINT_ASSERT(IR, result_type);
|
TINT_ASSERT(IR, result_type_);
|
||||||
TINT_ASSERT(IR, from);
|
TINT_ASSERT(IR, from_);
|
||||||
from->AddUsage(this);
|
from_->AddUsage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Load::~Load() = default;
|
Load::~Load() = default;
|
||||||
|
@ -35,13 +35,14 @@ class Load : public utils::Castable<Load, Instruction> {
|
|||||||
Load& operator=(Load&& inst) = delete;
|
Load& operator=(Load&& inst) = delete;
|
||||||
|
|
||||||
/// @returns the type of the value
|
/// @returns the type of the value
|
||||||
const type::Type* Type() const override { return result_type; }
|
const type::Type* Type() const override { return result_type_; }
|
||||||
|
|
||||||
/// the result type of the instruction
|
/// @returns the avlue being loaded from
|
||||||
const type::Type* result_type = nullptr;
|
Value* From() const { return from_; }
|
||||||
|
|
||||||
/// the value being loaded
|
private:
|
||||||
Value* from = nullptr;
|
const type::Type* result_type_;
|
||||||
|
Value* from_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -33,12 +33,12 @@ TEST_F(IR_InstructionTest, CreateLoad) {
|
|||||||
const auto* inst = b.Load(var);
|
const auto* inst = b.Load(var);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Load>());
|
ASSERT_TRUE(inst->Is<Load>());
|
||||||
ASSERT_EQ(inst->from, var);
|
ASSERT_EQ(inst->From(), var);
|
||||||
|
|
||||||
EXPECT_EQ(inst->Type(), store_type);
|
EXPECT_EQ(inst->Type(), store_type);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->from->Is<ir::Var>());
|
ASSERT_TRUE(inst->From()->Is<ir::Var>());
|
||||||
EXPECT_EQ(inst->from, var);
|
EXPECT_EQ(inst->From(), var);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IR_InstructionTest, Load_Usage) {
|
TEST_F(IR_InstructionTest, Load_Usage) {
|
||||||
@ -50,9 +50,9 @@ TEST_F(IR_InstructionTest, Load_Usage) {
|
|||||||
store_type, builtin::AddressSpace::kFunction, builtin::Access::kReadWrite));
|
store_type, builtin::AddressSpace::kFunction, builtin::Access::kReadWrite));
|
||||||
const auto* inst = b.Load(var);
|
const auto* inst = b.Load(var);
|
||||||
|
|
||||||
ASSERT_NE(inst->from, nullptr);
|
ASSERT_NE(inst->From(), nullptr);
|
||||||
ASSERT_EQ(inst->from->Usage().Length(), 1u);
|
ASSERT_EQ(inst->From()->Usage().Length(), 1u);
|
||||||
EXPECT_EQ(inst->from->Usage()[0], inst);
|
EXPECT_EQ(inst->From()->Usage()[0], inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -26,16 +26,32 @@ class Loop : public utils::Castable<Loop, FlowNode> {
|
|||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
Loop();
|
Loop();
|
||||||
|
Loop(const Loop&) = delete;
|
||||||
|
Loop(Loop&&) = delete;
|
||||||
~Loop() override;
|
~Loop() override;
|
||||||
|
|
||||||
/// The start block is the first block in a loop.
|
Loop& operator=(const Loop&) = delete;
|
||||||
Branch start = {};
|
Loop& operator=(Loop&&) = delete;
|
||||||
/// The continue target of the block.
|
|
||||||
Branch continuing = {};
|
/// @returns the switch start branch
|
||||||
/// The loop merge target. If the `loop` does a `return` then this block may not actually
|
const Branch& Start() const { return start_; }
|
||||||
/// end up in the control flow. We need it if the loop does a `break` we know where to break
|
/// @returns the switch start branch
|
||||||
/// too.
|
Branch& Start() { return start_; }
|
||||||
Branch merge = {};
|
|
||||||
|
/// @returns the switch continuing branch
|
||||||
|
const Branch& Continuing() const { return continuing_; }
|
||||||
|
/// @returns the switch continuing branch
|
||||||
|
Branch& Continuing() { return continuing_; }
|
||||||
|
|
||||||
|
/// @returns the switch merge branch
|
||||||
|
const Branch& Merge() const { return merge_; }
|
||||||
|
/// @returns the switch merge branch
|
||||||
|
Branch& Merge() { return merge_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Branch start_ = {};
|
||||||
|
Branch continuing_ = {};
|
||||||
|
Branch merge_ = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -25,7 +25,12 @@ class RootTerminator : public utils::Castable<RootTerminator, FlowNode> {
|
|||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
RootTerminator();
|
RootTerminator();
|
||||||
|
RootTerminator(const RootTerminator&) = delete;
|
||||||
|
RootTerminator(RootTerminator&&) = delete;
|
||||||
~RootTerminator() override;
|
~RootTerminator() override;
|
||||||
|
|
||||||
|
RootTerminator& operator=(const RootTerminator&) = delete;
|
||||||
|
RootTerminator& operator=(RootTerminator&&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -19,11 +19,11 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Store);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Store::Store(Value* t, Value* f) : Base(), to(t), from(f) {
|
Store::Store(Value* to, Value* from) : Base(), to_(to), from_(from) {
|
||||||
TINT_ASSERT(IR, to);
|
TINT_ASSERT(IR, to_);
|
||||||
TINT_ASSERT(IR, from);
|
TINT_ASSERT(IR, from_);
|
||||||
to->AddUsage(this);
|
to_->AddUsage(this);
|
||||||
from->AddUsage(this);
|
from_->AddUsage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Store::~Store() = default;
|
Store::~Store() = default;
|
||||||
|
@ -34,10 +34,15 @@ class Store : public utils::Castable<Store, Instruction> {
|
|||||||
Store& operator=(const Store& inst) = delete;
|
Store& operator=(const Store& inst) = delete;
|
||||||
Store& operator=(Store&& inst) = delete;
|
Store& operator=(Store&& inst) = delete;
|
||||||
|
|
||||||
/// the value being stored to
|
/// @returns the value being stored too
|
||||||
Value* to = nullptr;
|
Value* To() const { return to_; }
|
||||||
/// the value being stored
|
|
||||||
Value* from = nullptr;
|
/// @returns the value being stored
|
||||||
|
Value* From() const { return from_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Value* to_;
|
||||||
|
Value* from_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -33,10 +33,10 @@ TEST_F(IR_InstructionTest, CreateStore) {
|
|||||||
const auto* inst = b.Store(to, b.Constant(4_i));
|
const auto* inst = b.Store(to, b.Constant(4_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Store>());
|
ASSERT_TRUE(inst->Is<Store>());
|
||||||
ASSERT_EQ(inst->to, to);
|
ASSERT_EQ(inst->To(), to);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->from->Is<Constant>());
|
ASSERT_TRUE(inst->From()->Is<Constant>());
|
||||||
auto lhs = inst->from->As<Constant>()->value;
|
auto lhs = inst->From()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -48,13 +48,13 @@ TEST_F(IR_InstructionTest, Store_Usage) {
|
|||||||
auto* to = b.Discard();
|
auto* to = b.Discard();
|
||||||
const auto* inst = b.Store(to, b.Constant(4_i));
|
const auto* inst = b.Store(to, b.Constant(4_i));
|
||||||
|
|
||||||
ASSERT_NE(inst->to, nullptr);
|
ASSERT_NE(inst->To(), nullptr);
|
||||||
ASSERT_EQ(inst->to->Usage().Length(), 1u);
|
ASSERT_EQ(inst->To()->Usage().Length(), 1u);
|
||||||
EXPECT_EQ(inst->to->Usage()[0], inst);
|
EXPECT_EQ(inst->To()->Usage()[0], inst);
|
||||||
|
|
||||||
ASSERT_NE(inst->from, nullptr);
|
ASSERT_NE(inst->From(), nullptr);
|
||||||
ASSERT_EQ(inst->from->Usage().Length(), 1u);
|
ASSERT_EQ(inst->From()->Usage().Length(), 1u);
|
||||||
EXPECT_EQ(inst->from->Usage()[0], inst);
|
EXPECT_EQ(inst->From()->Usage()[0], inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -18,7 +18,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Switch);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Switch::Switch(Value* cond) : Base(), condition(cond) {}
|
Switch::Switch(Value* cond) : Base(), condition_(cond) {}
|
||||||
|
|
||||||
Switch::~Switch() = default;
|
Switch::~Switch() = default;
|
||||||
|
|
||||||
|
@ -41,21 +41,40 @@ class Switch : public utils::Castable<Switch, FlowNode> {
|
|||||||
utils::Vector<CaseSelector, 4> selectors;
|
utils::Vector<CaseSelector, 4> selectors;
|
||||||
/// The start block for the case block.
|
/// The start block for the case block.
|
||||||
Branch start = {};
|
Branch start = {};
|
||||||
|
|
||||||
|
/// @returns the case start target
|
||||||
|
const Branch& Start() const { return start; }
|
||||||
|
/// @returns the case start target
|
||||||
|
Branch& Start() { return start; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param cond the condition
|
/// @param cond the condition
|
||||||
explicit Switch(Value* cond);
|
explicit Switch(Value* cond);
|
||||||
|
Switch(const Switch&) = delete;
|
||||||
|
Switch(Switch&&) = delete;
|
||||||
~Switch() override;
|
~Switch() override;
|
||||||
|
|
||||||
/// The switch merge target
|
Switch& operator=(const Switch&) = delete;
|
||||||
Branch merge = {};
|
Switch& operator=(Switch&&) = delete;
|
||||||
|
|
||||||
/// The switch case statements
|
/// @returns the switch merge branch
|
||||||
utils::Vector<Case, 4> cases;
|
const Branch& Merge() const { return merge_; }
|
||||||
|
/// @returns the switch merge branch
|
||||||
|
Branch& Merge() { return merge_; }
|
||||||
|
|
||||||
/// Value holding the condition result
|
/// @returns the switch cases
|
||||||
const Value* condition = nullptr;
|
utils::VectorRef<Case> Cases() const { return cases_; }
|
||||||
|
/// @returns the switch cases
|
||||||
|
utils::Vector<Case, 4>& Cases() { return cases_; }
|
||||||
|
|
||||||
|
/// @returns the condition
|
||||||
|
const Value* Condition() const { return condition_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Branch merge_ = {};
|
||||||
|
utils::Vector<Case, 4> cases_;
|
||||||
|
Value* condition_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -33,7 +33,6 @@ template <typename BASE>
|
|||||||
class TestHelperBase : public BASE, public ProgramBuilder {
|
class TestHelperBase : public BASE, public ProgramBuilder {
|
||||||
public:
|
public:
|
||||||
TestHelperBase() = default;
|
TestHelperBase() = default;
|
||||||
|
|
||||||
~TestHelperBase() override = default;
|
~TestHelperBase() override = default;
|
||||||
|
|
||||||
/// Build the module, cleaning up the program before returning.
|
/// Build the module, cleaning up the program before returning.
|
||||||
|
@ -91,14 +91,14 @@ class State {
|
|||||||
const ast::Function* Fn(const Function* fn) {
|
const ast::Function* Fn(const Function* fn) {
|
||||||
SCOPED_NESTING();
|
SCOPED_NESTING();
|
||||||
|
|
||||||
auto name = Sym(fn->name);
|
auto name = Sym(fn->Name());
|
||||||
// TODO(crbug.com/tint/1915): Properly implement this when we've fleshed out Function
|
// TODO(crbug.com/tint/1915): Properly implement this when we've fleshed out Function
|
||||||
utils::Vector<const ast::Parameter*, 1> params{};
|
utils::Vector<const ast::Parameter*, 1> params{};
|
||||||
auto ret_ty = Type(fn->return_type);
|
auto ret_ty = Type(fn->ReturnType());
|
||||||
if (!ret_ty) {
|
if (!ret_ty) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto* body = FlowNodeGraph(fn->start_target);
|
auto* body = FlowNodeGraph(fn->StartTarget());
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ class State {
|
|||||||
branch->target,
|
branch->target,
|
||||||
|
|
||||||
[&](const ir::Block* block) {
|
[&](const ir::Block* block) {
|
||||||
for (auto* inst : block->instructions) {
|
for (const auto* inst : block->Instructions()) {
|
||||||
auto stmt = Stmt(inst);
|
auto stmt = Stmt(inst);
|
||||||
if (TINT_UNLIKELY(!stmt)) {
|
if (TINT_UNLIKELY(!stmt)) {
|
||||||
return kError;
|
return kError;
|
||||||
@ -135,7 +135,7 @@ class State {
|
|||||||
stmts.Push(s);
|
stmts.Push(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
branch = &block->branch;
|
branch = &block->Branch();
|
||||||
return kContinue;
|
return kContinue;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -145,8 +145,8 @@ class State {
|
|||||||
return kError;
|
return kError;
|
||||||
}
|
}
|
||||||
stmts.Push(stmt);
|
stmts.Push(stmt);
|
||||||
branch = &if_->merge;
|
branch = &if_->Merge();
|
||||||
return branch->target->inbound_branches.IsEmpty() ? kStop : kContinue;
|
return branch->target->InboundBranches().IsEmpty() ? kStop : kContinue;
|
||||||
},
|
},
|
||||||
|
|
||||||
[&](const ir::Switch* switch_) {
|
[&](const ir::Switch* switch_) {
|
||||||
@ -155,8 +155,8 @@ class State {
|
|||||||
return kError;
|
return kError;
|
||||||
}
|
}
|
||||||
stmts.Push(stmt);
|
stmts.Push(stmt);
|
||||||
branch = &switch_->merge;
|
branch = &switch_->Merge();
|
||||||
return branch->target->inbound_branches.IsEmpty() ? kStop : kContinue;
|
return branch->target->InboundBranches().IsEmpty() ? kStop : kContinue;
|
||||||
},
|
},
|
||||||
|
|
||||||
[&](const ir::FunctionTerminator*) {
|
[&](const ir::FunctionTerminator*) {
|
||||||
@ -189,25 +189,25 @@ class State {
|
|||||||
const ast::IfStatement* If(const ir::If* i) {
|
const ast::IfStatement* If(const ir::If* i) {
|
||||||
SCOPED_NESTING();
|
SCOPED_NESTING();
|
||||||
|
|
||||||
auto* cond = Expr(i->condition);
|
auto* cond = Expr(i->Condition());
|
||||||
auto* t = FlowNodeGraph(i->true_.target, i->merge.target);
|
auto* t = FlowNodeGraph(i->True().target, i->Merge().target);
|
||||||
if (TINT_UNLIKELY(!t)) {
|
if (TINT_UNLIKELY(!t)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsEmpty(i->false_.target, i->merge.target)) {
|
if (!IsEmpty(i->False().target, i->Merge().target)) {
|
||||||
// If the else target is an if flow node with the same merge target as this if, then
|
// If the else target is an if flow node with the same Merge().target as this if, then
|
||||||
// emit an 'else if' instead of a block statement for the else.
|
// emit an 'else if' instead of a block statement for the else.
|
||||||
if (auto* else_if = As<ir::If>(NextNonEmptyNode(i->false_.target));
|
if (auto* else_if = As<ir::If>(NextNonEmptyNode(i->False().target));
|
||||||
else_if &&
|
else_if &&
|
||||||
NextNonEmptyNode(i->merge.target) == NextNonEmptyNode(else_if->merge.target)) {
|
NextNonEmptyNode(i->Merge().target) == NextNonEmptyNode(else_if->Merge().target)) {
|
||||||
auto* f = If(else_if);
|
auto* f = If(else_if);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return b.If(cond, t, b.Else(f));
|
return b.If(cond, t, b.Else(f));
|
||||||
} else {
|
} else {
|
||||||
auto* f = FlowNodeGraph(i->false_.target, i->merge.target);
|
auto* f = FlowNodeGraph(i->False().target, i->Merge().target);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -221,16 +221,16 @@ class State {
|
|||||||
const ast::SwitchStatement* Switch(const ir::Switch* s) {
|
const ast::SwitchStatement* Switch(const ir::Switch* s) {
|
||||||
SCOPED_NESTING();
|
SCOPED_NESTING();
|
||||||
|
|
||||||
auto* cond = Expr(s->condition);
|
auto* cond = Expr(s->Condition());
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cases = utils::Transform(
|
auto cases = utils::Transform<1>(
|
||||||
s->cases, //
|
s->Cases(), //
|
||||||
[&](const ir::Switch::Case& c) -> const tint::ast::CaseStatement* {
|
[&](const ir::Switch::Case& c) -> const tint::ast::CaseStatement* {
|
||||||
SCOPED_NESTING();
|
SCOPED_NESTING();
|
||||||
auto* body = FlowNodeGraph(c.start.target, s->merge.target);
|
auto* body = FlowNodeGraph(c.start.target, s->Merge().target);
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -292,10 +292,10 @@ class State {
|
|||||||
bool IsEmpty(const ir::FlowNode* node, const ir::FlowNode* stop_at) {
|
bool IsEmpty(const ir::FlowNode* node, const ir::FlowNode* stop_at) {
|
||||||
while (node != stop_at) {
|
while (node != stop_at) {
|
||||||
if (auto* block = node->As<ir::Block>()) {
|
if (auto* block = node->As<ir::Block>()) {
|
||||||
if (block->instructions.Length() > 0) {
|
if (!block->Instructions().IsEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
node = block->branch.target;
|
node = block->Branch().target;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -307,13 +307,13 @@ class State {
|
|||||||
const ir::FlowNode* NextNonEmptyNode(const ir::FlowNode* node) {
|
const ir::FlowNode* NextNonEmptyNode(const ir::FlowNode* node) {
|
||||||
while (node) {
|
while (node) {
|
||||||
if (auto* block = node->As<ir::Block>()) {
|
if (auto* block = node->As<ir::Block>()) {
|
||||||
for (auto* inst : block->instructions) {
|
for (const auto* inst : block->Instructions()) {
|
||||||
// Load instructions will be inlined, so ignore them.
|
// Load instructions will be inlined, so ignore them.
|
||||||
if (!inst->Is<ir::Load>()) {
|
if (!inst->Is<ir::Load>()) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node = block->branch.target;
|
node = block->Branch().target;
|
||||||
} else {
|
} else {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -351,8 +351,8 @@ class State {
|
|||||||
}
|
}
|
||||||
auto ty = Type(ptr->StoreType());
|
auto ty = Type(ptr->StoreType());
|
||||||
const ast::Expression* init = nullptr;
|
const ast::Expression* init = nullptr;
|
||||||
if (var->initializer) {
|
if (var->Initializer()) {
|
||||||
init = Expr(var->initializer);
|
init = Expr(var->Initializer());
|
||||||
if (!init) {
|
if (!init) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -368,18 +368,19 @@ class State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ast::AssignmentStatement* Store(const ir::Store* store) {
|
const ast::AssignmentStatement* Store(const ir::Store* store) {
|
||||||
auto* expr = Expr(store->from);
|
auto* expr = Expr(store->From());
|
||||||
return b.Assign(NameOf(store->to), expr);
|
return b.Assign(NameOf(store->To()), expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ast::CallExpression* Call(const ir::Call* call) {
|
const ast::CallExpression* Call(const ir::Call* call) {
|
||||||
auto args = utils::Transform(call->args, [&](const ir::Value* arg) { return Expr(arg); });
|
auto args =
|
||||||
|
utils::Transform<2>(call->Args(), [&](const ir::Value* arg) { return Expr(arg); });
|
||||||
if (args.Any(utils::IsNull)) {
|
if (args.Any(utils::IsNull)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return tint::Switch(
|
return tint::Switch(
|
||||||
call, //
|
call, //
|
||||||
[&](const ir::UserCall* c) { return b.Call(Sym(c->name), std::move(args)); },
|
[&](const ir::UserCall* c) { return b.Call(Sym(c->Name()), std::move(args)); },
|
||||||
[&](Default) {
|
[&](Default) {
|
||||||
UNHANDLED_CASE(call);
|
UNHANDLED_CASE(call);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -401,18 +402,18 @@ class State {
|
|||||||
const ast::Expression* ConstExpr(const ir::Constant* c) {
|
const ast::Expression* ConstExpr(const ir::Constant* c) {
|
||||||
return tint::Switch(
|
return tint::Switch(
|
||||||
c->Type(), //
|
c->Type(), //
|
||||||
[&](const type::I32*) { return b.Expr(c->value->ValueAs<i32>()); },
|
[&](const type::I32*) { return b.Expr(c->Value()->ValueAs<i32>()); },
|
||||||
[&](const type::U32*) { return b.Expr(c->value->ValueAs<u32>()); },
|
[&](const type::U32*) { return b.Expr(c->Value()->ValueAs<u32>()); },
|
||||||
[&](const type::F32*) { return b.Expr(c->value->ValueAs<f32>()); },
|
[&](const type::F32*) { return b.Expr(c->Value()->ValueAs<f32>()); },
|
||||||
[&](const type::F16*) { return b.Expr(c->value->ValueAs<f16>()); },
|
[&](const type::F16*) { return b.Expr(c->Value()->ValueAs<f16>()); },
|
||||||
[&](const type::Bool*) { return b.Expr(c->value->ValueAs<bool>()); },
|
[&](const type::Bool*) { return b.Expr(c->Value()->ValueAs<bool>()); },
|
||||||
[&](Default) {
|
[&](Default) {
|
||||||
UNHANDLED_CASE(c);
|
UNHANDLED_CASE(c);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const ast::Expression* LoadExpr(const ir::Load* l) { return Expr(l->from); }
|
const ast::Expression* LoadExpr(const ir::Load* l) { return Expr(l->From()); }
|
||||||
|
|
||||||
const ast::Expression* VarExpr(const ir::Var* v) { return b.Expr(NameOf(v)); }
|
const ast::Expression* VarExpr(const ir::Var* v) { return b.Expr(NameOf(v)); }
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ AddEmptyEntryPoint::~AddEmptyEntryPoint() = default;
|
|||||||
|
|
||||||
void AddEmptyEntryPoint::Run(ir::Module* ir, const DataMap&, DataMap&) const {
|
void AddEmptyEntryPoint::Run(ir::Module* ir, const DataMap&, DataMap&) const {
|
||||||
for (auto* func : ir->functions) {
|
for (auto* func : ir->functions) {
|
||||||
if (func->pipeline_stage != Function::PipelineStage::kUndefined) {
|
if (func->Stage() != Function::PipelineStage::kUndefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ void AddEmptyEntryPoint::Run(ir::Module* ir, const DataMap&, DataMap&) const {
|
|||||||
auto* ep =
|
auto* ep =
|
||||||
builder.CreateFunction(ir->symbols.New("unused_entry_point"), ir->types.Get<type::Void>(),
|
builder.CreateFunction(ir->symbols.New("unused_entry_point"), ir->types.Get<type::Void>(),
|
||||||
Function::PipelineStage::kCompute, std::array{1u, 1u, 1u});
|
Function::PipelineStage::kCompute, std::array{1u, 1u, 1u});
|
||||||
builder.Branch(ep->start_target, ep->end_target);
|
ep->StartTarget()->BranchTo(ep->EndTarget());
|
||||||
ir->functions.Push(ep);
|
ir->functions.Push(ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ TEST_F(IR_AddEmptyEntryPointTest, EmptyModule) {
|
|||||||
TEST_F(IR_AddEmptyEntryPointTest, ExistingEntryPoint) {
|
TEST_F(IR_AddEmptyEntryPointTest, ExistingEntryPoint) {
|
||||||
auto* ep = b.CreateFunction(mod.symbols.New("main"), mod.types.Get<type::Void>(),
|
auto* ep = b.CreateFunction(mod.symbols.New("main"), mod.types.Get<type::Void>(),
|
||||||
Function::PipelineStage::kFragment);
|
Function::PipelineStage::kFragment);
|
||||||
b.Branch(ep->start_target, ep->end_target);
|
ep->StartTarget()->BranchTo(ep->EndTarget());
|
||||||
mod.functions.Push(ep);
|
mod.functions.Push(ep);
|
||||||
|
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@ -19,8 +19,8 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Unary);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Unary::Unary(Kind k, const type::Type* res_ty, Value* val)
|
Unary::Unary(enum Kind k, const type::Type* res_ty, Value* val)
|
||||||
: kind(k), result_type(res_ty), val_(val) {
|
: kind_(k), result_type_(res_ty), val_(val) {
|
||||||
TINT_ASSERT(IR, val_);
|
TINT_ASSERT(IR, val_);
|
||||||
val_->AddUsage(this);
|
val_->AddUsage(this);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class Unary : public utils::Castable<Unary, Instruction> {
|
|||||||
/// @param kind the kind of unary instruction
|
/// @param kind the kind of unary instruction
|
||||||
/// @param result_type the result type
|
/// @param result_type the result type
|
||||||
/// @param val the input value for the instruction
|
/// @param val the input value for the instruction
|
||||||
Unary(Kind kind, const type::Type* result_type, Value* val);
|
Unary(enum Kind kind, const type::Type* result_type, Value* val);
|
||||||
Unary(const Unary& inst) = delete;
|
Unary(const Unary& inst) = delete;
|
||||||
Unary(Unary&& inst) = delete;
|
Unary(Unary&& inst) = delete;
|
||||||
~Unary() override;
|
~Unary() override;
|
||||||
@ -42,19 +42,18 @@ class Unary : public utils::Castable<Unary, Instruction> {
|
|||||||
Unary& operator=(Unary&& inst) = delete;
|
Unary& operator=(Unary&& inst) = delete;
|
||||||
|
|
||||||
/// @returns the type of the value
|
/// @returns the type of the value
|
||||||
const type::Type* Type() const override { return result_type; }
|
const type::Type* Type() const override { return result_type_; }
|
||||||
|
|
||||||
/// @returns the value for the instruction
|
/// @returns the value for the instruction
|
||||||
const Value* Val() const { return val_; }
|
const Value* Val() const { return val_; }
|
||||||
|
|
||||||
/// the kind of unary instruction
|
/// @returns the kind of unary instruction
|
||||||
Kind kind = Kind::kNegation;
|
enum Kind Kind() const { return kind_; }
|
||||||
|
|
||||||
/// the result type of the instruction
|
|
||||||
const type::Type* result_type = nullptr;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Value* val_ = nullptr;
|
enum Kind kind_;
|
||||||
|
const type::Type* result_type_;
|
||||||
|
Value* val_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -29,10 +29,10 @@ TEST_F(IR_InstructionTest, CreateComplement) {
|
|||||||
const auto* inst = b.Complement(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
const auto* inst = b.Complement(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Unary>());
|
ASSERT_TRUE(inst->Is<Unary>());
|
||||||
EXPECT_EQ(inst->kind, Unary::Kind::kComplement);
|
EXPECT_EQ(inst->Kind(), Unary::Kind::kComplement);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Val()->Is<Constant>());
|
ASSERT_TRUE(inst->Val()->Is<Constant>());
|
||||||
auto lhs = inst->Val()->As<Constant>()->value;
|
auto lhs = inst->Val()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -43,10 +43,10 @@ TEST_F(IR_InstructionTest, CreateNegation) {
|
|||||||
const auto* inst = b.Negation(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
const auto* inst = b.Negation(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Is<Unary>());
|
ASSERT_TRUE(inst->Is<Unary>());
|
||||||
EXPECT_EQ(inst->kind, Unary::Kind::kNegation);
|
EXPECT_EQ(inst->Kind(), Unary::Kind::kNegation);
|
||||||
|
|
||||||
ASSERT_TRUE(inst->Val()->Is<Constant>());
|
ASSERT_TRUE(inst->Val()->Is<Constant>());
|
||||||
auto lhs = inst->Val()->As<Constant>()->value;
|
auto lhs = inst->Val()->As<Constant>()->Value();
|
||||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ TEST_F(IR_InstructionTest, Unary_Usage) {
|
|||||||
Builder b{mod};
|
Builder b{mod};
|
||||||
const auto* inst = b.Negation(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
const auto* inst = b.Negation(b.ir.types.Get<type::I32>(), b.Constant(4_i));
|
||||||
|
|
||||||
EXPECT_EQ(inst->kind, Unary::Kind::kNegation);
|
EXPECT_EQ(inst->Kind(), Unary::Kind::kNegation);
|
||||||
|
|
||||||
ASSERT_NE(inst->Val(), nullptr);
|
ASSERT_NE(inst->Val(), nullptr);
|
||||||
ASSERT_EQ(inst->Val()->Usage().Length(), 1u);
|
ASSERT_EQ(inst->Val()->Usage().Length(), 1u);
|
||||||
|
@ -23,7 +23,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::UserCall);
|
|||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
UserCall::UserCall(const type::Type* ty, Symbol n, utils::VectorRef<Value*> arguments)
|
UserCall::UserCall(const type::Type* ty, Symbol n, utils::VectorRef<Value*> arguments)
|
||||||
: Base(ty, std::move(arguments)), name(n) {}
|
: Base(ty, std::move(arguments)), name_(n) {}
|
||||||
|
|
||||||
UserCall::~UserCall() = default;
|
UserCall::~UserCall() = default;
|
||||||
|
|
||||||
|
@ -36,8 +36,11 @@ class UserCall : public utils::Castable<UserCall, Call> {
|
|||||||
UserCall& operator=(const UserCall& inst) = delete;
|
UserCall& operator=(const UserCall& inst) = delete;
|
||||||
UserCall& operator=(UserCall&& inst) = delete;
|
UserCall& operator=(UserCall&& inst) = delete;
|
||||||
|
|
||||||
/// The function name
|
/// @returns the called function name
|
||||||
Symbol name;
|
Symbol Name() const { return name_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Symbol name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -19,8 +19,14 @@ TINT_INSTANTIATE_TYPEINFO(tint::ir::Var);
|
|||||||
|
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
|
||||||
Var::Var(const type::Type* ty) : type(ty) {}
|
Var::Var(const type::Type* ty) : type_(ty) {}
|
||||||
|
|
||||||
Var::~Var() = default;
|
Var::~Var() = default;
|
||||||
|
|
||||||
|
void Var::SetInitializer(Value* initializer) {
|
||||||
|
initializer_ = initializer;
|
||||||
|
initializer_->AddUsage(this);
|
||||||
|
// TODO(dsinclair): Probably should do a RemoveUsage on an existing initializer if set
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -36,13 +36,17 @@ class Var : public utils::Castable<Var, Instruction> {
|
|||||||
Var& operator=(Var&& inst) = delete;
|
Var& operator=(Var&& inst) = delete;
|
||||||
|
|
||||||
/// @returns the type of the var
|
/// @returns the type of the var
|
||||||
const type::Type* Type() const override { return type; }
|
const type::Type* Type() const override { return type_; }
|
||||||
|
|
||||||
/// the result type of the instruction
|
/// Sets the var initializer
|
||||||
const type::Type* type = nullptr;
|
/// @param initializer the initializer
|
||||||
|
void SetInitializer(Value* initializer);
|
||||||
|
/// @returns the initializer
|
||||||
|
const Value* Initializer() const { return initializer_; }
|
||||||
|
|
||||||
/// The optional initializer
|
private:
|
||||||
Value* initializer = nullptr;
|
const type::Type* type_;
|
||||||
|
Value* initializer_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
|
@ -52,7 +52,7 @@ class IR_AddFunction final : public ir::transform::Transform {
|
|||||||
ir::Builder builder(*mod);
|
ir::Builder builder(*mod);
|
||||||
auto* func =
|
auto* func =
|
||||||
builder.CreateFunction(mod->symbols.New("ir_func"), mod->types.Get<type::Void>());
|
builder.CreateFunction(mod->symbols.New("ir_func"), mod->types.Get<type::Void>());
|
||||||
builder.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
mod->functions.Push(func);
|
mod->functions.Push(func);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -70,7 +70,7 @@ ir::Module MakeIR() {
|
|||||||
ir::Builder builder(mod);
|
ir::Builder builder(mod);
|
||||||
auto* func =
|
auto* func =
|
||||||
builder.CreateFunction(builder.ir.symbols.New("main"), builder.ir.types.Get<type::Void>());
|
builder.CreateFunction(builder.ir.symbols.New("main"), builder.ir.types.Get<type::Void>());
|
||||||
builder.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
builder.ir.functions.Push(func);
|
builder.ir.functions.Push(func);
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
@ -102,9 +102,10 @@ TEST_F(TransformManagerTest, IR_MutateInPlace) {
|
|||||||
manager.Add<IR_AddFunction>();
|
manager.Add<IR_AddFunction>();
|
||||||
|
|
||||||
manager.Run(&ir, {}, outputs);
|
manager.Run(&ir, {}, outputs);
|
||||||
|
|
||||||
ASSERT_EQ(ir.functions.Length(), 2u);
|
ASSERT_EQ(ir.functions.Length(), 2u);
|
||||||
EXPECT_EQ(ir.functions[0]->name.Name(), "main");
|
EXPECT_EQ(ir.functions[0]->Name().Name(), "main");
|
||||||
EXPECT_EQ(ir.functions[1]->name.Name(), "ir_func");
|
EXPECT_EQ(ir.functions[1]->Name().Name(), "ir_func");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TransformManagerTest, AST_MixedTransforms_AST_Before_IR) {
|
TEST_F(TransformManagerTest, AST_MixedTransforms_AST_Before_IR) {
|
||||||
@ -149,9 +150,9 @@ TEST_F(TransformManagerTest, IR_MixedTransforms_AST_Before_IR) {
|
|||||||
|
|
||||||
manager.Run(&ir, {}, outputs);
|
manager.Run(&ir, {}, outputs);
|
||||||
ASSERT_EQ(ir.functions.Length(), 3u);
|
ASSERT_EQ(ir.functions.Length(), 3u);
|
||||||
EXPECT_EQ(ir.functions[0]->name.Name(), "ast_func");
|
EXPECT_EQ(ir.functions[0]->Name().Name(), "ast_func");
|
||||||
EXPECT_EQ(ir.functions[1]->name.Name(), "main");
|
EXPECT_EQ(ir.functions[1]->Name().Name(), "main");
|
||||||
EXPECT_EQ(ir.functions[2]->name.Name(), "ir_func");
|
EXPECT_EQ(ir.functions[2]->Name().Name(), "ir_func");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TransformManagerTest, IR_MixedTransforms_IR_Before_AST) {
|
TEST_F(TransformManagerTest, IR_MixedTransforms_IR_Before_AST) {
|
||||||
@ -164,9 +165,9 @@ TEST_F(TransformManagerTest, IR_MixedTransforms_IR_Before_AST) {
|
|||||||
|
|
||||||
manager.Run(&ir, {}, outputs);
|
manager.Run(&ir, {}, outputs);
|
||||||
ASSERT_EQ(ir.functions.Length(), 3u);
|
ASSERT_EQ(ir.functions.Length(), 3u);
|
||||||
EXPECT_EQ(ir.functions[0]->name.Name(), "ast_func");
|
EXPECT_EQ(ir.functions[0]->Name().Name(), "ast_func");
|
||||||
EXPECT_EQ(ir.functions[1]->name.Name(), "main");
|
EXPECT_EQ(ir.functions[1]->Name().Name(), "main");
|
||||||
EXPECT_EQ(ir.functions[2]->name.Name(), "ir_func");
|
EXPECT_EQ(ir.functions[2]->Name().Name(), "ir_func");
|
||||||
}
|
}
|
||||||
#endif // TINT_BUILD_IR
|
#endif // TINT_BUILD_IR
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ bool GeneratorImplIr::Generate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GeneratorImplIr::Constant(const ir::Constant* constant) {
|
uint32_t GeneratorImplIr::Constant(const ir::Constant* constant) {
|
||||||
return Constant(constant->value);
|
return Constant(constant->Value());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GeneratorImplIr::Constant(const constant::Value* constant) {
|
uint32_t GeneratorImplIr::Constant(const constant::Value* constant) {
|
||||||
@ -214,15 +214,15 @@ void GeneratorImplIr::EmitFunction(const ir::Function* func) {
|
|||||||
auto id = module_.NextId();
|
auto id = module_.NextId();
|
||||||
|
|
||||||
// Emit the function name.
|
// Emit the function name.
|
||||||
module_.PushDebug(spv::Op::OpName, {id, Operand(func->name.Name())});
|
module_.PushDebug(spv::Op::OpName, {id, Operand(func->Name().Name())});
|
||||||
|
|
||||||
// Emit OpEntryPoint and OpExecutionMode declarations if needed.
|
// Emit OpEntryPoint and OpExecutionMode declarations if needed.
|
||||||
if (func->pipeline_stage != ir::Function::PipelineStage::kUndefined) {
|
if (func->Stage() != ir::Function::PipelineStage::kUndefined) {
|
||||||
EmitEntryPoint(func, id);
|
EmitEntryPoint(func, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the ID for the return type.
|
// Get the ID for the return type.
|
||||||
auto return_type_id = Type(func->return_type);
|
auto return_type_id = Type(func->ReturnType());
|
||||||
|
|
||||||
// Get the ID for the function type (creating it if needed).
|
// Get the ID for the function type (creating it if needed).
|
||||||
// TODO(jrprice): Add the parameter types when they are supported in the IR.
|
// TODO(jrprice): Add the parameter types when they are supported in the IR.
|
||||||
@ -248,7 +248,7 @@ void GeneratorImplIr::EmitFunction(const ir::Function* func) {
|
|||||||
TINT_DEFER(current_function_ = Function());
|
TINT_DEFER(current_function_ = Function());
|
||||||
|
|
||||||
// Emit the body of the function.
|
// Emit the body of the function.
|
||||||
EmitBlock(func->start_target);
|
EmitBlock(func->StartTarget());
|
||||||
|
|
||||||
// Add the function to the module.
|
// Add the function to the module.
|
||||||
module_.PushFunction(current_function_);
|
module_.PushFunction(current_function_);
|
||||||
@ -256,13 +256,13 @@ void GeneratorImplIr::EmitFunction(const ir::Function* func) {
|
|||||||
|
|
||||||
void GeneratorImplIr::EmitEntryPoint(const ir::Function* func, uint32_t id) {
|
void GeneratorImplIr::EmitEntryPoint(const ir::Function* func, uint32_t id) {
|
||||||
SpvExecutionModel stage = SpvExecutionModelMax;
|
SpvExecutionModel stage = SpvExecutionModelMax;
|
||||||
switch (func->pipeline_stage) {
|
switch (func->Stage()) {
|
||||||
case ir::Function::PipelineStage::kCompute: {
|
case ir::Function::PipelineStage::kCompute: {
|
||||||
stage = SpvExecutionModelGLCompute;
|
stage = SpvExecutionModelGLCompute;
|
||||||
module_.PushExecutionMode(
|
module_.PushExecutionMode(
|
||||||
spv::Op::OpExecutionMode,
|
spv::Op::OpExecutionMode,
|
||||||
{id, U32Operand(SpvExecutionModeLocalSize), func->workgroup_size->at(0),
|
{id, U32Operand(SpvExecutionModeLocalSize), func->WorkgroupSize()->at(0),
|
||||||
func->workgroup_size->at(1), func->workgroup_size->at(2)});
|
func->WorkgroupSize()->at(1), func->WorkgroupSize()->at(2)});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ir::Function::PipelineStage::kFragment: {
|
case ir::Function::PipelineStage::kFragment: {
|
||||||
@ -282,7 +282,7 @@ void GeneratorImplIr::EmitEntryPoint(const ir::Function* func, uint32_t id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jrprice): Add the interface list of all referenced global variables.
|
// TODO(jrprice): Add the interface list of all referenced global variables.
|
||||||
module_.PushEntryPoint(spv::Op::OpEntryPoint, {U32Operand(stage), id, func->name.Name()});
|
module_.PushEntryPoint(spv::Op::OpEntryPoint, {U32Operand(stage), id, func->Name().Name()});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneratorImplIr::EmitBlock(const ir::Block* block) {
|
void GeneratorImplIr::EmitBlock(const ir::Block* block) {
|
||||||
@ -293,7 +293,7 @@ void GeneratorImplIr::EmitBlock(const ir::Block* block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Emit the instructions.
|
// Emit the instructions.
|
||||||
for (auto* inst : block->instructions) {
|
for (const auto* inst : block->Instructions()) {
|
||||||
auto result = Switch(
|
auto result = Switch(
|
||||||
inst, //
|
inst, //
|
||||||
[&](const ir::Binary* b) { return EmitBinary(b); },
|
[&](const ir::Binary* b) { return EmitBinary(b); },
|
||||||
@ -313,43 +313,43 @@ void GeneratorImplIr::EmitBlock(const ir::Block* block) {
|
|||||||
|
|
||||||
// Handle the branch at the end of the block.
|
// Handle the branch at the end of the block.
|
||||||
Switch(
|
Switch(
|
||||||
block->branch.target,
|
block->Branch().target,
|
||||||
[&](const ir::Block* b) { current_function_.push_inst(spv::Op::OpBranch, {Label(b)}); },
|
[&](const ir::Block* b) { current_function_.push_inst(spv::Op::OpBranch, {Label(b)}); },
|
||||||
[&](const ir::If* i) { EmitIf(i); },
|
[&](const ir::If* i) { EmitIf(i); },
|
||||||
[&](const ir::FunctionTerminator*) {
|
[&](const ir::FunctionTerminator*) {
|
||||||
// TODO(jrprice): Handle the return value, which will be a branch argument.
|
// TODO(jrprice): Handle the return value, which will be a branch argument.
|
||||||
if (!block->branch.args.IsEmpty()) {
|
if (!block->Branch().args.IsEmpty()) {
|
||||||
TINT_ICE(Writer, diagnostics_) << "unimplemented return value";
|
TINT_ICE(Writer, diagnostics_) << "unimplemented return value";
|
||||||
}
|
}
|
||||||
current_function_.push_inst(spv::Op::OpReturn, {});
|
current_function_.push_inst(spv::Op::OpReturn, {});
|
||||||
},
|
},
|
||||||
[&](Default) {
|
[&](Default) {
|
||||||
if (!block->branch.target) {
|
if (!block->Branch().target) {
|
||||||
// A block may not have an outward branch (e.g. an unreachable merge block).
|
// A block may not have an outward branch (e.g. an unreachable merge block).
|
||||||
current_function_.push_inst(spv::Op::OpUnreachable, {});
|
current_function_.push_inst(spv::Op::OpUnreachable, {});
|
||||||
} else {
|
} else {
|
||||||
TINT_ICE(Writer, diagnostics_)
|
TINT_ICE(Writer, diagnostics_)
|
||||||
<< "unimplemented branch target: " << block->branch.target->TypeInfo().name;
|
<< "unimplemented branch target: " << block->Branch().target->TypeInfo().name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneratorImplIr::EmitIf(const ir::If* i) {
|
void GeneratorImplIr::EmitIf(const ir::If* i) {
|
||||||
auto* merge_block = i->merge.target->As<ir::Block>();
|
auto* merge_block = i->Merge().target->As<ir::Block>();
|
||||||
auto* true_block = i->true_.target->As<ir::Block>();
|
auto* true_block = i->True().target->As<ir::Block>();
|
||||||
auto* false_block = i->false_.target->As<ir::Block>();
|
auto* false_block = i->False().target->As<ir::Block>();
|
||||||
|
|
||||||
// Generate labels for the blocks. We emit the true or false block if it:
|
// Generate labels for the blocks. We emit the true or false block if it:
|
||||||
// 1. contains instructions, or
|
// 1. contains instructions, or
|
||||||
// 2. branches somewhere other then the merge target.
|
// 2. branches somewhere other then the Merge().target.
|
||||||
// Otherwise we skip them and branch straight to the merge block.
|
// Otherwise we skip them and branch straight to the merge block.
|
||||||
uint32_t merge_label = Label(merge_block);
|
uint32_t merge_label = Label(merge_block);
|
||||||
uint32_t true_label = merge_label;
|
uint32_t true_label = merge_label;
|
||||||
uint32_t false_label = merge_label;
|
uint32_t false_label = merge_label;
|
||||||
if (!true_block->instructions.IsEmpty() || true_block->branch.target != merge_block) {
|
if (!true_block->Instructions().IsEmpty() || true_block->Branch().target != merge_block) {
|
||||||
true_label = Label(true_block);
|
true_label = Label(true_block);
|
||||||
}
|
}
|
||||||
if (!false_block->instructions.IsEmpty() || false_block->branch.target != merge_block) {
|
if (!false_block->Instructions().IsEmpty() || false_block->Branch().target != merge_block) {
|
||||||
false_label = Label(false_block);
|
false_label = Label(false_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ void GeneratorImplIr::EmitIf(const ir::If* i) {
|
|||||||
current_function_.push_inst(spv::Op::OpSelectionMerge,
|
current_function_.push_inst(spv::Op::OpSelectionMerge,
|
||||||
{merge_label, U32Operand(SpvSelectionControlMaskNone)});
|
{merge_label, U32Operand(SpvSelectionControlMaskNone)});
|
||||||
current_function_.push_inst(spv::Op::OpBranchConditional,
|
current_function_.push_inst(spv::Op::OpBranchConditional,
|
||||||
{Value(i->condition), true_label, false_label});
|
{Value(i->Condition()), true_label, false_label});
|
||||||
|
|
||||||
// Emit the `true` and `false` blocks, if they're not being skipped.
|
// Emit the `true` and `false` blocks, if they're not being skipped.
|
||||||
if (true_label != merge_label) {
|
if (true_label != merge_label) {
|
||||||
@ -376,7 +376,7 @@ uint32_t GeneratorImplIr::EmitBinary(const ir::Binary* binary) {
|
|||||||
|
|
||||||
// Determine the opcode.
|
// Determine the opcode.
|
||||||
spv::Op op = spv::Op::Max;
|
spv::Op op = spv::Op::Max;
|
||||||
switch (binary->kind) {
|
switch (binary->Kind()) {
|
||||||
case ir::Binary::Kind::kAdd: {
|
case ir::Binary::Kind::kAdd: {
|
||||||
op = binary->Type()->is_integer_scalar_or_vector() ? spv::Op::OpIAdd : spv::Op::OpFAdd;
|
op = binary->Type()->is_integer_scalar_or_vector() ? spv::Op::OpIAdd : spv::Op::OpFAdd;
|
||||||
break;
|
break;
|
||||||
@ -387,7 +387,7 @@ uint32_t GeneratorImplIr::EmitBinary(const ir::Binary* binary) {
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
TINT_ICE(Writer, diagnostics_)
|
TINT_ICE(Writer, diagnostics_)
|
||||||
<< "unimplemented binary instruction: " << static_cast<uint32_t>(binary->kind);
|
<< "unimplemented binary instruction: " << static_cast<uint32_t>(binary->Kind());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,12 +400,12 @@ uint32_t GeneratorImplIr::EmitBinary(const ir::Binary* binary) {
|
|||||||
|
|
||||||
uint32_t GeneratorImplIr::EmitLoad(const ir::Load* load) {
|
uint32_t GeneratorImplIr::EmitLoad(const ir::Load* load) {
|
||||||
auto id = module_.NextId();
|
auto id = module_.NextId();
|
||||||
current_function_.push_inst(spv::Op::OpLoad, {Type(load->Type()), id, Value(load->from)});
|
current_function_.push_inst(spv::Op::OpLoad, {Type(load->Type()), id, Value(load->From())});
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneratorImplIr::EmitStore(const ir::Store* store) {
|
void GeneratorImplIr::EmitStore(const ir::Store* store) {
|
||||||
current_function_.push_inst(spv::Op::OpStore, {Value(store->to), Value(store->from)});
|
current_function_.push_inst(spv::Op::OpStore, {Value(store->To()), Value(store->From())});
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GeneratorImplIr::EmitVar(const ir::Var* var) {
|
uint32_t GeneratorImplIr::EmitVar(const ir::Var* var) {
|
||||||
@ -417,8 +417,8 @@ uint32_t GeneratorImplIr::EmitVar(const ir::Var* var) {
|
|||||||
if (ptr->AddressSpace() == builtin::AddressSpace::kFunction) {
|
if (ptr->AddressSpace() == builtin::AddressSpace::kFunction) {
|
||||||
TINT_ASSERT(Writer, current_function_);
|
TINT_ASSERT(Writer, current_function_);
|
||||||
current_function_.push_var({ty, id, U32Operand(SpvStorageClassFunction)});
|
current_function_.push_var({ty, id, U32Operand(SpvStorageClassFunction)});
|
||||||
if (var->initializer) {
|
if (var->Initializer()) {
|
||||||
current_function_.push_inst(spv::Op::OpStore, {id, Value(var->initializer)});
|
current_function_.push_inst(spv::Op::OpStore, {id, Value(var->Initializer())});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TINT_ICE(Writer, diagnostics_)
|
TINT_ICE(Writer, diagnostics_)
|
||||||
|
@ -21,10 +21,10 @@ namespace {
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Add_I32) {
|
TEST_F(SpvGeneratorImplTest, Binary_Add_I32) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i)));
|
utils::Vector{b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -43,10 +43,10 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Add_U32) {
|
TEST_F(SpvGeneratorImplTest, Binary_Add_U32) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Add(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u)));
|
utils::Vector{b.Add(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -65,10 +65,10 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Add_F32) {
|
TEST_F(SpvGeneratorImplTest, Binary_Add_F32) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Add(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f)));
|
utils::Vector{b.Add(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -87,10 +87,10 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Sub_I32) {
|
TEST_F(SpvGeneratorImplTest, Binary_Sub_I32) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Subtract(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i)));
|
utils::Vector{b.Subtract(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -109,10 +109,10 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Sub_U32) {
|
TEST_F(SpvGeneratorImplTest, Binary_Sub_U32) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Subtract(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u)));
|
utils::Vector{b.Subtract(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -131,10 +131,10 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Sub_F32) {
|
TEST_F(SpvGeneratorImplTest, Binary_Sub_F32) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Subtract(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f)));
|
utils::Vector{b.Subtract(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -153,17 +153,17 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Sub_Vec2i) {
|
TEST_F(SpvGeneratorImplTest, Binary_Sub_Vec2i) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* lhs = mod.constants_arena.Create<constant::Composite>(
|
auto* lhs = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u),
|
mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u),
|
||||||
utils::Vector{b.Constant(42_i)->value, b.Constant(-1_i)->value}, false, false);
|
utils::Vector{b.Constant(42_i)->Value(), b.Constant(-1_i)->Value()}, false, false);
|
||||||
auto* rhs = mod.constants_arena.Create<constant::Composite>(
|
auto* rhs = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u),
|
mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u),
|
||||||
utils::Vector{b.Constant(0_i)->value, b.Constant(-43_i)->value}, false, false);
|
utils::Vector{b.Constant(0_i)->Value(), b.Constant(-43_i)->Value()}, false, false);
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u), b.Constant(lhs),
|
utils::Vector{b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u),
|
||||||
b.Constant(rhs)));
|
b.Constant(lhs), b.Constant(rhs))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -187,21 +187,21 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Sub_Vec4f) {
|
TEST_F(SpvGeneratorImplTest, Binary_Sub_Vec4f) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* lhs = mod.constants_arena.Create<constant::Composite>(
|
auto* lhs = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u),
|
mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u),
|
||||||
utils::Vector{b.Constant(42_f)->value, b.Constant(-1_f)->value, b.Constant(0_f)->value,
|
utils::Vector{b.Constant(42_f)->Value(), b.Constant(-1_f)->Value(),
|
||||||
b.Constant(1.25_f)->value},
|
b.Constant(0_f)->Value(), b.Constant(1.25_f)->Value()},
|
||||||
false, false);
|
false, false);
|
||||||
auto* rhs = mod.constants_arena.Create<constant::Composite>(
|
auto* rhs = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u),
|
mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u),
|
||||||
utils::Vector{b.Constant(0_f)->value, b.Constant(1.25_f)->value, b.Constant(-42_f)->value,
|
utils::Vector{b.Constant(0_f)->Value(), b.Constant(1.25_f)->Value(),
|
||||||
b.Constant(1_f)->value},
|
b.Constant(-42_f)->Value(), b.Constant(1_f)->Value()},
|
||||||
false, false);
|
false, false);
|
||||||
func->start_target->instructions.Push(
|
func->StartTarget()->SetInstructions(
|
||||||
b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u), b.Constant(lhs),
|
utils::Vector{b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u),
|
||||||
b.Constant(rhs)));
|
b.Constant(lhs), b.Constant(rhs))});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -227,11 +227,10 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Binary_Chain) {
|
TEST_F(SpvGeneratorImplTest, Binary_Chain) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* a = b.Subtract(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i));
|
auto* a = b.Subtract(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i));
|
||||||
func->start_target->instructions.Push(a);
|
func->StartTarget()->SetInstructions(utils::Vector{a, b.Add(mod.types.Get<type::I32>(), a, a)});
|
||||||
func->start_target->instructions.Push(b.Add(mod.types.Get<type::I32>(), a, a));
|
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
|
@ -67,7 +67,7 @@ TEST_F(SpvGeneratorImplTest, Constant_Vec4Bool) {
|
|||||||
auto* f = b.Constant(false);
|
auto* f = b.Constant(false);
|
||||||
auto* v = mod.constants_arena.Create<constant::Composite>(
|
auto* v = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(mod.types.Get<type::Bool>(), 4u),
|
mod.types.Get<type::Vector>(mod.types.Get<type::Bool>(), 4u),
|
||||||
utils::Vector{t->value, f->value, f->value, t->value}, false, true);
|
utils::Vector{t->Value(), f->Value(), f->Value(), t->Value()}, false, true);
|
||||||
generator_.Constant(b.Constant(v));
|
generator_.Constant(b.Constant(v));
|
||||||
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeBool
|
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeBool
|
||||||
%2 = OpTypeVector %3 4
|
%2 = OpTypeVector %3 4
|
||||||
@ -82,7 +82,8 @@ TEST_F(SpvGeneratorImplTest, Constant_Vec2i) {
|
|||||||
auto* i_42 = b.Constant(i32(42));
|
auto* i_42 = b.Constant(i32(42));
|
||||||
auto* i_n1 = b.Constant(i32(-1));
|
auto* i_n1 = b.Constant(i32(-1));
|
||||||
auto* v = mod.constants_arena.Create<constant::Composite>(
|
auto* v = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(i, 2u), utils::Vector{i_42->value, i_n1->value}, false, false);
|
mod.types.Get<type::Vector>(i, 2u), utils::Vector{i_42->Value(), i_n1->Value()}, false,
|
||||||
|
false);
|
||||||
generator_.Constant(b.Constant(v));
|
generator_.Constant(b.Constant(v));
|
||||||
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeInt 32 1
|
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeInt 32 1
|
||||||
%2 = OpTypeVector %3 2
|
%2 = OpTypeVector %3 2
|
||||||
@ -98,8 +99,8 @@ TEST_F(SpvGeneratorImplTest, Constant_Vec3u) {
|
|||||||
auto* u_0 = b.Constant(u32(0));
|
auto* u_0 = b.Constant(u32(0));
|
||||||
auto* u_4b = b.Constant(u32(4000000000));
|
auto* u_4b = b.Constant(u32(4000000000));
|
||||||
auto* v = mod.constants_arena.Create<constant::Composite>(
|
auto* v = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(u, 3u), utils::Vector{u_42->value, u_0->value, u_4b->value},
|
mod.types.Get<type::Vector>(u, 3u),
|
||||||
false, true);
|
utils::Vector{u_42->Value(), u_0->Value(), u_4b->Value()}, false, true);
|
||||||
generator_.Constant(b.Constant(v));
|
generator_.Constant(b.Constant(v));
|
||||||
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeInt 32 0
|
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeInt 32 0
|
||||||
%2 = OpTypeVector %3 3
|
%2 = OpTypeVector %3 3
|
||||||
@ -118,7 +119,7 @@ TEST_F(SpvGeneratorImplTest, Constant_Vec4f) {
|
|||||||
auto* f_n1 = b.Constant(f32(-1));
|
auto* f_n1 = b.Constant(f32(-1));
|
||||||
auto* v = mod.constants_arena.Create<constant::Composite>(
|
auto* v = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(f, 4u),
|
mod.types.Get<type::Vector>(f, 4u),
|
||||||
utils::Vector{f_42->value, f_0->value, f_q->value, f_n1->value}, false, true);
|
utils::Vector{f_42->Value(), f_0->Value(), f_q->Value(), f_n1->Value()}, false, true);
|
||||||
generator_.Constant(b.Constant(v));
|
generator_.Constant(b.Constant(v));
|
||||||
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeFloat 32
|
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeFloat 32
|
||||||
%2 = OpTypeVector %3 4
|
%2 = OpTypeVector %3 4
|
||||||
@ -135,7 +136,8 @@ TEST_F(SpvGeneratorImplTest, Constant_Vec2h) {
|
|||||||
auto* h_42 = b.Constant(f16(42));
|
auto* h_42 = b.Constant(f16(42));
|
||||||
auto* h_q = b.Constant(f16(0.25));
|
auto* h_q = b.Constant(f16(0.25));
|
||||||
auto* v = mod.constants_arena.Create<constant::Composite>(
|
auto* v = mod.constants_arena.Create<constant::Composite>(
|
||||||
mod.types.Get<type::Vector>(h, 2u), utils::Vector{h_42->value, h_q->value}, false, false);
|
mod.types.Get<type::Vector>(h, 2u), utils::Vector{h_42->Value(), h_q->Value()}, false,
|
||||||
|
false);
|
||||||
generator_.Constant(b.Constant(v));
|
generator_.Constant(b.Constant(v));
|
||||||
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeFloat 16
|
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeFloat 16
|
||||||
%2 = OpTypeVector %3 2
|
%2 = OpTypeVector %3 2
|
||||||
|
@ -19,7 +19,7 @@ namespace {
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, Function_Empty) {
|
TEST_F(SpvGeneratorImplTest, Function_Empty) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -35,7 +35,7 @@ OpFunctionEnd
|
|||||||
// Test that we do not emit the same function type more than once.
|
// Test that we do not emit the same function type more than once.
|
||||||
TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) {
|
TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
@ -48,7 +48,7 @@ TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) {
|
|||||||
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Compute) {
|
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Compute) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
|
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
|
||||||
ir::Function::PipelineStage::kCompute, {{32, 4, 1}});
|
ir::Function::PipelineStage::kCompute, {{32, 4, 1}});
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint GLCompute %1 "main"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint GLCompute %1 "main"
|
||||||
@ -66,7 +66,7 @@ OpFunctionEnd
|
|||||||
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Fragment) {
|
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Fragment) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
|
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
|
||||||
ir::Function::PipelineStage::kFragment);
|
ir::Function::PipelineStage::kFragment);
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Fragment %1 "main"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Fragment %1 "main"
|
||||||
@ -84,7 +84,7 @@ OpFunctionEnd
|
|||||||
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Vertex) {
|
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Vertex) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
|
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
|
||||||
ir::Function::PipelineStage::kVertex);
|
ir::Function::PipelineStage::kVertex);
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Vertex %1 "main"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Vertex %1 "main"
|
||||||
@ -101,15 +101,15 @@ OpFunctionEnd
|
|||||||
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Multiple) {
|
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Multiple) {
|
||||||
auto* f1 = b.CreateFunction(mod.symbols.Register("main1"), mod.types.Get<type::Void>(),
|
auto* f1 = b.CreateFunction(mod.symbols.Register("main1"), mod.types.Get<type::Void>(),
|
||||||
ir::Function::PipelineStage::kCompute, {{32, 4, 1}});
|
ir::Function::PipelineStage::kCompute, {{32, 4, 1}});
|
||||||
b.Branch(f1->start_target, f1->end_target);
|
f1->StartTarget()->BranchTo(f1->EndTarget());
|
||||||
|
|
||||||
auto* f2 = b.CreateFunction(mod.symbols.Register("main2"), mod.types.Get<type::Void>(),
|
auto* f2 = b.CreateFunction(mod.symbols.Register("main2"), mod.types.Get<type::Void>(),
|
||||||
ir::Function::PipelineStage::kCompute, {{8, 2, 16}});
|
ir::Function::PipelineStage::kCompute, {{8, 2, 16}});
|
||||||
b.Branch(f2->start_target, f2->end_target);
|
f2->StartTarget()->BranchTo(f2->EndTarget());
|
||||||
|
|
||||||
auto* f3 = b.CreateFunction(mod.symbols.Register("main3"), mod.types.Get<type::Void>(),
|
auto* f3 = b.CreateFunction(mod.symbols.Register("main3"), mod.types.Get<type::Void>(),
|
||||||
ir::Function::PipelineStage::kFragment);
|
ir::Function::PipelineStage::kFragment);
|
||||||
b.Branch(f3->start_target, f3->end_target);
|
f3->StartTarget()->BranchTo(f3->EndTarget());
|
||||||
|
|
||||||
generator_.EmitFunction(f1);
|
generator_.EmitFunction(f1);
|
||||||
generator_.EmitFunction(f2);
|
generator_.EmitFunction(f2);
|
||||||
|
@ -23,11 +23,11 @@ TEST_F(SpvGeneratorImplTest, If_TrueEmpty_FalseEmpty) {
|
|||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
|
|
||||||
auto* i = b.CreateIf(b.Constant(true));
|
auto* i = b.CreateIf(b.Constant(true));
|
||||||
b.Branch(i->true_.target->As<ir::Block>(), i->merge.target);
|
i->True().target->As<ir::Block>()->BranchTo(i->Merge().target);
|
||||||
b.Branch(i->false_.target->As<ir::Block>(), i->merge.target);
|
i->False().target->As<ir::Block>()->BranchTo(i->Merge().target);
|
||||||
b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
|
i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
b.Branch(func->start_target, i);
|
func->StartTarget()->BranchTo(i);
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -49,15 +49,15 @@ TEST_F(SpvGeneratorImplTest, If_FalseEmpty) {
|
|||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
|
|
||||||
auto* i = b.CreateIf(b.Constant(true));
|
auto* i = b.CreateIf(b.Constant(true));
|
||||||
b.Branch(i->false_.target->As<ir::Block>(), i->merge.target);
|
i->False().target->As<ir::Block>()->BranchTo(i->Merge().target);
|
||||||
b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
|
i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* true_block = i->true_.target->As<ir::Block>();
|
auto* true_block = i->True().target->As<ir::Block>();
|
||||||
true_block->instructions.Push(
|
true_block->SetInstructions(
|
||||||
b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i)));
|
utils::Vector{b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i))});
|
||||||
b.Branch(true_block, i->merge.target);
|
true_block->BranchTo(i->Merge().target);
|
||||||
|
|
||||||
b.Branch(func->start_target, i);
|
func->StartTarget()->BranchTo(i);
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -84,15 +84,15 @@ TEST_F(SpvGeneratorImplTest, If_TrueEmpty) {
|
|||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
|
|
||||||
auto* i = b.CreateIf(b.Constant(true));
|
auto* i = b.CreateIf(b.Constant(true));
|
||||||
b.Branch(i->true_.target->As<ir::Block>(), i->merge.target);
|
i->True().target->As<ir::Block>()->BranchTo(i->Merge().target);
|
||||||
b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
|
i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* false_block = i->false_.target->As<ir::Block>();
|
auto* false_block = i->False().target->As<ir::Block>();
|
||||||
false_block->instructions.Push(
|
false_block->SetInstructions(
|
||||||
b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i)));
|
utils::Vector{b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i))});
|
||||||
b.Branch(false_block, i->merge.target);
|
false_block->BranchTo(i->Merge().target);
|
||||||
|
|
||||||
b.Branch(func->start_target, i);
|
func->StartTarget()->BranchTo(i);
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -119,11 +119,11 @@ TEST_F(SpvGeneratorImplTest, If_BothBranchesReturn) {
|
|||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
|
|
||||||
auto* i = b.CreateIf(b.Constant(true));
|
auto* i = b.CreateIf(b.Constant(true));
|
||||||
b.Branch(i->true_.target->As<ir::Block>(), func->end_target);
|
i->True().target->As<ir::Block>()->BranchTo(func->EndTarget());
|
||||||
b.Branch(i->false_.target->As<ir::Block>(), func->end_target);
|
i->False().target->As<ir::Block>()->BranchTo(func->EndTarget());
|
||||||
i->merge.target->As<ir::Block>()->branch.target = nullptr;
|
i->Merge().target->As<ir::Block>()->BranchTo(nullptr);
|
||||||
|
|
||||||
b.Branch(func->start_target, i);
|
func->StartTarget()->BranchTo(i);
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
|
@ -22,12 +22,11 @@ namespace {
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, FunctionVar_NoInit) {
|
TEST_F(SpvGeneratorImplTest, FunctionVar_NoInit) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* ty = mod.types.Get<type::Pointer>(
|
auto* ty = mod.types.Get<type::Pointer>(
|
||||||
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
||||||
auto* v = b.Declare(ty);
|
func->StartTarget()->SetInstructions(utils::Vector{b.Declare(ty)});
|
||||||
func->start_target->instructions.Push(v);
|
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -45,13 +44,14 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, FunctionVar_WithInit) {
|
TEST_F(SpvGeneratorImplTest, FunctionVar_WithInit) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* ty = mod.types.Get<type::Pointer>(
|
auto* ty = mod.types.Get<type::Pointer>(
|
||||||
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
||||||
auto* v = b.Declare(ty);
|
auto* v = b.Declare(ty);
|
||||||
func->start_target->instructions.Push(v);
|
v->SetInitializer(b.Constant(42_i));
|
||||||
v->initializer = b.Constant(42_i);
|
|
||||||
|
func->StartTarget()->SetInstructions(utils::Vector{v});
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -71,12 +71,12 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, FunctionVar_Name) {
|
TEST_F(SpvGeneratorImplTest, FunctionVar_Name) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* ty = mod.types.Get<type::Pointer>(
|
auto* ty = mod.types.Get<type::Pointer>(
|
||||||
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
||||||
auto* v = b.Declare(ty);
|
auto* v = b.Declare(ty);
|
||||||
func->start_target->instructions.Push(v);
|
func->StartTarget()->SetInstructions(utils::Vector{v});
|
||||||
mod.SetName(v, "myvar");
|
mod.SetName(v, "myvar");
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
@ -96,22 +96,22 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, FunctionVar_DeclInsideBlock) {
|
TEST_F(SpvGeneratorImplTest, FunctionVar_DeclInsideBlock) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* ty = mod.types.Get<type::Pointer>(
|
auto* ty = mod.types.Get<type::Pointer>(
|
||||||
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
||||||
auto* v = b.Declare(ty);
|
auto* v = b.Declare(ty);
|
||||||
v->initializer = b.Constant(42_i);
|
v->SetInitializer(b.Constant(42_i));
|
||||||
|
|
||||||
auto* i = b.CreateIf(b.Constant(true));
|
auto* i = b.CreateIf(b.Constant(true));
|
||||||
b.Branch(i->false_.target->As<ir::Block>(), func->end_target);
|
i->False().target->As<ir::Block>()->BranchTo(func->EndTarget());
|
||||||
b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
|
i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* true_block = i->true_.target->As<ir::Block>();
|
auto* true_block = i->True().target->As<ir::Block>();
|
||||||
true_block->instructions.Push(v);
|
true_block->SetInstructions(utils::Vector{v});
|
||||||
b.Branch(true_block, i->merge.target);
|
true_block->BranchTo(i->Merge().target);
|
||||||
|
|
||||||
b.Branch(func->start_target, i);
|
func->StartTarget()->BranchTo(i);
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -140,14 +140,13 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, FunctionVar_Load) {
|
TEST_F(SpvGeneratorImplTest, FunctionVar_Load) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* store_ty = mod.types.Get<type::I32>();
|
auto* store_ty = mod.types.Get<type::I32>();
|
||||||
auto* ty = mod.types.Get<type::Pointer>(store_ty, builtin::AddressSpace::kFunction,
|
auto* ty = mod.types.Get<type::Pointer>(store_ty, builtin::AddressSpace::kFunction,
|
||||||
builtin::Access::kReadWrite);
|
builtin::Access::kReadWrite);
|
||||||
auto* v = b.Declare(ty);
|
auto* v = b.Declare(ty);
|
||||||
func->start_target->instructions.Push(v);
|
func->StartTarget()->SetInstructions(utils::Vector{v, b.Load(v)});
|
||||||
func->start_target->instructions.Push(b.Load(v));
|
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
@ -166,13 +165,12 @@ OpFunctionEnd
|
|||||||
|
|
||||||
TEST_F(SpvGeneratorImplTest, FunctionVar_Store) {
|
TEST_F(SpvGeneratorImplTest, FunctionVar_Store) {
|
||||||
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
|
||||||
b.Branch(func->start_target, func->end_target);
|
func->StartTarget()->BranchTo(func->EndTarget());
|
||||||
|
|
||||||
auto* ty = mod.types.Get<type::Pointer>(
|
auto* ty = mod.types.Get<type::Pointer>(
|
||||||
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
|
||||||
auto* v = b.Declare(ty);
|
auto* v = b.Declare(ty);
|
||||||
func->start_target->instructions.Push(v);
|
func->StartTarget()->SetInstructions(utils::Vector{v, b.Store(v, b.Constant(42_i))});
|
||||||
func->start_target->instructions.Push(b.Store(v, b.Constant(42_i)));
|
|
||||||
|
|
||||||
generator_.EmitFunction(func);
|
generator_.EmitFunction(func);
|
||||||
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user