Import Tint changes from Dawn
Changes:
- 24cb81116d30d0eee37ed5897c5a65df4baf31a0 [ir] Shift back to accessors. by dan sinclair <dsinclair@chromium.org>
- 97744832bc6e24eead7416d26f35c6ee9320981a [ir] Deduplicate constants by dan sinclair <dsinclair@chromium.org>
- 92151b238b7a3c71ae5e27f9eaa769b618b3f6ac [ir][spirv-writer] Emit load instructions by James Price <jrprice@google.com>
- 84d750e9823a70aee01d40b19eb0d4a92ecaa40d [ir] Add function parameters. by dan sinclair <dsinclair@chromium.org>
GitOrigin-RevId: 24cb81116d30d0eee37ed5897c5a65df4baf31a0
Change-Id: I7607901715e20e152804c5ef21101760636346c3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/133680
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 47efd52..64fde4c 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -1226,6 +1226,8 @@
"ir/flow_node.h",
"ir/function.cc",
"ir/function.h",
+ "ir/function_param.cc",
+ "ir/function_param.h",
"ir/function_terminator.cc",
"ir/function_terminator.h",
"ir/if.cc",
@@ -2263,6 +2265,7 @@
"ir/store_test.cc",
"ir/test_helper.h",
"ir/to_program_roundtrip_test.cc",
+ "ir/transform/add_empty_entry_point_test.cc",
"ir/unary_test.cc",
]
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index d0c7487..8ec573a 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -742,6 +742,8 @@
ir/flow_node.h
ir/function.cc
ir/function.h
+ ir/function_param.cc
+ ir/function_param.h
ir/function_terminator.cc
ir/function_terminator.h
ir/if.cc
@@ -1474,6 +1476,7 @@
ir/module_test.cc
ir/store_test.cc
ir/test_helper.h
+ ir/transform/add_empty_entry_point_test.cc
ir/unary_test.cc
)
endif()
diff --git a/src/tint/ir/binary.cc b/src/tint/ir/binary.cc
index af28306..2b179ac 100644
--- a/src/tint/ir/binary.cc
+++ b/src/tint/ir/binary.cc
@@ -19,8 +19,8 @@
namespace tint::ir {
-Binary::Binary(Kind k, const type::Type* res_ty, Value* lhs, Value* rhs)
- : kind(k), result_type(res_ty), lhs_(lhs), rhs_(rhs) {
+Binary::Binary(enum Kind kind, const type::Type* res_ty, Value* lhs, Value* rhs)
+ : kind_(kind), result_type_(res_ty), lhs_(lhs), rhs_(rhs) {
TINT_ASSERT(IR, lhs);
TINT_ASSERT(IR, rhs);
lhs_->AddUsage(this);
diff --git a/src/tint/ir/binary.h b/src/tint/ir/binary.h
index a6dc722..7ea6c08 100644
--- a/src/tint/ir/binary.h
+++ b/src/tint/ir/binary.h
@@ -51,7 +51,7 @@
/// @param type the result type
/// @param lhs the lhs 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(Binary&& inst) = delete;
~Binary() override;
@@ -59,8 +59,11 @@
Binary& operator=(const 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
- 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
const Value* LHS() const { return lhs_; }
@@ -68,15 +71,11 @@
/// @returns the right-hand-side value for the instruction
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:
- Value* lhs_ = nullptr;
- Value* rhs_ = nullptr;
+ enum Kind kind_;
+ const type::Type* result_type_;
+ Value* lhs_;
+ Value* rhs_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc
index 2968d28..dc35978 100644
--- a/src/tint/ir/binary_test.cc
+++ b/src/tint/ir/binary_test.cc
@@ -30,17 +30,16 @@
const auto* inst = b.And(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
ASSERT_TRUE(inst->Is<Binary>());
- EXPECT_EQ(inst->kind, Binary::Kind::kAnd);
- ASSERT_NE(inst->result_type, nullptr);
+ EXPECT_EQ(inst->Kind(), Binary::Kind::kAnd);
ASSERT_NE(inst->Type(), nullptr);
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>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -52,15 +51,15 @@
const auto* inst = b.Or(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -72,15 +71,15 @@
const auto* inst = b.Xor(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -92,15 +91,15 @@
const auto* inst = b.Equal(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -112,15 +111,15 @@
const auto* inst = b.NotEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -132,15 +131,15 @@
const auto* inst = b.LessThan(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -153,15 +152,15 @@
b.GreaterThan(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -174,15 +173,15 @@
b.LessThanEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -195,15 +194,15 @@
b.GreaterThanEqual(b.ir.types.Get<type::Bool>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -214,15 +213,15 @@
const auto* inst = b.Not(b.ir.types.Get<type::Bool>(), b.Constant(true));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<bool>>());
EXPECT_TRUE(lhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
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>>());
EXPECT_FALSE(rhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
}
@@ -234,15 +233,15 @@
const auto* inst = b.ShiftLeft(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -254,15 +253,15 @@
const auto* inst = b.ShiftRight(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -274,15 +273,15 @@
const auto* inst = b.Add(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -294,15 +293,15 @@
const auto* inst = b.Subtract(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -314,15 +313,15 @@
const auto* inst = b.Multiply(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -334,15 +333,15 @@
const auto* inst = b.Divide(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -354,15 +353,15 @@
const auto* inst = b.Modulo(b.ir.types.Get<type::I32>(), b.Constant(4_i), b.Constant(2_i));
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>());
- auto lhs = inst->LHS()->As<Constant>()->value;
+ auto lhs = inst->LHS()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
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>>());
EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -372,7 +371,7 @@
Builder b{mod};
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_EQ(inst->LHS()->Usage().Length(), 1u);
@@ -389,7 +388,7 @@
auto val = b.Constant(4_i);
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_NE(inst->LHS(), nullptr);
diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc
index e78b734..6eda562 100644
--- a/src/tint/ir/bitcast_test.cc
+++ b/src/tint/ir/bitcast_test.cc
@@ -32,9 +32,10 @@
ASSERT_TRUE(inst->Is<ir::Bitcast>());
ASSERT_NE(inst->Type(), nullptr);
- ASSERT_EQ(inst->args.Length(), 1u);
- ASSERT_TRUE(inst->args[0]->Is<Constant>());
- auto val = inst->args[0]->As<Constant>()->value;
+ const auto args = inst->Args();
+ ASSERT_EQ(args.Length(), 1u);
+ ASSERT_TRUE(args[0]->Is<Constant>());
+ auto val = args[0]->As<Constant>()->Value();
ASSERT_TRUE(val->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, val->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -44,10 +45,11 @@
Builder b{mod};
const auto* inst = b.Bitcast(b.ir.types.Get<type::I32>(), b.Constant(4_i));
- ASSERT_EQ(inst->args.Length(), 1u);
- ASSERT_NE(inst->args[0], nullptr);
- ASSERT_EQ(inst->args[0]->Usage().Length(), 1u);
- EXPECT_EQ(inst->args[0]->Usage()[0], inst);
+ const auto args = inst->Args();
+ ASSERT_EQ(args.Length(), 1u);
+ ASSERT_NE(args[0], nullptr);
+ ASSERT_EQ(args[0]->Usage().Length(), 1u);
+ EXPECT_EQ(args[0]->Usage()[0], inst);
}
} // namespace
diff --git a/src/tint/ir/block.cc b/src/tint/ir/block.cc
index 2030c19..f5b5bfb 100644
--- a/src/tint/ir/block.cc
+++ b/src/tint/ir/block.cc
@@ -22,4 +22,13 @@
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
diff --git a/src/tint/ir/block.h b/src/tint/ir/block.h
index 5af32fe..2b01fd0 100644
--- a/src/tint/ir/block.h
+++ b/src/tint/ir/block.h
@@ -15,6 +15,8 @@
#ifndef SRC_TINT_IR_BLOCK_H_
#define SRC_TINT_IR_BLOCK_H_
+#include <utility>
+
#include "src/tint/ir/block_param.h"
#include "src/tint/ir/branch.h"
#include "src/tint/ir/flow_node.h"
@@ -30,20 +32,48 @@
public:
/// Constructor
Block();
+ Block(const Block&) = delete;
+ Block(Block&&) = delete;
~Block() override;
- /// @returns true if this is a dead block. This can happen in the case like a loop merge block
- /// which is never reached.
- bool IsDead() const override { return branch.target == nullptr; }
+ Block& operator=(const Block&) = delete;
+ Block& operator=(Block&&) = delete;
- /// The node this block branches too.
- Branch branch = {};
+ /// Sets the blocks branch target to the given node.
+ /// @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
- utils::Vector<const Instruction*, 16> instructions;
+ /// @returns true if this is block has a branch target set
+ bool HasBranchTarget() const override { return branch_.target != nullptr; }
- /// The parameters passed into the block
- utils::Vector<const BlockParam*, 0> params;
+ /// @return the node this block branches too.
+ 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
diff --git a/src/tint/ir/block_param.cc b/src/tint/ir/block_param.cc
index f014d19..a3a0be5 100644
--- a/src/tint/ir/block_param.cc
+++ b/src/tint/ir/block_param.cc
@@ -18,7 +18,7 @@
namespace tint::ir {
-BlockParam::BlockParam(const type::Type* ty) : type(ty) {}
+BlockParam::BlockParam(const type::Type* ty) : type_(ty) {}
BlockParam::~BlockParam() = default;
diff --git a/src/tint/ir/block_param.h b/src/tint/ir/block_param.h
index 8ba68a7..036ddbf 100644
--- a/src/tint/ir/block_param.h
+++ b/src/tint/ir/block_param.h
@@ -34,10 +34,11 @@
BlockParam& operator=(BlockParam&& inst) = delete;
/// @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
- const type::Type* type = nullptr;
+ const type::Type* type_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc
index 983815e..b0b04d6 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -32,7 +32,7 @@
// 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.
- ir.root_block->branch.target = CreateRootTerminator();
+ ir.root_block->BranchTo(CreateRootTerminator());
}
return ir.root_block;
}
@@ -56,11 +56,11 @@
TINT_ASSERT(IR, return_type);
auto* ir_func = ir.flow_nodes.Create<Function>(name, return_type, stage, wg_size);
- ir_func->start_target = CreateBlock();
- ir_func->end_target = CreateFunctionTerminator();
+ ir_func->SetStartTarget(CreateBlock());
+ ir_func->SetEndTarget(CreateFunctionTerminator());
- // Function is always branching into the start target
- ir_func->start_target->inbound_branches.Push(ir_func);
+ // Function is always branching into the Start().target
+ ir_func->StartTarget()->AddInboundBranch(ir_func);
return ir_func;
}
@@ -69,53 +69,48 @@
TINT_ASSERT(IR, condition);
auto* ir_if = ir.flow_nodes.Create<If>(condition);
- ir_if->true_.target = CreateBlock();
- ir_if->false_.target = CreateBlock();
- ir_if->merge.target = CreateBlock();
+ ir_if->True().target = CreateBlock();
+ ir_if->False().target = CreateBlock();
+ ir_if->Merge().target = CreateBlock();
// An if always branches to both the true and false block.
- ir_if->true_.target->inbound_branches.Push(ir_if);
- ir_if->false_.target->inbound_branches.Push(ir_if);
+ ir_if->True().target->AddInboundBranch(ir_if);
+ ir_if->False().target->AddInboundBranch(ir_if);
return ir_if;
}
Loop* Builder::CreateLoop() {
auto* ir_loop = ir.flow_nodes.Create<Loop>();
- ir_loop->start.target = CreateBlock();
- ir_loop->continuing.target = CreateBlock();
- ir_loop->merge.target = CreateBlock();
+ ir_loop->Start().target = CreateBlock();
+ ir_loop->Continuing().target = CreateBlock();
+ ir_loop->Merge().target = CreateBlock();
// 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;
}
Switch* Builder::CreateSwitch(Value* condition) {
auto* ir_switch = ir.flow_nodes.Create<Switch>(condition);
- ir_switch->merge.target = CreateBlock();
+ ir_switch->Merge().target = CreateBlock();
return ir_switch;
}
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
- b->inbound_branches.Push(s);
+ b->AddInboundBranch(s);
return b;
}
-void Builder::Branch(Block* from, FlowNode* to, utils::VectorRef<Value*> args) {
- TINT_ASSERT(IR, from);
- TINT_ASSERT(IR, to);
- from->branch.target = to;
- from->branch.args = args;
- to->inbound_branches.Push(from);
-}
-
-Binary* Builder::CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs) {
+Binary* Builder::CreateBinary(enum Binary::Kind kind,
+ const type::Type* type,
+ Value* lhs,
+ Value* rhs) {
return ir.values.Create<ir::Binary>(kind, type, lhs, rhs);
}
@@ -183,7 +178,7 @@
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);
}
@@ -247,4 +242,8 @@
return ir.values.Create<ir::BlockParam>(type);
}
+ir::FunctionParam* Builder::FunctionParam(const type::Type* type) {
+ return ir.values.Create<ir::FunctionParam>(type);
+}
+
} // namespace tint::ir
diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h
index 7c0cab6..ebd7a87 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -20,12 +20,14 @@
#include "src/tint/constant/scalar.h"
#include "src/tint/ir/binary.h"
#include "src/tint/ir/bitcast.h"
+#include "src/tint/ir/block_param.h"
#include "src/tint/ir/builtin.h"
#include "src/tint/ir/constant.h"
#include "src/tint/ir/construct.h"
#include "src/tint/ir/convert.h"
#include "src/tint/ir/discard.h"
#include "src/tint/ir/function.h"
+#include "src/tint/ir/function_param.h"
#include "src/tint/ir/function_terminator.h"
#include "src/tint/ir/if.h"
#include "src/tint/ir/load.h"
@@ -96,26 +98,20 @@
/// @returns the start block for the case flow node
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
/// @param args the arguments
/// @returns the new constant value
template <typename T, typename... ARGS>
utils::traits::EnableIf<utils::traits::IsTypeOrDerived<T, constant::Value>, const T>* create(
ARGS&&... args) {
- return ir.constants.Create<T>(std::forward<ARGS>(args)...);
+ return ir.constants_arena.Create<T>(std::forward<ARGS>(args)...);
}
/// Creates a new ir::Constant
/// @param val the constant value
/// @returns the new constant
ir::Constant* Constant(const constant::Value* val) {
- return ir.values.Create<ir::Constant>(val);
+ return ir.constants.GetOrCreate(val, [&]() { return ir.values.Create<ir::Constant>(val); });
}
/// Creates a ir::Constant for an i32 Scalar
@@ -159,7 +155,7 @@
/// @param lhs the left-hand-side of the operation
/// @param rhs the right-hand-side of 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
/// @param type the result type of the expression
@@ -278,7 +274,7 @@
/// @param type the result type of the binary expression
/// @param val the value of 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
/// @param type the result type of the expression
@@ -360,6 +356,11 @@
/// @returns the value
ir::BlockParam* BlockParam(const type::Type* type);
+ /// Creates a new `FunctionParam`
+ /// @param type the parameter type
+ /// @returns the value
+ ir::FunctionParam* FunctionParam(const type::Type* type);
+
/// Retrieves the root block for the module, creating if necessary
/// @returns the root block
ir::Block* CreateRootBlockIfNeeded();
diff --git a/src/tint/ir/call.cc b/src/tint/ir/call.cc
index dd503ea..909079f 100644
--- a/src/tint/ir/call.cc
+++ b/src/tint/ir/call.cc
@@ -21,8 +21,8 @@
namespace tint::ir {
Call::Call(const type::Type* res_ty, utils::VectorRef<Value*> arguments)
- : result_type(res_ty), args(std::move(arguments)) {
- for (auto* arg : args) {
+ : result_type_(res_ty), args_(std::move(arguments)) {
+ for (auto* arg : args_) {
arg->AddUsage(this);
}
}
diff --git a/src/tint/ir/call.h b/src/tint/ir/call.h
index 5393810..f4e12f9 100644
--- a/src/tint/ir/call.h
+++ b/src/tint/ir/call.h
@@ -31,13 +31,10 @@
Call& operator=(Call&& inst) = delete;
/// @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
- const type::Type* result_type = nullptr;
-
- /// The constructor arguments
- utils::Vector<Value*, 1> args;
+ /// @returns the call arguments
+ utils::VectorRef<Value*> Args() const { return args_; }
protected:
/// Constructor
@@ -46,6 +43,10 @@
/// @param result_type the result type
/// @param args the constructor arguments
Call(const type::Type* result_type, utils::VectorRef<Value*> args);
+
+ private:
+ const type::Type* result_type_;
+ utils::Vector<Value*, 1> args_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/constant.cc b/src/tint/ir/constant.cc
index 8b5260c..a49d140 100644
--- a/src/tint/ir/constant.cc
+++ b/src/tint/ir/constant.cc
@@ -18,7 +18,7 @@
namespace tint::ir {
-Constant::Constant(const constant::Value* val) : value(val) {}
+Constant::Constant(const constant::Value* val) : value_(val) {}
Constant::~Constant() = default;
diff --git a/src/tint/ir/constant.h b/src/tint/ir/constant.h
index 68e0dc7..dcf3e5b 100644
--- a/src/tint/ir/constant.h
+++ b/src/tint/ir/constant.h
@@ -26,13 +26,21 @@
/// Constructor
/// @param val the value stored in the constant
explicit Constant(const constant::Value* val);
+ Constant(const Constant&) = delete;
+ Constant(Constant&&) = delete;
~Constant() override;
- /// @returns the type of the constant
- const type::Type* Type() const override { return value->Type(); }
+ Constant& operator=(const Constant&) = delete;
+ Constant& operator=(Constant&&) = delete;
- /// The constants value
- const constant::Value* const value;
+ /// @returns the constants 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
diff --git a/src/tint/ir/constant_test.cc b/src/tint/ir/constant_test.cc
index 7005751..7c3024a 100644
--- a/src/tint/ir/constant_test.cc
+++ b/src/tint/ir/constant_test.cc
@@ -30,13 +30,13 @@
utils::StringStream str;
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_FALSE(c->value->Is<constant::Scalar<f16>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
+ EXPECT_TRUE(c->Value()->Is<constant::Scalar<f32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
}
TEST_F(IR_ConstantTest, f16) {
@@ -46,13 +46,13 @@
utils::StringStream str;
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_TRUE(c->value->Is<constant::Scalar<f16>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
+ EXPECT_TRUE(c->Value()->Is<constant::Scalar<f16>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
}
TEST_F(IR_ConstantTest, i32) {
@@ -62,13 +62,13 @@
utils::StringStream str;
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<f16>>());
- EXPECT_TRUE(c->value->Is<constant::Scalar<i32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
+ EXPECT_TRUE(c->Value()->Is<constant::Scalar<i32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
}
TEST_F(IR_ConstantTest, u32) {
@@ -78,13 +78,13 @@
utils::StringStream str;
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<f16>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
- EXPECT_TRUE(c->value->Is<constant::Scalar<u32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
+ EXPECT_TRUE(c->Value()->Is<constant::Scalar<u32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<bool>>());
}
TEST_F(IR_ConstantTest, bool) {
@@ -95,19 +95,19 @@
utils::StringStream str;
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;
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<f16>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
- EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
- EXPECT_TRUE(c->value->Is<constant::Scalar<bool>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<f16>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<i32>>());
+ EXPECT_FALSE(c->Value()->Is<constant::Scalar<u32>>());
+ EXPECT_TRUE(c->Value()->Is<constant::Scalar<bool>>());
}
}
diff --git a/src/tint/ir/debug.cc b/src/tint/ir/debug.cc
index 655c455..85666ff 100644
--- a/src/tint/ir/debug.cc
+++ b/src/tint/ir/debug.cc
@@ -60,81 +60,81 @@
if (node_to_name.count(b) == 0) {
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
- if (merge_nodes.count(b->branch.target) != 0) {
+ if (merge_nodes.count(b->Branch().target) != 0) {
out << " [style=dashed]";
}
out << std::endl;
- Graph(b->branch.target);
+ Graph(b->Branch().target);
},
[&](const ir::Switch* s) {
out << name_for(s) << R"( [label="switch"])" << std::endl;
- out << name_for(s->merge.target) << R"( [label="switch merge"])" << std::endl;
- merge_nodes.insert(s->merge.target);
+ out << name_for(s->Merge().target) << R"( [label="switch merge"])" << std::endl;
+ merge_nodes.insert(s->Merge().target);
size_t i = 0;
- for (const auto& c : s->cases) {
- out << name_for(c.start.target)
+ for (const auto& c : s->Cases()) {
+ out << name_for(c.Start().target)
<< R"( [label="case )" + std::to_string(i++) + R"("])" << std::endl;
}
out << name_for(s) << " -> {";
- for (const auto& c : s->cases) {
- if (&c != &(s->cases[0])) {
+ for (const auto& c : s->Cases()) {
+ if (&c != &(s->Cases().Front())) {
out << ", ";
}
- out << name_for(c.start.target);
+ out << name_for(c.Start().target);
}
out << "}" << std::endl;
- for (const auto& c : s->cases) {
- Graph(c.start.target);
+ for (const auto& c : s->Cases()) {
+ Graph(c.Start().target);
}
- Graph(s->merge.target);
+ Graph(s->Merge().target);
},
[&](const ir::If* i) {
out << name_for(i) << R"( [label="if"])" << 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->merge.target) << R"( [label="if merge"])" << std::endl;
- merge_nodes.insert(i->merge.target);
+ 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->Merge().target) << R"( [label="if merge"])" << std::endl;
+ merge_nodes.insert(i->Merge().target);
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;
// Subgraph if true/false branches so they draw on the same line
out << "subgraph sub_" << name_for(i) << " {" << std::endl;
out << R"(rank="same")" << std::endl;
- out << name_for(i->true_.target) << std::endl;
- out << name_for(i->false_.target) << std::endl;
+ out << name_for(i->True().target) << std::endl;
+ out << name_for(i->False().target) << std::endl;
out << "}" << std::endl;
- Graph(i->true_.target);
- Graph(i->false_.target);
- Graph(i->merge.target);
+ Graph(i->True().target);
+ Graph(i->False().target);
+ Graph(i->Merge().target);
},
[&](const ir::Loop* l) {
out << name_for(l) << R"( [label="loop"])" << 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->merge.target) << R"( [label="loop merge"])" << std::endl;
- merge_nodes.insert(l->merge.target);
+ 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->Merge().target) << R"( [label="loop merge"])" << std::endl;
+ merge_nodes.insert(l->Merge().target);
// Subgraph the continuing and merge so they get drawn on the same line
out << "subgraph sub_" << name_for(l) << " {" << std::endl;
out << R"(rank="same")" << std::endl;
- out << name_for(l->continuing.target) << std::endl;
- out << name_for(l->merge.target) << std::endl;
+ out << name_for(l->Continuing().target) << std::endl;
+ out << name_for(l->Merge().target) << 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->continuing.target);
- Graph(l->merge.target);
+ Graph(l->Start().target);
+ Graph(l->Continuing().target);
+ Graph(l->Merge().target);
},
[&](const ir::FunctionTerminator*) {
// Already done
@@ -145,10 +145,10 @@
for (const auto* func : mod->functions) {
// Cluster each function to label and draw a box around it.
out << "subgraph cluster_" << name_for(func) << " {" << 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->end_target) << R"( [label="end"])" << std::endl;
- Graph(func->start_target);
+ out << R"(label=")" << func->Name().Name() << R"(")" << std::endl;
+ out << name_for(func->StartTarget()) << R"( [label="start"])" << std::endl;
+ out << name_for(func->EndTarget()) << R"( [label="end"])" << std::endl;
+ Graph(func->StartTarget());
out << "}" << std::endl;
}
out << "}";
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index f68b21a..76af740 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -81,7 +81,7 @@
}
void Disassembler::EmitBlockInstructions(const Block* b) {
- for (const auto* inst : b->instructions) {
+ for (const auto* inst : b->Instructions()) {
Indent();
EmitInstruction(inst);
out_ << std::endl;
@@ -114,25 +114,31 @@
[&](const ir::Function* f) {
TINT_SCOPED_ASSIGNMENT(in_function_, true);
- Indent() << "%fn" << IdOf(f) << " = func " << f->name.Name()
- << "():" << f->return_type->FriendlyName();
+ Indent() << "%fn" << IdOf(f) << " = func " << f->Name().Name() << "(";
+ for (auto* p : f->Params()) {
+ if (p != f->Params().Front()) {
+ out_ << ", ";
+ }
+ out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName();
+ }
+ out_ << "):" << f->ReturnType()->FriendlyName();
- if (f->pipeline_stage != Function::PipelineStage::kUndefined) {
- out_ << " [@" << f->pipeline_stage;
+ if (f->Stage() != Function::PipelineStage::kUndefined) {
+ out_ << " [@" << f->Stage();
- if (f->workgroup_size) {
- auto arr = f->workgroup_size.value();
+ if (f->WorkgroupSize()) {
+ auto arr = f->WorkgroupSize().value();
out_ << " @workgroup_size(" << arr[0] << ", " << arr[1] << ", " << arr[2]
<< ")";
}
- if (!f->return_attributes.IsEmpty()) {
+ if (!f->ReturnAttributes().IsEmpty()) {
out_ << " ra:";
- for (auto attr : f->return_attributes) {
+ for (auto attr : f->ReturnAttributes()) {
out_ << " @" << attr;
if (attr == Function::ReturnAttribute::kLocation) {
- out_ << "(" << f->return_location.value() << ")";
+ out_ << "(" << f->ReturnLocation().value() << ")";
}
}
}
@@ -143,23 +149,23 @@
{
ScopedIndent func_indent(indent_size_);
- ScopedStopNode scope(stop_nodes_, f->end_target);
- Walk(f->start_target);
+ ScopedStopNode scope(stop_nodes_, f->EndTarget());
+ Walk(f->StartTarget());
}
out_ << "} ";
- Walk(f->end_target);
+ Walk(f->EndTarget());
},
[&](const ir::Block* b) {
// If this block is dead, nothing to do
- if (b->IsDead()) {
+ if (!b->HasBranchTarget()) {
return;
}
Indent() << "%fn" << IdOf(b) << " = block";
- if (!b->params.IsEmpty()) {
+ if (!b->Params().IsEmpty()) {
out_ << " (";
- for (auto* p : b->params) {
- if (p != b->params.Front()) {
+ for (const auto* p : b->Params()) {
+ if (p != b->Params().Front()) {
out_ << ", ";
}
EmitValue(p);
@@ -175,20 +181,20 @@
Indent() << "}";
std::string suffix = "";
- if (b->branch.target->Is<FunctionTerminator>()) {
+ if (b->Branch().target->Is<FunctionTerminator>()) {
out_ << " -> %func_end";
suffix = "return";
- } else if (b->branch.target->Is<RootTerminator>()) {
+ } else if (b->Branch().target->Is<RootTerminator>()) {
// Nothing to do
} else {
out_ << " -> "
- << "%fn" << IdOf(b->branch.target);
+ << "%fn" << IdOf(b->Branch().target);
suffix = "branch";
}
- if (!b->branch.args.IsEmpty()) {
+ if (!b->Branch().args.IsEmpty()) {
out_ << " ";
- for (const auto* v : b->branch.args) {
- if (v != b->branch.args.Front()) {
+ for (const auto* v : b->Branch().args) {
+ if (v != b->Branch().args.Front()) {
out_ << ", ";
}
EmitValue(v);
@@ -199,18 +205,18 @@
}
out_ << std::endl;
- if (!b->branch.target->Is<FunctionTerminator>()) {
+ if (!b->Branch().target->Is<FunctionTerminator>()) {
out_ << std::endl;
}
- Walk(b->branch.target);
+ Walk(b->Branch().target);
},
[&](const ir::Switch* s) {
Indent() << "%fn" << IdOf(s) << " = switch ";
- EmitValue(s->condition);
+ EmitValue(s->Condition());
out_ << " [";
- for (const auto& c : s->cases) {
- if (&c != &s->cases.Front()) {
+ for (const auto& c : s->Cases()) {
+ if (&c != &s->Cases().Front()) {
out_ << ", ";
}
out_ << "c: (";
@@ -225,17 +231,17 @@
EmitValue(selector.val);
}
}
- out_ << ", %fn" << IdOf(c.start.target) << ")";
+ out_ << ", %fn" << IdOf(c.Start().target) << ")";
}
- if (s->merge.target->IsConnected()) {
- out_ << ", m: %fn" << IdOf(s->merge.target);
+ if (s->Merge().target->IsConnected()) {
+ out_ << ", m: %fn" << IdOf(s->Merge().target);
}
out_ << "]" << std::endl;
{
ScopedIndent switch_indent(indent_size_);
- ScopedStopNode scope(stop_nodes_, s->merge.target);
- for (const auto& c : s->cases) {
+ ScopedStopNode scope(stop_nodes_, s->Merge().target);
+ for (const auto& c : s->Cases()) {
Indent() << "# case ";
for (const auto& selector : c.selectors) {
if (&selector != &c.selectors.Front()) {
@@ -249,86 +255,86 @@
}
}
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;
- Walk(s->merge.target);
+ Walk(s->Merge().target);
}
},
[&](const ir::If* i) {
Indent() << "%fn" << IdOf(i) << " = if ";
- EmitValue(i->condition);
+ EmitValue(i->Condition());
- bool has_true = !i->true_.target->IsDead();
- bool has_false = !i->false_.target->IsDead();
+ bool has_true = i->True().target->HasBranchTarget();
+ bool has_false = i->False().target->HasBranchTarget();
out_ << " [";
if (has_true) {
- out_ << "t: %fn" << IdOf(i->true_.target);
+ out_ << "t: %fn" << IdOf(i->True().target);
}
if (has_false) {
if (has_true) {
out_ << ", ";
}
- out_ << "f: %fn" << IdOf(i->false_.target);
+ out_ << "f: %fn" << IdOf(i->False().target);
}
- if (i->merge.target->IsConnected()) {
- out_ << ", m: %fn" << IdOf(i->merge.target);
+ if (i->Merge().target->IsConnected()) {
+ out_ << ", m: %fn" << IdOf(i->Merge().target);
}
out_ << "]" << std::endl;
{
ScopedIndent if_indent(indent_size_);
- ScopedStopNode scope(stop_nodes_, i->merge.target);
+ ScopedStopNode scope(stop_nodes_, i->Merge().target);
if (has_true) {
Indent() << "# true branch" << std::endl;
- Walk(i->true_.target);
+ Walk(i->True().target);
}
if (has_false) {
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;
- Walk(i->merge.target);
+ Walk(i->Merge().target);
}
},
[&](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()) {
- out_ << ", c: %fn" << IdOf(l->continuing.target);
+ if (l->Continuing().target->IsConnected()) {
+ out_ << ", c: %fn" << IdOf(l->Continuing().target);
}
- if (l->merge.target->IsConnected()) {
- out_ << ", m: %fn" << IdOf(l->merge.target);
+ if (l->Merge().target->IsConnected()) {
+ out_ << ", m: %fn" << IdOf(l->Merge().target);
}
out_ << "]" << std::endl;
{
- ScopedStopNode loop_scope(stop_nodes_, l->merge.target);
+ ScopedStopNode loop_scope(stop_nodes_, l->Merge().target);
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;
- Walk(l->start.target);
+ Walk(l->Start().target);
}
- if (l->continuing.target->IsConnected()) {
+ if (l->Continuing().target->IsConnected()) {
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;
- Walk(l->merge.target);
+ Walk(l->Merge().target);
}
},
[&](const ir::FunctionTerminator*) {
@@ -401,12 +407,13 @@
}
});
};
- emit(constant->value);
+ emit(constant->Value());
},
[&](const ir::Instruction* i) { out_ << "%" << IdOf(i); },
[&](const ir::BlockParam* p) {
out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName();
},
+ [&](const ir::FunctionParam* p) { out_ << "%" << IdOf(p); },
[&](Default) { out_ << "Unknown value: " << val->TypeInfo().name; });
}
@@ -438,18 +445,18 @@
[&](const ir::Load* l) {
EmitValueWithType(l);
out_ << " = load ";
- EmitValue(l->from);
+ EmitValue(l->From());
},
[&](const ir::Store* s) {
out_ << "store ";
- EmitValue(s->to);
+ EmitValue(s->To());
out_ << ", ";
- EmitValue(s->from);
+ EmitValue(s->From());
},
[&](const ir::UserCall* uc) {
EmitValueWithType(uc);
- out_ << " = call " << uc->name.Name();
- if (uc->args.Length() > 0) {
+ out_ << " = call " << uc->Name().Name();
+ if (!uc->Args().IsEmpty()) {
out_ << ", ";
}
EmitArgs(uc);
@@ -457,16 +464,16 @@
[&](const ir::Var* v) {
EmitValueWithType(v);
out_ << " = var";
- if (v->initializer) {
+ if (v->Initializer()) {
out_ << ", ";
- EmitValue(v->initializer);
+ EmitValue(v->Initializer());
}
});
}
void Disassembler::EmitArgs(const Call* call) {
bool first = true;
- for (const auto* arg : call->args) {
+ for (const auto* arg : call->Args()) {
if (!first) {
out_ << ", ";
}
@@ -478,7 +485,7 @@
void Disassembler::EmitBinary(const Binary* b) {
EmitValueWithType(b);
out_ << " = ";
- switch (b->kind) {
+ switch (b->Kind()) {
case Binary::Kind::kAdd:
out_ << "add";
break;
@@ -537,7 +544,7 @@
void Disassembler::EmitUnary(const Unary* u) {
EmitValueWithType(u);
out_ << " = ";
- switch (u->kind) {
+ switch (u->Kind()) {
case Unary::Kind::kComplement:
out_ << "complement";
break;
diff --git a/src/tint/ir/flow_node.h b/src/tint/ir/flow_node.h
index 905f077..289873b 100644
--- a/src/tint/ir/flow_node.h
+++ b/src/tint/ir/flow_node.h
@@ -25,22 +25,30 @@
public:
~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
- 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
- virtual bool IsDead() const { return false; }
+ /// @returns true if the node has a branch target
+ 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:
/// Constructor
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
diff --git a/src/tint/ir/from_program.cc b/src/tint/ir/from_program.cc
index bb9c3f9..595db58 100644
--- a/src/tint/ir/from_program.cc
+++ b/src/tint/ir/from_program.cc
@@ -98,17 +98,13 @@
using ResultType = utils::Result<Module, diag::List>;
-bool IsBranched(const Block* b) {
- return b->branch.target != nullptr;
-}
-
bool IsConnected(const FlowNode* b) {
// Function is always connected as it's the start.
if (b->Is<ir::Function>()) {
return true;
}
- for (auto* parent : b->inbound_branches) {
+ for (auto* parent : b->InboundBranches()) {
if (IsConnected(parent)) {
return true;
}
@@ -146,7 +142,7 @@
/* src */ {&program_->Symbols()},
/* dst */ {&builder_.ir.symbols, &builder_.ir.types},
},
- /* dst */ {&builder_.ir.constants},
+ /* dst */ {&builder_.ir.constants_arena},
};
/// The stack of flow control blocks.
@@ -184,14 +180,14 @@
void BranchTo(FlowNode* node, utils::VectorRef<Value*> args = {}) {
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;
}
void BranchToIfNeeded(FlowNode* node) {
- if (!current_flow_block_ || IsBranched(current_flow_block_)) {
+ if (!current_flow_block_ || current_flow_block_->HasBranchTarget()) {
return;
}
BranchTo(node);
@@ -271,20 +267,17 @@
if (ast_func->IsEntryPoint()) {
switch (ast_func->PipelineStage()) {
case ast::PipelineStage::kVertex:
- ir_func->pipeline_stage = Function::PipelineStage::kVertex;
+ ir_func->SetStage(Function::PipelineStage::kVertex);
break;
case ast::PipelineStage::kFragment:
- ir_func->pipeline_stage = Function::PipelineStage::kFragment;
+ ir_func->SetStage(Function::PipelineStage::kFragment);
break;
case ast::PipelineStage::kCompute: {
- ir_func->pipeline_stage = Function::PipelineStage::kCompute;
+ ir_func->SetStage(Function::PipelineStage::kCompute);
auto wg_size = sem->WorkgroupSize();
- ir_func->workgroup_size = {
- wg_size[0].value(),
- wg_size[1].value_or(1),
- wg_size[2].value_or(1),
- };
+ ir_func->SetWorkgroupSize(wg_size[0].value(), wg_size[1].value_or(1),
+ wg_size[2].value_or(1));
break;
}
default: {
@@ -293,14 +286,15 @@
}
}
+ utils::Vector<Function::ReturnAttribute, 1> return_attributes;
for (auto* attr : ast_func->return_type_attributes) {
tint::Switch(
attr, //
[&](const ast::LocationAttribute*) {
- ir_func->return_attributes.Push(Function::ReturnAttribute::kLocation);
+ return_attributes.Push(Function::ReturnAttribute::kLocation);
},
[&](const ast::InvariantAttribute*) {
- ir_func->return_attributes.Push(Function::ReturnAttribute::kInvariant);
+ return_attributes.Push(Function::ReturnAttribute::kInvariant);
},
[&](const ast::BuiltinAttribute* b) {
if (auto* ident_sem =
@@ -309,16 +303,13 @@
->As<sem::BuiltinEnumExpression<builtin::BuiltinValue>>()) {
switch (ident_sem->Value()) {
case builtin::BuiltinValue::kPosition:
- ir_func->return_attributes.Push(
- Function::ReturnAttribute::kPosition);
+ return_attributes.Push(Function::ReturnAttribute::kPosition);
break;
case builtin::BuiltinValue::kFragDepth:
- ir_func->return_attributes.Push(
- Function::ReturnAttribute::kFragDepth);
+ return_attributes.Push(Function::ReturnAttribute::kFragDepth);
break;
case builtin::BuiltinValue::kSampleMask:
- ir_func->return_attributes.Push(
- Function::ReturnAttribute::kSampleMask);
+ return_attributes.Push(Function::ReturnAttribute::kSampleMask);
break;
default:
TINT_ICE(IR, diagnostics_)
@@ -332,20 +323,34 @@
}
});
}
+ ir_func->SetReturnAttributes(return_attributes);
}
- ir_func->return_location = sem->ReturnLocation();
+ ir_func->SetReturnLocation(sem->ReturnLocation());
+
+ scopes_.Push();
+ TINT_DEFER(scopes_.Pop());
+
+ utils::Vector<FunctionParam*, 1> params;
+ for (auto* p : ast_func->params) {
+ const auto* param_sem = program_->Sem().Get(p);
+ auto* ty = param_sem->Type()->Clone(clone_ctx_.type_ctx);
+ auto* param = builder_.FunctionParam(ty);
+
+ scopes_.Set(p->name->symbol, param);
+ builder_.ir.SetName(param, p->name->symbol.NameView());
+ params.Push(param);
+ }
+ ir_func->SetParams(params);
{
FlowStackScope scope(this, ir_func);
- current_flow_block_ = ir_func->start_target;
+ current_flow_block_ = ir_func->StartTarget();
EmitBlock(ast_func->body);
- // TODO(dsinclair): Store parameters
-
// If the branch target has already been set then a `return` was called. Only set in the
// case where `return` wasn't called.
- BranchToIfNeeded(current_function_->end_target);
+ BranchToIfNeeded(current_function_->EndTarget());
}
TINT_ASSERT(IR, flow_stack_.IsEmpty());
@@ -359,7 +364,7 @@
// If the current flow block has a branch target then the rest of the statements in this
// block are dead code. Skip them.
- if (!current_flow_block_ || IsBranched(current_flow_block_)) {
+ if (!current_flow_block_ || current_flow_block_->HasBranchTarget()) {
break;
}
}
@@ -414,7 +419,7 @@
return;
}
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) {
@@ -425,7 +430,7 @@
// Load from the LHS.
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();
@@ -438,10 +443,10 @@
} else {
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);
- current_flow_block_->instructions.Push(store);
+ current_flow_block_->Instructions().Push(store);
}
void EmitCompoundAssignment(const ast::CompoundAssignmentStatement* stmt) {
@@ -457,7 +462,7 @@
// Load from the LHS.
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();
@@ -507,10 +512,10 @@
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
return;
}
- current_flow_block_->instructions.Push(inst);
+ current_flow_block_->Instructions().Push(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) {
@@ -538,27 +543,27 @@
{
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);
- // If the true branch did not execute control flow, then go to the merge target
- BranchToIfNeeded(if_node->merge.target);
+ // If the true branch did not execute control flow, then go to the 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) {
EmitStatement(stmt->else_statement);
}
- // If the false branch did not execute control flow, then go to the merge target
- BranchToIfNeeded(if_node->merge.target);
+ // If the false branch did not execute control flow, then go to the Merge().target
+ BranchToIfNeeded(if_node->Merge().target);
}
current_flow_block_ = nullptr;
// 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
// anyway.
- if (IsConnected(if_node->merge.target)) {
- current_flow_block_ = if_node->merge.target->As<Block>();
+ if (IsConnected(if_node->Merge().target)) {
+ current_flow_block_ = if_node->Merge().target->As<Block>();
}
}
@@ -572,7 +577,7 @@
{
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
// until after the continuing block.
@@ -581,21 +586,22 @@
EmitStatements(stmt->body->statements);
// 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) {
EmitBlock(stmt->continuing);
}
// 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
- // target branches, eventually, to the merge, but nothing branched to the continuing target.
- current_flow_block_ = loop_node->merge.target->As<Block>();
- if (!IsConnected(loop_node->merge.target)) {
+ // target branches, eventually, to the merge, but nothing branched to the
+ // Continuing().target.
+ current_flow_block_ = loop_node->Merge().target->As<Block>();
+ if (!IsConnected(loop_node->Merge().target)) {
current_flow_block_ = nullptr;
}
}
@@ -603,9 +609,8 @@
void EmitWhile(const ast::WhileStatement* stmt) {
auto* loop_node = builder_.CreateLoop();
// Continue is always empty, just go back to the start
- TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>());
- builder_.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
- utils::Empty);
+ TINT_ASSERT(IR, loop_node->Continuing().target->Is<Block>());
+ loop_node->Continuing().target->As<Block>()->BranchTo(loop_node->Start().target);
BranchTo(loop_node);
@@ -614,9 +619,9 @@
{
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);
if (!reg) {
return;
@@ -624,31 +629,24 @@
// Create an `if (cond) {} else {break;}` control flow
auto* if_node = builder_.CreateIf(reg.Get());
- TINT_ASSERT(IR, if_node->true_.target->Is<Block>());
- builder_.Branch(if_node->true_.target->As<Block>(), if_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);
+ if_node->True().target->As<Block>()->BranchTo(if_node->Merge().target);
+ if_node->False().target->As<Block>()->BranchTo(loop_node->Merge().target);
BranchTo(if_node);
- current_flow_block_ = if_node->merge.target->As<Block>();
+ current_flow_block_ = if_node->Merge().target->As<Block>();
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
- // anything inside the loop.
- current_flow_block_ = loop_node->merge.target->As<Block>();
+ // The while loop always has a path to the Merge().target as the break statement comes
+ // before anything inside the loop.
+ current_flow_block_ = loop_node->Merge().target->As<Block>();
}
void EmitForLoop(const ast::ForLoopStatement* stmt) {
auto* loop_node = builder_.CreateLoop();
- TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>());
- builder_.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
- utils::Empty);
+ loop_node->Continuing().target->As<Block>()->BranchTo(loop_node->Start().target);
// Make sure the initializer ends up in a contained scope
scopes_.Push();
@@ -666,7 +664,7 @@
{
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) {
// Emit the condition into the target target of the loop
@@ -677,30 +675,25 @@
// Create an `if (cond) {} else {break;}` control flow
auto* if_node = builder_.CreateIf(reg.Get());
- TINT_ASSERT(IR, if_node->true_.target->Is<Block>());
- builder_.Branch(if_node->true_.target->As<Block>(), if_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);
+ if_node->True().target->As<Block>()->BranchTo(if_node->Merge().target);
+ if_node->False().target->As<Block>()->BranchTo(loop_node->Merge().target);
BranchTo(if_node);
- current_flow_block_ = if_node->merge.target->As<Block>();
+ current_flow_block_ = if_node->Merge().target->As<Block>();
}
EmitBlock(stmt->body);
- BranchToIfNeeded(loop_node->continuing.target);
+ BranchToIfNeeded(loop_node->Continuing().target);
if (stmt->continuing) {
- current_flow_block_ = loop_node->continuing.target->As<Block>();
+ current_flow_block_ = loop_node->Continuing().target->As<Block>();
EmitStatement(stmt->continuing);
}
}
- // The while loop always has a path to the merge target as the break statement comes before
- // anything inside the loop.
- current_flow_block_ = loop_node->merge.target->As<Block>();
+ // The while loop always has a path to the Merge().target as the break statement comes
+ // before anything inside the loop.
+ current_flow_block_ = loop_node->Merge().target->As<Block>();
}
void EmitSwitch(const ast::SwitchStatement* stmt) {
@@ -732,13 +725,13 @@
current_flow_block_ = builder_.CreateCase(switch_node, selectors);
EmitBlock(c->Body()->Declaration());
- BranchToIfNeeded(switch_node->merge.target);
+ BranchToIfNeeded(switch_node->Merge().target);
}
}
current_flow_block_ = nullptr;
- if (IsConnected(switch_node->merge.target)) {
- current_flow_block_ = switch_node->merge.target->As<Block>();
+ if (IsConnected(switch_node->Merge().target)) {
+ current_flow_block_ = switch_node->Merge().target->As<Block>();
}
}
@@ -752,7 +745,7 @@
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*) {
@@ -760,9 +753,9 @@
TINT_ASSERT(IR, current_control);
if (auto* c = current_control->As<Loop>()) {
- BranchTo(c->merge.target);
+ BranchTo(c->Merge().target);
} else if (auto* s = current_control->As<Switch>()) {
- BranchTo(s->merge.target);
+ BranchTo(s->Merge().target);
} else {
TINT_UNREACHABLE(IR, diagnostics_);
}
@@ -773,7 +766,7 @@
TINT_ASSERT(IR, current_control);
if (auto* c = current_control->As<Loop>()) {
- BranchTo(c->continuing.target);
+ BranchTo(c->Continuing().target);
} else {
TINT_UNREACHABLE(IR, diagnostics_);
}
@@ -785,7 +778,7 @@
// figuring out the multi-level exit that is triggered.
void EmitDiscard(const ast::DiscardStatement*) {
auto* inst = builder_.Discard();
- current_flow_block_->instructions.Push(inst);
+ current_flow_block_->Instructions().Push(inst);
}
void EmitBreakIf(const ast::BreakIfStatement* stmt) {
@@ -806,17 +799,17 @@
auto* loop = current_control->As<Loop>();
- current_flow_block_ = if_node->true_.target->As<Block>();
- BranchTo(loop->merge.target);
+ current_flow_block_ = if_node->True().target->As<Block>();
+ BranchTo(loop->Merge().target);
- current_flow_block_ = if_node->false_.target->As<Block>();
- BranchTo(if_node->merge.target);
+ current_flow_block_ = if_node->False().target->As<Block>();
+ 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
// `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) {
@@ -863,7 +856,7 @@
// If this expression maps to sem::Load, insert a load instruction to get the result.
if (result && sem->Is<sem::Load>()) {
auto* load = builder_.Load(result.Get());
- current_flow_block_->instructions.Push(load);
+ current_flow_block_->Instructions().Push(load);
return load;
}
@@ -882,14 +875,14 @@
ref->Access());
auto* val = builder_.Declare(ty);
- current_flow_block_->instructions.Push(val);
+ current_flow_block_->Instructions().Push(val);
if (v->initializer) {
auto init = EmitExpression(v->initializer);
if (!init) {
return;
}
- val->initializer = init.Get();
+ val->SetInitializer(init.Get());
}
// Store the declaration so we can get the instruction to store too
scopes_.Set(v->name->symbol, val);
@@ -956,7 +949,7 @@
break;
}
- current_flow_block_->instructions.Push(inst);
+ current_flow_block_->Instructions().Push(inst);
return inst;
}
@@ -983,7 +976,7 @@
BranchTo(if_node);
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;
{
@@ -997,17 +990,17 @@
if (expr->op == ast::BinaryOp::kLogicalAnd) {
// If the lhs is false, then that is the result we want to pass to the merge block
// as our argument
- current_flow_block_ = if_node->false_.target->As<Block>();
- BranchTo(if_node->merge.target, std::move(alt_args));
+ current_flow_block_ = if_node->False().target->As<Block>();
+ 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 {
// If the lhs is true, then that is the result we want to pass to the merge block
// as our argument
- current_flow_block_ = if_node->true_.target->As<Block>();
- BranchTo(if_node->merge.target, std::move(alt_args));
+ current_flow_block_ = if_node->True().target->As<Block>();
+ 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);
@@ -1017,9 +1010,9 @@
utils::Vector<Value*, 1> args;
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;
}
@@ -1101,7 +1094,7 @@
return utils::Failure;
}
- current_flow_block_->instructions.Push(inst);
+ current_flow_block_->Instructions().Push(inst);
return inst;
}
@@ -1115,7 +1108,7 @@
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
auto* inst = builder_.Bitcast(ty, val.Get());
- current_flow_block_->instructions.Push(inst);
+ current_flow_block_->Instructions().Push(inst);
return inst;
}
@@ -1178,7 +1171,7 @@
if (inst == nullptr) {
return utils::Failure;
}
- current_flow_block_->instructions.Push(inst);
+ current_flow_block_->Instructions().Push(inst);
return inst;
}
diff --git a/src/tint/ir/from_program_binary_test.cc b/src/tint/ir/from_program_binary_test.cc
index 85377ff..b74a8c8 100644
--- a/src/tint/ir/from_program_binary_test.cc
+++ b/src/tint/ir/from_program_binary_test.cc
@@ -830,7 +830,7 @@
auto m = Build();
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
- EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():bool {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func(%p:bool):bool {
%fn2 = block {
} -> %func_end true # return
} %func_end
diff --git a/src/tint/ir/from_program_call_test.cc b/src/tint/ir/from_program_call_test.cc
index 038f4dd..6339c22 100644
--- a/src/tint/ir/from_program_call_test.cc
+++ b/src/tint/ir/from_program_call_test.cc
@@ -77,14 +77,14 @@
auto m = Build();
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
- EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():void {
+ EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func(%p:f32):void {
%fn2 = block {
} -> %func_end # return
} %func_end
%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
%fn4 = block {
- %1:void = call my_func, 6.0f
+ %2:void = call my_func, 6.0f
} -> %func_end # return
} %func_end
diff --git a/src/tint/ir/from_program_literal_test.cc b/src/tint/ir/from_program_literal_test.cc
index de5e81e..f746bc0 100644
--- a/src/tint/ir/from_program_literal_test.cc
+++ b/src/tint/ir/from_program_literal_test.cc
@@ -25,17 +25,19 @@
namespace tint::ir {
namespace {
-Value* GlobalVarInitializer(const Module& m) {
- if (m.root_block->instructions.Length() == 0u) {
+const Value* GlobalVarInitializer(const Module& m) {
+ const auto instr = m.root_block->Instructions();
+
+ if (instr.Length() == 0u) {
ADD_FAILURE() << "m.root_block has no instruction";
return nullptr;
}
- auto* var = m.root_block->instructions[0]->As<ir::Var>();
+ auto* var = instr[0]->As<ir::Var>();
if (!var) {
ADD_FAILURE() << "m.root_block.instructions[0] was not a var";
return nullptr;
}
- return var->initializer;
+ return var->Initializer();
}
using namespace tint::number_suffixes; // NOLINT
@@ -51,7 +53,7 @@
auto* init = GlobalVarInitializer(m.Get());
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->As<constant::Scalar<bool>>()->ValueAs<bool>());
}
@@ -65,11 +67,35 @@
auto* init = GlobalVarInitializer(m.Get());
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_FALSE(val->As<constant::Scalar<bool>>()->ValueAs<bool>());
}
+TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_Deduped) {
+ GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(true));
+ GlobalVar("b", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(false));
+ GlobalVar("c", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(true));
+ GlobalVar("d", ty.bool_(), builtin::AddressSpace::kPrivate, Expr(false));
+
+ auto m = Build();
+ ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+
+ auto instr = m.Get().root_block->Instructions();
+ auto* var_a = instr[0]->As<ir::Var>();
+ ASSERT_NE(var_a, nullptr);
+ auto* var_b = instr[1]->As<ir::Var>();
+ ASSERT_NE(var_b, nullptr);
+ auto* var_c = instr[2]->As<ir::Var>();
+ ASSERT_NE(var_c, nullptr);
+ auto* var_d = instr[3]->As<ir::Var>();
+ ASSERT_NE(var_d, nullptr);
+
+ ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
+ ASSERT_EQ(var_b->Initializer(), var_d->Initializer());
+ ASSERT_NE(var_a->Initializer(), var_b->Initializer());
+}
+
TEST_F(IR_BuilderImplTest, EmitLiteral_F32) {
auto* expr = Expr(1.2_f);
GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate, expr);
@@ -79,11 +105,31 @@
auto* init = GlobalVarInitializer(m.Get());
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_EQ(1.2_f, val->As<constant::Scalar<f32>>()->ValueAs<f32>());
}
+TEST_F(IR_BuilderImplTest, EmitLiteral_F32_Deduped) {
+ GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate, Expr(1.2_f));
+ GlobalVar("b", ty.f32(), builtin::AddressSpace::kPrivate, Expr(1.25_f));
+ GlobalVar("c", ty.f32(), builtin::AddressSpace::kPrivate, Expr(1.2_f));
+
+ auto m = Build();
+ ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+
+ auto instr = m.Get().root_block->Instructions();
+ auto* var_a = instr[0]->As<ir::Var>();
+ ASSERT_NE(var_a, nullptr);
+ auto* var_b = instr[1]->As<ir::Var>();
+ ASSERT_NE(var_b, nullptr);
+ auto* var_c = instr[2]->As<ir::Var>();
+ ASSERT_NE(var_c, nullptr);
+
+ ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
+ ASSERT_NE(var_a->Initializer(), var_b->Initializer());
+}
+
TEST_F(IR_BuilderImplTest, EmitLiteral_F16) {
Enable(builtin::Extension::kF16);
auto* expr = Expr(1.2_h);
@@ -94,11 +140,32 @@
auto* init = GlobalVarInitializer(m.Get());
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_EQ(1.2_h, val->As<constant::Scalar<f16>>()->ValueAs<f32>());
}
+TEST_F(IR_BuilderImplTest, EmitLiteral_F16_Deduped) {
+ Enable(builtin::Extension::kF16);
+ GlobalVar("a", ty.f16(), builtin::AddressSpace::kPrivate, Expr(1.2_h));
+ GlobalVar("b", ty.f16(), builtin::AddressSpace::kPrivate, Expr(1.25_h));
+ GlobalVar("c", ty.f16(), builtin::AddressSpace::kPrivate, Expr(1.2_h));
+
+ auto m = Build();
+ ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+
+ auto instr = m.Get().root_block->Instructions();
+ auto* var_a = instr[0]->As<ir::Var>();
+ ASSERT_NE(var_a, nullptr);
+ auto* var_b = instr[1]->As<ir::Var>();
+ ASSERT_NE(var_b, nullptr);
+ auto* var_c = instr[2]->As<ir::Var>();
+ ASSERT_NE(var_c, nullptr);
+
+ ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
+ ASSERT_NE(var_a->Initializer(), var_b->Initializer());
+}
+
TEST_F(IR_BuilderImplTest, EmitLiteral_I32) {
auto* expr = Expr(-2_i);
GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate, expr);
@@ -108,11 +175,31 @@
auto* init = GlobalVarInitializer(m.Get());
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_EQ(-2_i, val->As<constant::Scalar<i32>>()->ValueAs<f32>());
}
+TEST_F(IR_BuilderImplTest, EmitLiteral_I32_Deduped) {
+ GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate, Expr(-2_i));
+ GlobalVar("b", ty.i32(), builtin::AddressSpace::kPrivate, Expr(2_i));
+ GlobalVar("c", ty.i32(), builtin::AddressSpace::kPrivate, Expr(-2_i));
+
+ auto m = Build();
+ ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+
+ auto instr = m.Get().root_block->Instructions();
+ auto* var_a = instr[0]->As<ir::Var>();
+ ASSERT_NE(var_a, nullptr);
+ auto* var_b = instr[1]->As<ir::Var>();
+ ASSERT_NE(var_b, nullptr);
+ auto* var_c = instr[2]->As<ir::Var>();
+ ASSERT_NE(var_c, nullptr);
+
+ ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
+ ASSERT_NE(var_a->Initializer(), var_b->Initializer());
+}
+
TEST_F(IR_BuilderImplTest, EmitLiteral_U32) {
auto* expr = Expr(2_u);
GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate, expr);
@@ -122,10 +209,30 @@
auto* init = GlobalVarInitializer(m.Get());
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_EQ(2_u, val->As<constant::Scalar<u32>>()->ValueAs<f32>());
}
+TEST_F(IR_BuilderImplTest, EmitLiteral_U32_Deduped) {
+ GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate, Expr(2_u));
+ GlobalVar("b", ty.u32(), builtin::AddressSpace::kPrivate, Expr(3_u));
+ GlobalVar("c", ty.u32(), builtin::AddressSpace::kPrivate, Expr(2_u));
+
+ auto m = Build();
+ ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+
+ auto instr = m.Get().root_block->Instructions();
+ auto* var_a = instr[0]->As<ir::Var>();
+ ASSERT_NE(var_a, nullptr);
+ auto* var_b = instr[1]->As<ir::Var>();
+ ASSERT_NE(var_b, nullptr);
+ auto* var_c = instr[2]->As<ir::Var>();
+ ASSERT_NE(var_c, nullptr);
+
+ ASSERT_EQ(var_a->Initializer(), var_c->Initializer());
+ ASSERT_NE(var_a->Initializer(), var_b->Initializer());
+}
+
} // namespace
} // namespace tint::ir
diff --git a/src/tint/ir/from_program_test.cc b/src/tint/ir/from_program_test.cc
index 47dc911..1049386 100644
--- a/src/tint/ir/from_program_test.cc
+++ b/src/tint/ir/from_program_test.cc
@@ -63,13 +63,13 @@
ASSERT_EQ(1u, m->functions.Length());
auto* f = m->functions[0];
- ASSERT_NE(f->start_target, nullptr);
- ASSERT_NE(f->end_target, nullptr);
+ ASSERT_NE(f->StartTarget(), nullptr);
+ ASSERT_NE(f->EndTarget(), nullptr);
- EXPECT_EQ(1u, f->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, f->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, f->StartTarget()->InboundBranches().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 {
%fn2 = block {
@@ -79,6 +79,57 @@
)");
}
+TEST_F(IR_BuilderImplTest, Func_WithParam) {
+ Func("f", utils::Vector{Param("a", ty.u32())}, ty.u32(), utils::Vector{Return("a")});
+
+ auto m = Build();
+ ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+
+ ASSERT_EQ(1u, m->functions.Length());
+
+ auto* f = m->functions[0];
+ ASSERT_NE(f->StartTarget(), nullptr);
+ ASSERT_NE(f->EndTarget(), nullptr);
+
+ EXPECT_EQ(1u, f->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, f->EndTarget()->InboundBranches().Length());
+
+ EXPECT_EQ(m->functions[0]->Stage(), Function::PipelineStage::kUndefined);
+
+ EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f(%a:u32):u32 {
+ %fn2 = block {
+ } -> %func_end %a # return
+} %func_end
+
+)");
+}
+
+TEST_F(IR_BuilderImplTest, Func_WithMultipleParam) {
+ Func("f", utils::Vector{Param("a", ty.u32()), Param("b", ty.i32()), Param("c", ty.bool_())},
+ ty.void_(), utils::Empty);
+
+ auto m = Build();
+ ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+
+ ASSERT_EQ(1u, m->functions.Length());
+
+ auto* f = m->functions[0];
+ ASSERT_NE(f->StartTarget(), nullptr);
+ ASSERT_NE(f->EndTarget(), nullptr);
+
+ EXPECT_EQ(1u, f->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, f->EndTarget()->InboundBranches().Length());
+
+ 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 {
+ %fn2 = block {
+ } -> %func_end # return
+} %func_end
+
+)");
+}
+
TEST_F(IR_BuilderImplTest, EntryPoint) {
Func("f", utils::Empty, ty.void_(), utils::Empty,
utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -86,7 +137,7 @@
auto m = Build();
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) {
@@ -97,19 +148,19 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(flow->true_.target, nullptr);
- ASSERT_NE(flow->false_.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->True().target, nullptr);
+ ASSERT_NE(flow->False().target, nullptr);
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(2u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(2u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -141,19 +192,19 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(flow->true_.target, nullptr);
- ASSERT_NE(flow->false_.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->True().target, nullptr);
+ ASSERT_NE(flow->False().target, nullptr);
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -184,19 +235,19 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(flow->true_.target, nullptr);
- ASSERT_NE(flow->false_.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->True().target, nullptr);
+ ASSERT_NE(flow->False().target, nullptr);
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -227,19 +278,19 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(flow->true_.target, nullptr);
- ASSERT_NE(flow->false_.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->True().target, nullptr);
+ ASSERT_NE(flow->False().target, nullptr);
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(0u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -267,15 +318,15 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(if_flow->true_.target, nullptr);
- ASSERT_NE(if_flow->false_.target, nullptr);
- ASSERT_NE(if_flow->merge.target, nullptr);
+ ASSERT_NE(if_flow->True().target, nullptr);
+ ASSERT_NE(if_flow->False().target, nullptr);
+ ASSERT_NE(if_flow->Merge().target, nullptr);
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
ASSERT_NE(loop_flow, nullptr);
- ASSERT_NE(loop_flow->start.target, nullptr);
- ASSERT_NE(loop_flow->continuing.target, nullptr);
- ASSERT_NE(loop_flow->merge.target, nullptr);
+ ASSERT_NE(loop_flow->Start().target, nullptr);
+ ASSERT_NE(loop_flow->Continuing().target, nullptr);
+ ASSERT_NE(loop_flow->Merge().target, nullptr);
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -316,19 +367,19 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(flow->start.target, nullptr);
- ASSERT_NE(flow->continuing.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->Start().target, nullptr);
+ ASSERT_NE(flow->Continuing().target, nullptr);
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
- EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -357,28 +408,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(loop_flow->start.target, nullptr);
- ASSERT_NE(loop_flow->continuing.target, nullptr);
- ASSERT_NE(loop_flow->merge.target, nullptr);
+ ASSERT_NE(loop_flow->Start().target, nullptr);
+ ASSERT_NE(loop_flow->Continuing().target, nullptr);
+ ASSERT_NE(loop_flow->Merge().target, nullptr);
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(if_flow->true_.target, nullptr);
- ASSERT_NE(if_flow->false_.target, nullptr);
- ASSERT_NE(if_flow->merge.target, nullptr);
+ ASSERT_NE(if_flow->True().target, nullptr);
+ ASSERT_NE(if_flow->False().target, nullptr);
+ ASSERT_NE(if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -424,28 +475,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(loop_flow->start.target, nullptr);
- ASSERT_NE(loop_flow->continuing.target, nullptr);
- ASSERT_NE(loop_flow->merge.target, nullptr);
+ ASSERT_NE(loop_flow->Start().target, nullptr);
+ ASSERT_NE(loop_flow->Continuing().target, nullptr);
+ ASSERT_NE(loop_flow->Merge().target, nullptr);
auto* break_if_flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(break_if_flow->true_.target, nullptr);
- ASSERT_NE(break_if_flow->false_.target, nullptr);
- ASSERT_NE(break_if_flow->merge.target, nullptr);
+ ASSERT_NE(break_if_flow->True().target, nullptr);
+ ASSERT_NE(break_if_flow->False().target, nullptr);
+ ASSERT_NE(break_if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, break_if_flow->inbound_branches.Length());
- EXPECT_EQ(1u, break_if_flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, break_if_flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, break_if_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, break_if_flow->InboundBranches().Length());
+ EXPECT_EQ(1u, break_if_flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, break_if_flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, break_if_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -535,28 +586,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(loop_flow->start.target, nullptr);
- ASSERT_NE(loop_flow->continuing.target, nullptr);
- ASSERT_NE(loop_flow->merge.target, nullptr);
+ ASSERT_NE(loop_flow->Start().target, nullptr);
+ ASSERT_NE(loop_flow->Continuing().target, nullptr);
+ ASSERT_NE(loop_flow->Merge().target, nullptr);
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(if_flow->true_.target, nullptr);
- ASSERT_NE(if_flow->false_.target, nullptr);
- ASSERT_NE(if_flow->merge.target, nullptr);
+ ASSERT_NE(if_flow->True().target, nullptr);
+ ASSERT_NE(if_flow->False().target, nullptr);
+ ASSERT_NE(if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(0u, loop_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(0u, loop_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -597,19 +648,19 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(loop_flow->start.target, nullptr);
- ASSERT_NE(loop_flow->continuing.target, nullptr);
- ASSERT_NE(loop_flow->merge.target, nullptr);
+ ASSERT_NE(loop_flow->Start().target, nullptr);
+ ASSERT_NE(loop_flow->Continuing().target, nullptr);
+ ASSERT_NE(loop_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
- EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(0u, loop_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, loop_flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(0u, loop_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -642,25 +693,25 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(loop_flow->start.target, nullptr);
- ASSERT_NE(loop_flow->continuing.target, nullptr);
- ASSERT_NE(loop_flow->merge.target, nullptr);
+ ASSERT_NE(loop_flow->Start().target, nullptr);
+ ASSERT_NE(loop_flow->Continuing().target, nullptr);
+ ASSERT_NE(loop_flow->Merge().target, nullptr);
auto* break_if_flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(break_if_flow->true_.target, nullptr);
- ASSERT_NE(break_if_flow->false_.target, nullptr);
- ASSERT_NE(break_if_flow->merge.target, nullptr);
+ ASSERT_NE(break_if_flow->True().target, nullptr);
+ ASSERT_NE(break_if_flow->False().target, nullptr);
+ ASSERT_NE(break_if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
- EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
+ EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, loop_flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
// 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()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -685,28 +736,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* loop_flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(loop_flow->start.target, nullptr);
- ASSERT_NE(loop_flow->continuing.target, nullptr);
- ASSERT_NE(loop_flow->merge.target, nullptr);
+ ASSERT_NE(loop_flow->Start().target, nullptr);
+ ASSERT_NE(loop_flow->Continuing().target, nullptr);
+ ASSERT_NE(loop_flow->Merge().target, nullptr);
auto* if_flow = FindSingleFlowNode<ir::If>(m.Get());
- ASSERT_NE(if_flow->true_.target, nullptr);
- ASSERT_NE(if_flow->false_.target, nullptr);
- ASSERT_NE(if_flow->merge.target, nullptr);
+ ASSERT_NE(if_flow->True().target, nullptr);
+ ASSERT_NE(if_flow->False().target, nullptr);
+ ASSERT_NE(if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, loop_flow->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length());
- EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(0u, if_flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, loop_flow->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, loop_flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(0u, if_flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -756,96 +807,96 @@
auto block_exit = [&](const ir::FlowNode* node) -> const ir::FlowNode* {
if (auto* block = As<ir::Block>(node)) {
- return block->branch.target;
+ return block->Branch().target;
}
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->start.target, nullptr);
- ASSERT_NE(loop_flow_a->continuing.target, nullptr);
- ASSERT_NE(loop_flow_a->merge.target, nullptr);
+ ASSERT_NE(loop_flow_a->Start().target, nullptr);
+ ASSERT_NE(loop_flow_a->Continuing().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->start.target, nullptr);
- ASSERT_NE(loop_flow_b->continuing.target, nullptr);
- ASSERT_NE(loop_flow_b->merge.target, nullptr);
+ ASSERT_NE(loop_flow_b->Start().target, nullptr);
+ ASSERT_NE(loop_flow_b->Continuing().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->true_.target, nullptr);
- ASSERT_NE(if_flow_a->false_.target, nullptr);
- ASSERT_NE(if_flow_a->merge.target, nullptr);
+ ASSERT_NE(if_flow_a->True().target, nullptr);
+ ASSERT_NE(if_flow_a->False().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->true_.target, nullptr);
- ASSERT_NE(if_flow_b->false_.target, nullptr);
- ASSERT_NE(if_flow_b->merge.target, nullptr);
+ ASSERT_NE(if_flow_b->True().target, nullptr);
+ ASSERT_NE(if_flow_b->False().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->start.target, nullptr);
- ASSERT_NE(loop_flow_c->continuing.target, nullptr);
- ASSERT_NE(loop_flow_c->merge.target, nullptr);
+ ASSERT_NE(loop_flow_c->Start().target, nullptr);
+ ASSERT_NE(loop_flow_c->Continuing().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->start.target, nullptr);
- ASSERT_NE(loop_flow_d->continuing.target, nullptr);
- ASSERT_NE(loop_flow_d->merge.target, nullptr);
+ ASSERT_NE(loop_flow_d->Start().target, nullptr);
+ ASSERT_NE(loop_flow_d->Continuing().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->true_.target, nullptr);
- ASSERT_NE(if_flow_c->false_.target, nullptr);
- ASSERT_NE(if_flow_c->merge.target, nullptr);
+ ASSERT_NE(if_flow_c->True().target, nullptr);
+ ASSERT_NE(if_flow_c->False().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->true_.target, nullptr);
- ASSERT_NE(if_flow_d->false_.target, nullptr);
- ASSERT_NE(if_flow_d->merge.target, nullptr);
+ ASSERT_NE(if_flow_d->True().target, nullptr);
+ ASSERT_NE(if_flow_d->False().target, nullptr);
+ ASSERT_NE(if_flow_d->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, loop_flow_a->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow_a->start.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_a->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_a->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_b->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow_b->start.target->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow_b->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_b->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_c->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow_c->start.target->inbound_branches.Length());
- EXPECT_EQ(0u, loop_flow_c->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_c->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_d->inbound_branches.Length());
- EXPECT_EQ(2u, loop_flow_d->start.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_d->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, loop_flow_d->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_a->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_a->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_a->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_a->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_b->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_b->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_b->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_b->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_c->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_c->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_c->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_c->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_d->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_d->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_d->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow_d->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, loop_flow_a->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow_a->Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_a->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_a->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_b->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow_b->Start().target->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow_b->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_b->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_c->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow_c->Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, loop_flow_c->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_c->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_d->InboundBranches().Length());
+ EXPECT_EQ(2u, loop_flow_d->Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_d->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, loop_flow_d->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_a->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_a->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_a->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_a->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_b->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_b->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_b->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_b->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_c->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_c->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_c->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_c->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_d->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_d->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_d->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow_d->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->StartTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -964,28 +1015,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(flow->start.target, nullptr);
- ASSERT_NE(flow->continuing.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->Start().target, nullptr);
+ ASSERT_NE(flow->Continuing().target, nullptr);
+ ASSERT_NE(flow->Merge().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>());
- 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->false_.target, nullptr);
- ASSERT_NE(if_flow->merge.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>());
+ 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->False().target, nullptr);
+ ASSERT_NE(if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -1030,28 +1081,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(flow->start.target, nullptr);
- ASSERT_NE(flow->continuing.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->Start().target, nullptr);
+ ASSERT_NE(flow->Continuing().target, nullptr);
+ ASSERT_NE(flow->Merge().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>());
- 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->false_.target, nullptr);
- ASSERT_NE(if_flow->merge.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>());
+ 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->False().target, nullptr);
+ ASSERT_NE(if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
- EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
+ EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -1104,28 +1155,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(flow->start.target, nullptr);
- ASSERT_NE(flow->continuing.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->Start().target, nullptr);
+ ASSERT_NE(flow->Continuing().target, nullptr);
+ ASSERT_NE(flow->Merge().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>());
- 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->false_.target, nullptr);
- ASSERT_NE(if_flow->merge.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>());
+ 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->False().target, nullptr);
+ ASSERT_NE(if_flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
- EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->True().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->False().target->InboundBranches().Length());
+ EXPECT_EQ(1u, if_flow->Merge().target->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()), R"()");
}
@@ -1138,18 +1189,18 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Loop>(m.Get());
- ASSERT_NE(flow->start.target, nullptr);
- ASSERT_NE(flow->continuing.target, nullptr);
- ASSERT_NE(flow->merge.target, nullptr);
+ ASSERT_NE(flow->Start().target, nullptr);
+ ASSERT_NE(flow->Continuing().target, nullptr);
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(2u, flow->start.target->inbound_branches.Length());
- EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(2u, flow->Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, flow->Continuing().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -1180,31 +1231,33 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
- ASSERT_NE(flow->merge.target, nullptr);
- ASSERT_EQ(3u, flow->cases.Length());
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- ASSERT_EQ(1u, flow->cases[0].selectors.Length());
- ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+ auto cases = flow->Cases();
+ 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,
- 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_TRUE(flow->cases[1].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+ ASSERT_EQ(1u, cases[1].selectors.Length());
+ ASSERT_TRUE(cases[1].selectors[0].val->Value()->Is<constant::Scalar<tint::i32>>());
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());
- EXPECT_TRUE(flow->cases[2].selectors[0].IsDefault());
+ ASSERT_EQ(1u, cases[2].selectors.Length());
+ EXPECT_TRUE(cases[2].selectors[0].IsDefault());
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->cases[2].start.target->inbound_branches.Length());
- EXPECT_EQ(3u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[1].Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[2].Start().target->InboundBranches().Length());
+ EXPECT_EQ(3u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -1244,27 +1297,28 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
- ASSERT_NE(flow->merge.target, nullptr);
- ASSERT_EQ(1u, flow->cases.Length());
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- ASSERT_EQ(3u, flow->cases[0].selectors.Length());
- ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+ auto cases = flow->Cases();
+ 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,
- 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,
- 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->cases[0].start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -1292,19 +1346,20 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
- ASSERT_NE(flow->merge.target, nullptr);
- ASSERT_EQ(1u, flow->cases.Length());
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- ASSERT_EQ(1u, flow->cases[0].selectors.Length());
- EXPECT_TRUE(flow->cases[0].selectors[0].IsDefault());
+ auto cases = flow->Cases();
+ 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->cases[0].start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -1334,26 +1389,27 @@
ASSERT_TRUE(m) << (!m ? m.Failure() : "");
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
- ASSERT_NE(flow->merge.target, nullptr);
- ASSERT_EQ(2u, flow->cases.Length());
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- ASSERT_EQ(1u, flow->cases[0].selectors.Length());
- ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+ auto cases = flow->Cases();
+ 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,
- 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());
- EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
+ ASSERT_EQ(1u, cases[1].selectors.Length());
+ EXPECT_TRUE(cases[1].selectors[0].IsDefault());
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length());
- EXPECT_EQ(2u, flow->merge.target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[1].Start().target->InboundBranches().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.
- EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
@@ -1390,25 +1446,26 @@
ASSERT_EQ(FindSingleFlowNode<ir::If>(m.Get()), nullptr);
auto* flow = FindSingleFlowNode<ir::Switch>(m.Get());
- ASSERT_NE(flow->merge.target, nullptr);
- ASSERT_EQ(2u, flow->cases.Length());
+ ASSERT_NE(flow->Merge().target, nullptr);
ASSERT_EQ(1u, m->functions.Length());
auto* func = m->functions[0];
- ASSERT_EQ(1u, flow->cases[0].selectors.Length());
- ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+ auto cases = flow->Cases();
+ 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,
- 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());
- EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
+ ASSERT_EQ(1u, cases[1].selectors.Length());
+ EXPECT_TRUE(cases[1].selectors[0].IsDefault());
- EXPECT_EQ(1u, flow->inbound_branches.Length());
- EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
- EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length());
- EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length());
- EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
+ EXPECT_EQ(1u, flow->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[0].Start().target->InboundBranches().Length());
+ EXPECT_EQ(1u, cases[1].Start().target->InboundBranches().Length());
+ EXPECT_EQ(0u, flow->Merge().target->InboundBranches().Length());
+ EXPECT_EQ(2u, func->EndTarget()->InboundBranches().Length());
EXPECT_EQ(Disassemble(m.Get()),
R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] {
diff --git a/src/tint/ir/function.cc b/src/tint/ir/function.cc
index 2a5f8c3..d6cd6fc 100644
--- a/src/tint/ir/function.cc
+++ b/src/tint/ir/function.cc
@@ -18,11 +18,11 @@
namespace tint::ir {
-Function::Function(Symbol n,
+Function::Function(Symbol name,
type::Type* rt,
PipelineStage stage,
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;
diff --git a/src/tint/ir/function.h b/src/tint/ir/function.h
index 95487b9..86465aa 100644
--- a/src/tint/ir/function.h
+++ b/src/tint/ir/function.h
@@ -17,8 +17,10 @@
#include <array>
#include <optional>
+#include <utility>
#include "src/tint/ir/flow_node.h"
+#include "src/tint/ir/function_param.h"
#include "src/tint/symbol.h"
#include "src/tint/type/type.h"
@@ -70,29 +72,81 @@
type::Type* rt,
PipelineStage stage = PipelineStage::kUndefined,
std::optional<std::array<uint32_t, 3>> wg_size = {});
+ Function(Function&&) = delete;
+ Function(const Function&) = delete;
~Function() override;
- /// The function name
- Symbol name;
+ Function& operator=(Function&&) = delete;
+ Function& operator=(const Function&) = delete;
- /// The pipeline stage for the function, `kUndefined` if the function is not an entry point
- PipelineStage pipeline_stage = PipelineStage::kUndefined;
+ /// @returns the function name
+ Symbol Name() const { return name_; }
- /// If this is a `compute` entry point, holds the workgroup size information
- std::optional<std::array<uint32_t, 3>> workgroup_size;
+ /// Sets the function stage
+ /// @param stage the stage to set
+ void SetStage(PipelineStage stage) { pipeline_stage_ = stage; }
- /// The function return type
- const type::Type* return_type = nullptr;
- /// 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;
+ /// @returns the function pipeline stage
+ PipelineStage Stage() const { return pipeline_stage_; }
- /// The start target is the first block in a function.
- Block* start_target = nullptr;
- /// The end target is the end of the function. It is used as the branch target if a return is
- /// encountered in the function.
- FunctionTerminator* end_target = nullptr;
+ /// Sets the workgroup size
+ /// @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}; }
+
+ /// @returns the workgroup size information
+ std::optional<std::array<uint32_t, 3>> WorkgroupSize() const { return workgroup_size_; }
+
+ /// @returns the return type for the function
+ 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);
diff --git a/src/tint/ir/function_param.cc b/src/tint/ir/function_param.cc
new file mode 100644
index 0000000..a9570fa
--- /dev/null
+++ b/src/tint/ir/function_param.cc
@@ -0,0 +1,25 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ir/function_param.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::FunctionParam);
+
+namespace tint::ir {
+
+FunctionParam::FunctionParam(const type::Type* ty) : type_(ty) {}
+
+FunctionParam::~FunctionParam() = default;
+
+} // namespace tint::ir
diff --git a/src/tint/ir/function_param.h b/src/tint/ir/function_param.h
new file mode 100644
index 0000000..1bbb812
--- /dev/null
+++ b/src/tint/ir/function_param.h
@@ -0,0 +1,46 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_IR_FUNCTION_PARAM_H_
+#define SRC_TINT_IR_FUNCTION_PARAM_H_
+
+#include "src/tint/ir/value.h"
+#include "src/tint/utils/castable.h"
+
+namespace tint::ir {
+
+/// A function parameter in the IR.
+class FunctionParam : public utils::Castable<FunctionParam, Value> {
+ public:
+ /// Constructor
+ /// @param type the type of the var
+ explicit FunctionParam(const type::Type* type);
+ FunctionParam(const FunctionParam& inst) = delete;
+ FunctionParam(FunctionParam&& inst) = delete;
+ ~FunctionParam() override;
+
+ FunctionParam& operator=(const FunctionParam& inst) = delete;
+ FunctionParam& operator=(FunctionParam&& inst) = delete;
+
+ /// @returns the type of the var
+ const type::Type* Type() const override { return type_; }
+
+ private:
+ /// The type of the parameter
+ const type::Type* type_;
+};
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_FUNCTION_PARAM_H_
diff --git a/src/tint/ir/if.cc b/src/tint/ir/if.cc
index b59d87f..d235b5e 100644
--- a/src/tint/ir/if.cc
+++ b/src/tint/ir/if.cc
@@ -18,7 +18,7 @@
namespace tint::ir {
-If::If(Value* cond) : Base(), condition(cond) {}
+If::If(Value* cond) : Base(), condition_(cond) {}
If::~If() = default;
diff --git a/src/tint/ir/if.h b/src/tint/ir/if.h
index aadc5c9..d02c32a 100644
--- a/src/tint/ir/if.h
+++ b/src/tint/ir/if.h
@@ -32,17 +32,36 @@
/// Constructor
/// @param cond the if condition
explicit If(Value* cond);
+ If(const If&) = delete;
+ If(If&&) = delete;
~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_ = {};
- /// The false branch block
Branch false_ = {};
- /// An block to converge the true/false branches. The block always exists, but there maybe no
- /// branches into it. (e.g. if both branches `return`)
- Branch merge = {};
- /// Value holding the condition result
- const Value* condition = nullptr;
+ Branch merge_ = {};
+ Value* condition_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/load.cc b/src/tint/ir/load.cc
index 1fe55c0..3b64cdd 100644
--- a/src/tint/ir/load.cc
+++ b/src/tint/ir/load.cc
@@ -19,10 +19,10 @@
namespace tint::ir {
-Load::Load(const type::Type* type, Value* f) : Base(), result_type(type), from(f) {
- TINT_ASSERT(IR, result_type);
- TINT_ASSERT(IR, from);
- from->AddUsage(this);
+Load::Load(const type::Type* type, Value* f) : Base(), result_type_(type), from_(f) {
+ TINT_ASSERT(IR, result_type_);
+ TINT_ASSERT(IR, from_);
+ from_->AddUsage(this);
}
Load::~Load() = default;
diff --git a/src/tint/ir/load.h b/src/tint/ir/load.h
index b15eced..e1a365f 100644
--- a/src/tint/ir/load.h
+++ b/src/tint/ir/load.h
@@ -35,13 +35,14 @@
Load& operator=(Load&& inst) = delete;
/// @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
- const type::Type* result_type = nullptr;
+ /// @returns the avlue being loaded from
+ Value* From() const { return from_; }
- /// the value being loaded
- Value* from = nullptr;
+ private:
+ const type::Type* result_type_;
+ Value* from_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/load_test.cc b/src/tint/ir/load_test.cc
index 2c6e5c1..9881e98 100644
--- a/src/tint/ir/load_test.cc
+++ b/src/tint/ir/load_test.cc
@@ -33,12 +33,12 @@
const auto* inst = b.Load(var);
ASSERT_TRUE(inst->Is<Load>());
- ASSERT_EQ(inst->from, var);
+ ASSERT_EQ(inst->From(), var);
EXPECT_EQ(inst->Type(), store_type);
- ASSERT_TRUE(inst->from->Is<ir::Var>());
- EXPECT_EQ(inst->from, var);
+ ASSERT_TRUE(inst->From()->Is<ir::Var>());
+ EXPECT_EQ(inst->From(), var);
}
TEST_F(IR_InstructionTest, Load_Usage) {
@@ -50,9 +50,9 @@
store_type, builtin::AddressSpace::kFunction, builtin::Access::kReadWrite));
const auto* inst = b.Load(var);
- ASSERT_NE(inst->from, nullptr);
- ASSERT_EQ(inst->from->Usage().Length(), 1u);
- EXPECT_EQ(inst->from->Usage()[0], inst);
+ ASSERT_NE(inst->From(), nullptr);
+ ASSERT_EQ(inst->From()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->From()->Usage()[0], inst);
}
} // namespace
diff --git a/src/tint/ir/loop.h b/src/tint/ir/loop.h
index e0066f4..590f49c 100644
--- a/src/tint/ir/loop.h
+++ b/src/tint/ir/loop.h
@@ -26,16 +26,32 @@
public:
/// Constructor
Loop();
+ Loop(const Loop&) = delete;
+ Loop(Loop&&) = delete;
~Loop() override;
- /// The start block is the first block in a loop.
- Branch start = {};
- /// The continue target of the block.
- Branch continuing = {};
- /// The loop merge target. If the `loop` does a `return` then this block may not actually
- /// end up in the control flow. We need it if the loop does a `break` we know where to break
- /// too.
- Branch merge = {};
+ Loop& operator=(const Loop&) = delete;
+ Loop& operator=(Loop&&) = delete;
+
+ /// @returns the switch start branch
+ const Branch& Start() const { return start_; }
+ /// @returns the switch start branch
+ Branch& Start() { return start_; }
+
+ /// @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
diff --git a/src/tint/ir/module.h b/src/tint/ir/module.h
index 244bc0a..c6cf74c 100644
--- a/src/tint/ir/module.h
+++ b/src/tint/ir/module.h
@@ -18,6 +18,7 @@
#include <string>
#include "src/tint/constant/value.h"
+#include "src/tint/ir/constant.h"
#include "src/tint/ir/function.h"
#include "src/tint/ir/instruction.h"
#include "src/tint/ir/value.h"
@@ -67,7 +68,7 @@
/// The flow node allocator
utils::BlockAllocator<FlowNode> flow_nodes;
/// The constant allocator
- utils::BlockAllocator<constant::Value> constants;
+ utils::BlockAllocator<constant::Value> constants_arena;
/// The value allocator
utils::BlockAllocator<Value> values;
@@ -82,6 +83,29 @@
/// The symbol table for the module
SymbolTable symbols{prog_id_};
+
+ /// ConstantHasher provides a hash function for a constant::Value pointer, hashing the value
+ /// instead of the pointer itself.
+ struct ConstantHasher {
+ /// @param c the constant pointer to create a hash for
+ /// @return the hash value
+ inline std::size_t operator()(const constant::Value* c) const { return c->Hash(); }
+ };
+
+ /// ConstantEquals provides an equality function for two constant::Value pointers, comparing
+ /// their values instead of the pointers.
+ struct ConstantEquals {
+ /// @param a the first constant pointer to compare
+ /// @param b the second constant pointer to compare
+ /// @return the hash value
+ inline bool operator()(const constant::Value* a, const constant::Value* b) const {
+ return a->Equal(b);
+ }
+ };
+
+ /// The map of constant::Value to their ir::Constant.
+ utils::Hashmap<const constant::Value*, ir::Constant*, 16, ConstantHasher, ConstantEquals>
+ constants;
};
} // namespace tint::ir
diff --git a/src/tint/ir/root_terminator.h b/src/tint/ir/root_terminator.h
index 361aa6d..c6338ba 100644
--- a/src/tint/ir/root_terminator.h
+++ b/src/tint/ir/root_terminator.h
@@ -25,7 +25,12 @@
public:
/// Constructor
RootTerminator();
+ RootTerminator(const RootTerminator&) = delete;
+ RootTerminator(RootTerminator&&) = delete;
~RootTerminator() override;
+
+ RootTerminator& operator=(const RootTerminator&) = delete;
+ RootTerminator& operator=(RootTerminator&&) = delete;
};
} // namespace tint::ir
diff --git a/src/tint/ir/store.cc b/src/tint/ir/store.cc
index 87f3620..8b8de46 100644
--- a/src/tint/ir/store.cc
+++ b/src/tint/ir/store.cc
@@ -19,11 +19,11 @@
namespace tint::ir {
-Store::Store(Value* t, Value* f) : Base(), to(t), from(f) {
- TINT_ASSERT(IR, to);
- TINT_ASSERT(IR, from);
- to->AddUsage(this);
- from->AddUsage(this);
+Store::Store(Value* to, Value* from) : Base(), to_(to), from_(from) {
+ TINT_ASSERT(IR, to_);
+ TINT_ASSERT(IR, from_);
+ to_->AddUsage(this);
+ from_->AddUsage(this);
}
Store::~Store() = default;
diff --git a/src/tint/ir/store.h b/src/tint/ir/store.h
index 9095c41..af5377d 100644
--- a/src/tint/ir/store.h
+++ b/src/tint/ir/store.h
@@ -34,10 +34,15 @@
Store& operator=(const Store& inst) = delete;
Store& operator=(Store&& inst) = delete;
- /// the value being stored to
- Value* to = nullptr;
- /// the value being stored
- Value* from = nullptr;
+ /// @returns the value being stored too
+ Value* To() const { return to_; }
+
+ /// @returns the value being stored
+ Value* From() const { return from_; }
+
+ private:
+ Value* to_;
+ Value* from_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/store_test.cc b/src/tint/ir/store_test.cc
index 902ca95..1906cc6 100644
--- a/src/tint/ir/store_test.cc
+++ b/src/tint/ir/store_test.cc
@@ -33,10 +33,10 @@
const auto* inst = b.Store(to, b.Constant(4_i));
ASSERT_TRUE(inst->Is<Store>());
- ASSERT_EQ(inst->to, to);
+ ASSERT_EQ(inst->To(), to);
- ASSERT_TRUE(inst->from->Is<Constant>());
- auto lhs = inst->from->As<Constant>()->value;
+ ASSERT_TRUE(inst->From()->Is<Constant>());
+ auto lhs = inst->From()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -48,13 +48,13 @@
auto* to = b.Discard();
const auto* inst = b.Store(to, b.Constant(4_i));
- ASSERT_NE(inst->to, nullptr);
- ASSERT_EQ(inst->to->Usage().Length(), 1u);
- EXPECT_EQ(inst->to->Usage()[0], inst);
+ ASSERT_NE(inst->To(), nullptr);
+ ASSERT_EQ(inst->To()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->To()->Usage()[0], inst);
- ASSERT_NE(inst->from, nullptr);
- ASSERT_EQ(inst->from->Usage().Length(), 1u);
- EXPECT_EQ(inst->from->Usage()[0], inst);
+ ASSERT_NE(inst->From(), nullptr);
+ ASSERT_EQ(inst->From()->Usage().Length(), 1u);
+ EXPECT_EQ(inst->From()->Usage()[0], inst);
}
} // namespace
diff --git a/src/tint/ir/switch.cc b/src/tint/ir/switch.cc
index ad6a145..3bccc83 100644
--- a/src/tint/ir/switch.cc
+++ b/src/tint/ir/switch.cc
@@ -18,7 +18,7 @@
namespace tint::ir {
-Switch::Switch(Value* cond) : Base(), condition(cond) {}
+Switch::Switch(Value* cond) : Base(), condition_(cond) {}
Switch::~Switch() = default;
diff --git a/src/tint/ir/switch.h b/src/tint/ir/switch.h
index 6be7b62..2e977ec 100644
--- a/src/tint/ir/switch.h
+++ b/src/tint/ir/switch.h
@@ -41,21 +41,40 @@
utils::Vector<CaseSelector, 4> selectors;
/// The start block for the case block.
Branch start = {};
+
+ /// @returns the case start target
+ const Branch& Start() const { return start; }
+ /// @returns the case start target
+ Branch& Start() { return start; }
};
/// Constructor
/// @param cond the condition
explicit Switch(Value* cond);
+ Switch(const Switch&) = delete;
+ Switch(Switch&&) = delete;
~Switch() override;
- /// The switch merge target
- Branch merge = {};
+ Switch& operator=(const Switch&) = delete;
+ Switch& operator=(Switch&&) = delete;
- /// The switch case statements
- utils::Vector<Case, 4> cases;
+ /// @returns the switch merge branch
+ const Branch& Merge() const { return merge_; }
+ /// @returns the switch merge branch
+ Branch& Merge() { return merge_; }
- /// Value holding the condition result
- const Value* condition = nullptr;
+ /// @returns the switch cases
+ 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
diff --git a/src/tint/ir/test_helper.h b/src/tint/ir/test_helper.h
index d9055ce..b7279f3 100644
--- a/src/tint/ir/test_helper.h
+++ b/src/tint/ir/test_helper.h
@@ -33,7 +33,6 @@
class TestHelperBase : public BASE, public ProgramBuilder {
public:
TestHelperBase() = default;
-
~TestHelperBase() override = default;
/// Build the module, cleaning up the program before returning.
diff --git a/src/tint/ir/to_program.cc b/src/tint/ir/to_program.cc
index b1aa67f..9be189c 100644
--- a/src/tint/ir/to_program.cc
+++ b/src/tint/ir/to_program.cc
@@ -91,14 +91,14 @@
const ast::Function* Fn(const Function* fn) {
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
utils::Vector<const ast::Parameter*, 1> params{};
- auto ret_ty = Type(fn->return_type);
+ auto ret_ty = Type(fn->ReturnType());
if (!ret_ty) {
return nullptr;
}
- auto* body = FlowNodeGraph(fn->start_target);
+ auto* body = FlowNodeGraph(fn->StartTarget());
if (!body) {
return nullptr;
}
@@ -126,7 +126,7 @@
branch->target,
[&](const ir::Block* block) {
- for (auto* inst : block->instructions) {
+ for (const auto* inst : block->Instructions()) {
auto stmt = Stmt(inst);
if (TINT_UNLIKELY(!stmt)) {
return kError;
@@ -135,7 +135,7 @@
stmts.Push(s);
}
}
- branch = &block->branch;
+ branch = &block->Branch();
return kContinue;
},
@@ -145,8 +145,8 @@
return kError;
}
stmts.Push(stmt);
- branch = &if_->merge;
- return branch->target->inbound_branches.IsEmpty() ? kStop : kContinue;
+ branch = &if_->Merge();
+ return branch->target->InboundBranches().IsEmpty() ? kStop : kContinue;
},
[&](const ir::Switch* switch_) {
@@ -155,8 +155,8 @@
return kError;
}
stmts.Push(stmt);
- branch = &switch_->merge;
- return branch->target->inbound_branches.IsEmpty() ? kStop : kContinue;
+ branch = &switch_->Merge();
+ return branch->target->InboundBranches().IsEmpty() ? kStop : kContinue;
},
[&](const ir::FunctionTerminator*) {
@@ -189,25 +189,25 @@
const ast::IfStatement* If(const ir::If* i) {
SCOPED_NESTING();
- auto* cond = Expr(i->condition);
- auto* t = FlowNodeGraph(i->true_.target, i->merge.target);
+ auto* cond = Expr(i->Condition());
+ auto* t = FlowNodeGraph(i->True().target, i->Merge().target);
if (TINT_UNLIKELY(!t)) {
return nullptr;
}
- 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 (!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
// 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 &&
- NextNonEmptyNode(i->merge.target) == NextNonEmptyNode(else_if->merge.target)) {
+ NextNonEmptyNode(i->Merge().target) == NextNonEmptyNode(else_if->Merge().target)) {
auto* f = If(else_if);
if (!f) {
return nullptr;
}
return b.If(cond, t, b.Else(f));
} else {
- auto* f = FlowNodeGraph(i->false_.target, i->merge.target);
+ auto* f = FlowNodeGraph(i->False().target, i->Merge().target);
if (!f) {
return nullptr;
}
@@ -221,16 +221,16 @@
const ast::SwitchStatement* Switch(const ir::Switch* s) {
SCOPED_NESTING();
- auto* cond = Expr(s->condition);
+ auto* cond = Expr(s->Condition());
if (!cond) {
return nullptr;
}
- auto cases = utils::Transform(
- s->cases, //
+ auto cases = utils::Transform<1>(
+ s->Cases(), //
[&](const ir::Switch::Case& c) -> const tint::ast::CaseStatement* {
SCOPED_NESTING();
- auto* body = FlowNodeGraph(c.start.target, s->merge.target);
+ auto* body = FlowNodeGraph(c.start.target, s->Merge().target);
if (!body) {
return nullptr;
}
@@ -292,10 +292,10 @@
bool IsEmpty(const ir::FlowNode* node, const ir::FlowNode* stop_at) {
while (node != stop_at) {
if (auto* block = node->As<ir::Block>()) {
- if (block->instructions.Length() > 0) {
+ if (!block->Instructions().IsEmpty()) {
return false;
}
- node = block->branch.target;
+ node = block->Branch().target;
} else {
return false;
}
@@ -307,13 +307,13 @@
const ir::FlowNode* NextNonEmptyNode(const ir::FlowNode* node) {
while (node) {
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.
if (!inst->Is<ir::Load>()) {
return node;
}
}
- node = block->branch.target;
+ node = block->Branch().target;
} else {
return node;
}
@@ -351,8 +351,8 @@
}
auto ty = Type(ptr->StoreType());
const ast::Expression* init = nullptr;
- if (var->initializer) {
- init = Expr(var->initializer);
+ if (var->Initializer()) {
+ init = Expr(var->Initializer());
if (!init) {
return nullptr;
}
@@ -368,18 +368,19 @@
}
const ast::AssignmentStatement* Store(const ir::Store* store) {
- auto* expr = Expr(store->from);
- return b.Assign(NameOf(store->to), expr);
+ auto* expr = Expr(store->From());
+ return b.Assign(NameOf(store->To()), expr);
}
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)) {
return nullptr;
}
return tint::Switch(
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) {
UNHANDLED_CASE(call);
return nullptr;
@@ -401,18 +402,18 @@
const ast::Expression* ConstExpr(const ir::Constant* c) {
return tint::Switch(
c->Type(), //
- [&](const type::I32*) { return b.Expr(c->value->ValueAs<i32>()); },
- [&](const type::U32*) { return b.Expr(c->value->ValueAs<u32>()); },
- [&](const type::F32*) { return b.Expr(c->value->ValueAs<f32>()); },
- [&](const type::F16*) { return b.Expr(c->value->ValueAs<f16>()); },
- [&](const type::Bool*) { return b.Expr(c->value->ValueAs<bool>()); },
+ [&](const type::I32*) { return b.Expr(c->Value()->ValueAs<i32>()); },
+ [&](const type::U32*) { return b.Expr(c->Value()->ValueAs<u32>()); },
+ [&](const type::F32*) { return b.Expr(c->Value()->ValueAs<f32>()); },
+ [&](const type::F16*) { return b.Expr(c->Value()->ValueAs<f16>()); },
+ [&](const type::Bool*) { return b.Expr(c->Value()->ValueAs<bool>()); },
[&](Default) {
UNHANDLED_CASE(c);
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)); }
diff --git a/src/tint/ir/transform/add_empty_entry_point.cc b/src/tint/ir/transform/add_empty_entry_point.cc
index 809a6ad..6788d7c 100644
--- a/src/tint/ir/transform/add_empty_entry_point.cc
+++ b/src/tint/ir/transform/add_empty_entry_point.cc
@@ -29,7 +29,7 @@
void AddEmptyEntryPoint::Run(ir::Module* ir, const DataMap&, DataMap&) const {
for (auto* func : ir->functions) {
- if (func->pipeline_stage != Function::PipelineStage::kUndefined) {
+ if (func->Stage() != Function::PipelineStage::kUndefined) {
return;
}
}
@@ -38,7 +38,7 @@
auto* ep =
builder.CreateFunction(ir->symbols.New("unused_entry_point"), ir->types.Get<type::Void>(),
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);
}
diff --git a/src/tint/ir/transform/add_empty_entry_point_test.cc b/src/tint/ir/transform/add_empty_entry_point_test.cc
index baba8e0..a363d83 100644
--- a/src/tint/ir/transform/add_empty_entry_point_test.cc
+++ b/src/tint/ir/transform/add_empty_entry_point_test.cc
@@ -40,7 +40,7 @@
TEST_F(IR_AddEmptyEntryPointTest, ExistingEntryPoint) {
auto* ep = b.CreateFunction(mod.symbols.New("main"), mod.types.Get<type::Void>(),
Function::PipelineStage::kFragment);
- b.Branch(ep->start_target, ep->end_target);
+ ep->StartTarget()->BranchTo(ep->EndTarget());
mod.functions.Push(ep);
auto* expect = R"(
diff --git a/src/tint/ir/unary.cc b/src/tint/ir/unary.cc
index db13d5d..2a0ee94 100644
--- a/src/tint/ir/unary.cc
+++ b/src/tint/ir/unary.cc
@@ -19,8 +19,8 @@
namespace tint::ir {
-Unary::Unary(Kind k, const type::Type* res_ty, Value* val)
- : kind(k), result_type(res_ty), val_(val) {
+Unary::Unary(enum Kind k, const type::Type* res_ty, Value* val)
+ : kind_(k), result_type_(res_ty), val_(val) {
TINT_ASSERT(IR, val_);
val_->AddUsage(this);
}
diff --git a/src/tint/ir/unary.h b/src/tint/ir/unary.h
index 46edd45..98ad9b8 100644
--- a/src/tint/ir/unary.h
+++ b/src/tint/ir/unary.h
@@ -33,7 +33,7 @@
/// @param kind the kind of unary instruction
/// @param result_type the result type
/// @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(Unary&& inst) = delete;
~Unary() override;
@@ -42,19 +42,18 @@
Unary& operator=(Unary&& inst) = delete;
/// @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
const Value* Val() const { return val_; }
- /// the kind of unary instruction
- Kind kind = Kind::kNegation;
-
- /// the result type of the instruction
- const type::Type* result_type = nullptr;
+ /// @returns the kind of unary instruction
+ enum Kind Kind() const { return kind_; }
private:
- Value* val_ = nullptr;
+ enum Kind kind_;
+ const type::Type* result_type_;
+ Value* val_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/unary_test.cc b/src/tint/ir/unary_test.cc
index 280c7de..6cefed3 100644
--- a/src/tint/ir/unary_test.cc
+++ b/src/tint/ir/unary_test.cc
@@ -29,10 +29,10 @@
const auto* inst = b.Complement(b.ir.types.Get<type::I32>(), b.Constant(4_i));
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>());
- auto lhs = inst->Val()->As<Constant>()->value;
+ auto lhs = inst->Val()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -43,10 +43,10 @@
const auto* inst = b.Negation(b.ir.types.Get<type::I32>(), b.Constant(4_i));
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>());
- auto lhs = inst->Val()->As<Constant>()->value;
+ auto lhs = inst->Val()->As<Constant>()->Value();
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
}
@@ -56,7 +56,7 @@
Builder b{mod};
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_EQ(inst->Val()->Usage().Length(), 1u);
diff --git a/src/tint/ir/user_call.cc b/src/tint/ir/user_call.cc
index f718284..e44e285 100644
--- a/src/tint/ir/user_call.cc
+++ b/src/tint/ir/user_call.cc
@@ -23,7 +23,7 @@
namespace tint::ir {
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;
diff --git a/src/tint/ir/user_call.h b/src/tint/ir/user_call.h
index 5ada8f8..ba52e20 100644
--- a/src/tint/ir/user_call.h
+++ b/src/tint/ir/user_call.h
@@ -36,8 +36,11 @@
UserCall& operator=(const UserCall& inst) = delete;
UserCall& operator=(UserCall&& inst) = delete;
- /// The function name
- Symbol name;
+ /// @returns the called function name
+ Symbol Name() const { return name_; }
+
+ private:
+ Symbol name_;
};
} // namespace tint::ir
diff --git a/src/tint/ir/var.cc b/src/tint/ir/var.cc
index 9bf4b8d..9b43329 100644
--- a/src/tint/ir/var.cc
+++ b/src/tint/ir/var.cc
@@ -19,8 +19,14 @@
namespace tint::ir {
-Var::Var(const type::Type* ty) : type(ty) {}
+Var::Var(const type::Type* ty) : type_(ty) {}
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
diff --git a/src/tint/ir/var.h b/src/tint/ir/var.h
index c874a62..67ccf0d 100644
--- a/src/tint/ir/var.h
+++ b/src/tint/ir/var.h
@@ -36,13 +36,17 @@
Var& operator=(Var&& inst) = delete;
/// @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
- const type::Type* type = nullptr;
+ /// Sets the var initializer
+ /// @param initializer the initializer
+ void SetInitializer(Value* initializer);
+ /// @returns the initializer
+ const Value* Initializer() const { return initializer_; }
- /// The optional initializer
- Value* initializer = nullptr;
+ private:
+ const type::Type* type_;
+ Value* initializer_ = nullptr;
};
} // namespace tint::ir
diff --git a/src/tint/transform/manager_test.cc b/src/tint/transform/manager_test.cc
index 3b0ee25..a81f7bf 100644
--- a/src/tint/transform/manager_test.cc
+++ b/src/tint/transform/manager_test.cc
@@ -52,7 +52,7 @@
ir::Builder builder(*mod);
auto* func =
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);
}
};
@@ -70,7 +70,7 @@
ir::Builder builder(mod);
auto* func =
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);
return mod;
}
@@ -102,9 +102,10 @@
manager.Add<IR_AddFunction>();
manager.Run(&ir, {}, outputs);
+
ASSERT_EQ(ir.functions.Length(), 2u);
- EXPECT_EQ(ir.functions[0]->name.Name(), "main");
- EXPECT_EQ(ir.functions[1]->name.Name(), "ir_func");
+ EXPECT_EQ(ir.functions[0]->Name().Name(), "main");
+ EXPECT_EQ(ir.functions[1]->Name().Name(), "ir_func");
}
TEST_F(TransformManagerTest, AST_MixedTransforms_AST_Before_IR) {
@@ -149,9 +150,9 @@
manager.Run(&ir, {}, outputs);
ASSERT_EQ(ir.functions.Length(), 3u);
- EXPECT_EQ(ir.functions[0]->name.Name(), "ast_func");
- EXPECT_EQ(ir.functions[1]->name.Name(), "main");
- EXPECT_EQ(ir.functions[2]->name.Name(), "ir_func");
+ EXPECT_EQ(ir.functions[0]->Name().Name(), "ast_func");
+ EXPECT_EQ(ir.functions[1]->Name().Name(), "main");
+ EXPECT_EQ(ir.functions[2]->Name().Name(), "ir_func");
}
TEST_F(TransformManagerTest, IR_MixedTransforms_IR_Before_AST) {
@@ -164,9 +165,9 @@
manager.Run(&ir, {}, outputs);
ASSERT_EQ(ir.functions.Length(), 3u);
- EXPECT_EQ(ir.functions[0]->name.Name(), "ast_func");
- EXPECT_EQ(ir.functions[1]->name.Name(), "main");
- EXPECT_EQ(ir.functions[2]->name.Name(), "ir_func");
+ EXPECT_EQ(ir.functions[0]->Name().Name(), "ast_func");
+ EXPECT_EQ(ir.functions[1]->Name().Name(), "main");
+ EXPECT_EQ(ir.functions[2]->Name().Name(), "ir_func");
}
#endif // TINT_BUILD_IR
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir.cc b/src/tint/writer/spirv/ir/generator_impl_ir.cc
index 4ec4d9d..bd9a735 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir.cc
@@ -19,6 +19,7 @@
#include "src/tint/ir/block.h"
#include "src/tint/ir/function_terminator.h"
#include "src/tint/ir/if.h"
+#include "src/tint/ir/load.h"
#include "src/tint/ir/module.h"
#include "src/tint/ir/store.h"
#include "src/tint/ir/transform/add_empty_entry_point.h"
@@ -109,7 +110,7 @@
}
uint32_t GeneratorImplIr::Constant(const ir::Constant* constant) {
- return Constant(constant->value);
+ return Constant(constant->Value());
}
uint32_t GeneratorImplIr::Constant(const constant::Value* constant) {
@@ -213,15 +214,15 @@
auto id = module_.NextId();
// 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.
- if (func->pipeline_stage != ir::Function::PipelineStage::kUndefined) {
+ if (func->Stage() != ir::Function::PipelineStage::kUndefined) {
EmitEntryPoint(func, id);
}
// 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).
// TODO(jrprice): Add the parameter types when they are supported in the IR.
@@ -247,7 +248,7 @@
TINT_DEFER(current_function_ = Function());
// Emit the body of the function.
- EmitBlock(func->start_target);
+ EmitBlock(func->StartTarget());
// Add the function to the module.
module_.PushFunction(current_function_);
@@ -255,13 +256,13 @@
void GeneratorImplIr::EmitEntryPoint(const ir::Function* func, uint32_t id) {
SpvExecutionModel stage = SpvExecutionModelMax;
- switch (func->pipeline_stage) {
+ switch (func->Stage()) {
case ir::Function::PipelineStage::kCompute: {
stage = SpvExecutionModelGLCompute;
module_.PushExecutionMode(
spv::Op::OpExecutionMode,
- {id, U32Operand(SpvExecutionModeLocalSize), func->workgroup_size->at(0),
- func->workgroup_size->at(1), func->workgroup_size->at(2)});
+ {id, U32Operand(SpvExecutionModeLocalSize), func->WorkgroupSize()->at(0),
+ func->WorkgroupSize()->at(1), func->WorkgroupSize()->at(2)});
break;
}
case ir::Function::PipelineStage::kFragment: {
@@ -281,7 +282,7 @@
}
// 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) {
@@ -292,10 +293,11 @@
}
// Emit the instructions.
- for (auto* inst : block->instructions) {
+ for (const auto* inst : block->Instructions()) {
auto result = Switch(
inst, //
[&](const ir::Binary* b) { return EmitBinary(b); },
+ [&](const ir::Load* l) { return EmitLoad(l); },
[&](const ir::Store* s) {
EmitStore(s);
return 0u;
@@ -311,43 +313,43 @@
// Handle the branch at the end of the block.
Switch(
- block->branch.target,
+ block->Branch().target,
[&](const ir::Block* b) { current_function_.push_inst(spv::Op::OpBranch, {Label(b)}); },
[&](const ir::If* i) { EmitIf(i); },
[&](const ir::FunctionTerminator*) {
// 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";
}
current_function_.push_inst(spv::Op::OpReturn, {});
},
[&](Default) {
- if (!block->branch.target) {
+ if (!block->Branch().target) {
// A block may not have an outward branch (e.g. an unreachable merge block).
current_function_.push_inst(spv::Op::OpUnreachable, {});
} else {
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) {
- auto* merge_block = i->merge.target->As<ir::Block>();
- auto* true_block = i->true_.target->As<ir::Block>();
- auto* false_block = i->false_.target->As<ir::Block>();
+ auto* merge_block = i->Merge().target->As<ir::Block>();
+ auto* true_block = i->True().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:
// 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.
uint32_t merge_label = Label(merge_block);
uint32_t true_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);
}
- 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);
}
@@ -355,7 +357,7 @@
current_function_.push_inst(spv::Op::OpSelectionMerge,
{merge_label, U32Operand(SpvSelectionControlMaskNone)});
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.
if (true_label != merge_label) {
@@ -374,7 +376,7 @@
// Determine the opcode.
spv::Op op = spv::Op::Max;
- switch (binary->kind) {
+ switch (binary->Kind()) {
case ir::Binary::Kind::kAdd: {
op = binary->Type()->is_integer_scalar_or_vector() ? spv::Op::OpIAdd : spv::Op::OpFAdd;
break;
@@ -385,7 +387,7 @@
}
default: {
TINT_ICE(Writer, diagnostics_)
- << "unimplemented binary instruction: " << static_cast<uint32_t>(binary->kind);
+ << "unimplemented binary instruction: " << static_cast<uint32_t>(binary->Kind());
}
}
@@ -396,8 +398,14 @@
return id;
}
+uint32_t GeneratorImplIr::EmitLoad(const ir::Load* load) {
+ auto id = module_.NextId();
+ current_function_.push_inst(spv::Op::OpLoad, {Type(load->Type()), id, Value(load->From())});
+ return id;
+}
+
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) {
@@ -409,8 +417,8 @@
if (ptr->AddressSpace() == builtin::AddressSpace::kFunction) {
TINT_ASSERT(Writer, current_function_);
current_function_.push_var({ty, id, U32Operand(SpvStorageClassFunction)});
- if (var->initializer) {
- current_function_.push_inst(spv::Op::OpStore, {id, Value(var->initializer)});
+ if (var->Initializer()) {
+ current_function_.push_inst(spv::Op::OpStore, {id, Value(var->Initializer())});
}
} else {
TINT_ICE(Writer, diagnostics_)
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir.h b/src/tint/writer/spirv/ir/generator_impl_ir.h
index 66ffe48..b72201f 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir.h
+++ b/src/tint/writer/spirv/ir/generator_impl_ir.h
@@ -32,6 +32,7 @@
class Block;
class If;
class Function;
+class Load;
class Module;
class Store;
class Value;
@@ -106,6 +107,11 @@
/// @returns the result ID of the instruction
uint32_t EmitBinary(const ir::Binary* binary);
+ /// Emit a load instruction.
+ /// @param load the load instruction to emit
+ /// @returns the result ID of the instruction
+ uint32_t EmitLoad(const ir::Load* load);
+
/// Emit a store instruction.
/// @param store the store instruction to emit
void EmitStore(const ir::Store* store);
@@ -151,25 +157,6 @@
}
};
- /// ConstantHasher provides a hash function for a constant::Value pointer, hashing the value
- /// instead of the pointer itself.
- struct ConstantHasher {
- /// @param c the constant::Value pointer to create a hash for
- /// @return the hash value
- inline std::size_t operator()(const constant::Value* c) const { return c->Hash(); }
- };
-
- /// ConstantEquals provides an equality function for two constant::Value pointers, comparing
- /// their values instead of the pointers.
- struct ConstantEquals {
- /// @param a the first constant::Value pointer to compare
- /// @param b the second constant::Value pointer to compare
- /// @return the hash value
- inline bool operator()(const constant::Value* a, const constant::Value* b) const {
- return a->Equal(b);
- }
- };
-
/// The map of types to their result IDs.
utils::Hashmap<const type::Type*, uint32_t, 8> types_;
@@ -177,7 +164,7 @@
utils::Hashmap<FunctionType, uint32_t, 8, FunctionType::Hasher> function_types_;
/// The map of constants to their result IDs.
- utils::Hashmap<const constant::Value*, uint32_t, 16, ConstantHasher, ConstantEquals> constants_;
+ utils::Hashmap<const constant::Value*, uint32_t, 16> constants_;
/// The map of instructions to their result IDs.
utils::Hashmap<const ir::Instruction*, uint32_t, 8> instructions_;
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc
index 30dc059..e9231f3 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc
@@ -21,10 +21,10 @@
TEST_F(SpvGeneratorImplTest, Binary_Add_I32) {
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(
- b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i)));
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -43,10 +43,10 @@
TEST_F(SpvGeneratorImplTest, Binary_Add_U32) {
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(
- b.Add(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u)));
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Add(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -65,10 +65,10 @@
TEST_F(SpvGeneratorImplTest, Binary_Add_F32) {
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(
- b.Add(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f)));
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Add(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -87,10 +87,10 @@
TEST_F(SpvGeneratorImplTest, Binary_Sub_I32) {
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(
- b.Subtract(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i)));
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Subtract(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(2_i))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -109,10 +109,10 @@
TEST_F(SpvGeneratorImplTest, Binary_Sub_U32) {
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(
- b.Subtract(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u)));
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Subtract(mod.types.Get<type::U32>(), b.Constant(1_u), b.Constant(2_u))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -131,10 +131,10 @@
TEST_F(SpvGeneratorImplTest, Binary_Sub_F32) {
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(
- b.Subtract(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f)));
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Subtract(mod.types.Get<type::F32>(), b.Constant(1_f), b.Constant(2_f))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -153,17 +153,17 @@
TEST_F(SpvGeneratorImplTest, Binary_Sub_Vec2i) {
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.Create<constant::Composite>(
+ auto* lhs = mod.constants_arena.Create<constant::Composite>(
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);
- auto* rhs = mod.constants.Create<constant::Composite>(
+ utils::Vector{b.Constant(42_i)->Value(), b.Constant(-1_i)->Value()}, false, false);
+ auto* rhs = mod.constants_arena.Create<constant::Composite>(
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);
- func->start_target->instructions.Push(
- b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u), b.Constant(lhs),
- b.Constant(rhs)));
+ utils::Vector{b.Constant(0_i)->Value(), b.Constant(-43_i)->Value()}, false, false);
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::I32>(), 2u),
+ b.Constant(lhs), b.Constant(rhs))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -187,21 +187,21 @@
TEST_F(SpvGeneratorImplTest, Binary_Sub_Vec4f) {
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.Create<constant::Composite>(
+ auto* lhs = mod.constants_arena.Create<constant::Composite>(
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,
- b.Constant(1.25_f)->value},
+ utils::Vector{b.Constant(42_f)->Value(), b.Constant(-1_f)->Value(),
+ b.Constant(0_f)->Value(), b.Constant(1.25_f)->Value()},
false, false);
- auto* rhs = mod.constants.Create<constant::Composite>(
+ auto* rhs = mod.constants_arena.Create<constant::Composite>(
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,
- b.Constant(1_f)->value},
+ utils::Vector{b.Constant(0_f)->Value(), b.Constant(1.25_f)->Value(),
+ b.Constant(-42_f)->Value(), b.Constant(1_f)->Value()},
false, false);
- func->start_target->instructions.Push(
- b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u), b.Constant(lhs),
- b.Constant(rhs)));
+ func->StartTarget()->SetInstructions(
+ utils::Vector{b.Subtract(mod.types.Get<type::Vector>(mod.types.Get<type::F32>(), 4u),
+ b.Constant(lhs), b.Constant(rhs))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -227,11 +227,10 @@
TEST_F(SpvGeneratorImplTest, Binary_Chain) {
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));
- func->start_target->instructions.Push(a);
- func->start_target->instructions.Push(b.Add(mod.types.Get<type::I32>(), a, a));
+ func->StartTarget()->SetInstructions(utils::Vector{a, b.Add(mod.types.Get<type::I32>(), a, a)});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_constant_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_constant_test.cc
index 95fce03..6ab48aa 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_constant_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_constant_test.cc
@@ -65,9 +65,9 @@
TEST_F(SpvGeneratorImplTest, Constant_Vec4Bool) {
auto* t = b.Constant(true);
auto* f = b.Constant(false);
- auto* v = mod.constants.Create<constant::Composite>(
+ auto* v = mod.constants_arena.Create<constant::Composite>(
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));
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeBool
%2 = OpTypeVector %3 4
@@ -81,8 +81,9 @@
auto* i = mod.types.Get<type::I32>();
auto* i_42 = b.Constant(i32(42));
auto* i_n1 = b.Constant(i32(-1));
- auto* v = mod.constants.Create<constant::Composite>(
- mod.types.Get<type::Vector>(i, 2u), utils::Vector{i_42->value, i_n1->value}, false, false);
+ 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);
generator_.Constant(b.Constant(v));
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeInt 32 1
%2 = OpTypeVector %3 2
@@ -97,9 +98,9 @@
auto* u_42 = b.Constant(u32(42));
auto* u_0 = b.Constant(u32(0));
auto* u_4b = b.Constant(u32(4000000000));
- auto* v = mod.constants.Create<constant::Composite>(
- mod.types.Get<type::Vector>(u, 3u), utils::Vector{u_42->value, u_0->value, u_4b->value},
- false, true);
+ 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()}, false, true);
generator_.Constant(b.Constant(v));
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeInt 32 0
%2 = OpTypeVector %3 3
@@ -116,9 +117,9 @@
auto* f_0 = b.Constant(f32(0));
auto* f_q = b.Constant(f32(0.25));
auto* f_n1 = b.Constant(f32(-1));
- auto* v = mod.constants.Create<constant::Composite>(
+ auto* v = mod.constants_arena.Create<constant::Composite>(
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));
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeFloat 32
%2 = OpTypeVector %3 4
@@ -134,8 +135,9 @@
auto* h = mod.types.Get<type::F16>();
auto* h_42 = b.Constant(f16(42));
auto* h_q = b.Constant(f16(0.25));
- auto* v = mod.constants.Create<constant::Composite>(
- mod.types.Get<type::Vector>(h, 2u), utils::Vector{h_42->value, h_q->value}, false, false);
+ 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);
generator_.Constant(b.Constant(v));
EXPECT_EQ(DumpTypes(), R"(%3 = OpTypeFloat 16
%2 = OpTypeVector %3 2
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
index 77b4a62..d2af246 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
@@ -19,7 +19,7 @@
TEST_F(SpvGeneratorImplTest, Function_Empty) {
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);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -35,7 +35,7 @@
// Test that we do not emit the same function type more than once.
TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) {
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);
@@ -48,7 +48,7 @@
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Compute) {
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
ir::Function::PipelineStage::kCompute, {{32, 4, 1}});
- b.Branch(func->start_target, func->end_target);
+ func->StartTarget()->BranchTo(func->EndTarget());
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint GLCompute %1 "main"
@@ -66,7 +66,7 @@
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Fragment) {
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
ir::Function::PipelineStage::kFragment);
- b.Branch(func->start_target, func->end_target);
+ func->StartTarget()->BranchTo(func->EndTarget());
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Fragment %1 "main"
@@ -84,7 +84,7 @@
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Vertex) {
auto* func = b.CreateFunction(mod.symbols.Register("main"), mod.types.Get<type::Void>(),
ir::Function::PipelineStage::kVertex);
- b.Branch(func->start_target, func->end_target);
+ func->StartTarget()->BranchTo(func->EndTarget());
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Vertex %1 "main"
@@ -101,15 +101,15 @@
TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Multiple) {
auto* f1 = b.CreateFunction(mod.symbols.Register("main1"), mod.types.Get<type::Void>(),
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>(),
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>(),
ir::Function::PipelineStage::kFragment);
- b.Branch(f3->start_target, f3->end_target);
+ f3->StartTarget()->BranchTo(f3->EndTarget());
generator_.EmitFunction(f1);
generator_.EmitFunction(f2);
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc
index 7b41184..fa8cc6b 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc
@@ -23,11 +23,11 @@
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
auto* i = b.CreateIf(b.Constant(true));
- b.Branch(i->true_.target->As<ir::Block>(), i->merge.target);
- b.Branch(i->false_.target->As<ir::Block>(), i->merge.target);
- b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
+ i->True().target->As<ir::Block>()->BranchTo(i->Merge().target);
+ i->False().target->As<ir::Block>()->BranchTo(i->Merge().target);
+ i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
- b.Branch(func->start_target, i);
+ func->StartTarget()->BranchTo(i);
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -49,15 +49,15 @@
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
auto* i = b.CreateIf(b.Constant(true));
- b.Branch(i->false_.target->As<ir::Block>(), i->merge.target);
- b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
+ i->False().target->As<ir::Block>()->BranchTo(i->Merge().target);
+ i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
- auto* true_block = i->true_.target->As<ir::Block>();
- true_block->instructions.Push(
- b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i)));
- b.Branch(true_block, i->merge.target);
+ auto* true_block = i->True().target->As<ir::Block>();
+ true_block->SetInstructions(
+ utils::Vector{b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i))});
+ true_block->BranchTo(i->Merge().target);
- b.Branch(func->start_target, i);
+ func->StartTarget()->BranchTo(i);
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -84,15 +84,15 @@
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
auto* i = b.CreateIf(b.Constant(true));
- b.Branch(i->true_.target->As<ir::Block>(), i->merge.target);
- b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
+ i->True().target->As<ir::Block>()->BranchTo(i->Merge().target);
+ i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
- auto* false_block = i->false_.target->As<ir::Block>();
- false_block->instructions.Push(
- b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i)));
- b.Branch(false_block, i->merge.target);
+ auto* false_block = i->False().target->As<ir::Block>();
+ false_block->SetInstructions(
+ utils::Vector{b.Add(mod.types.Get<type::I32>(), b.Constant(1_i), b.Constant(1_i))});
+ false_block->BranchTo(i->Merge().target);
- b.Branch(func->start_target, i);
+ func->StartTarget()->BranchTo(i);
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -119,11 +119,11 @@
auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
auto* i = b.CreateIf(b.Constant(true));
- b.Branch(i->true_.target->As<ir::Block>(), func->end_target);
- b.Branch(i->false_.target->As<ir::Block>(), func->end_target);
- i->merge.target->As<ir::Block>()->branch.target = nullptr;
+ i->True().target->As<ir::Block>()->BranchTo(func->EndTarget());
+ i->False().target->As<ir::Block>()->BranchTo(func->EndTarget());
+ i->Merge().target->As<ir::Block>()->BranchTo(nullptr);
- b.Branch(func->start_target, i);
+ func->StartTarget()->BranchTo(i);
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
index ff94862..20e5167 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
@@ -22,12 +22,11 @@
TEST_F(SpvGeneratorImplTest, FunctionVar_NoInit) {
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>(
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
- auto* v = b.Declare(ty);
- func->start_target->instructions.Push(v);
+ func->StartTarget()->SetInstructions(utils::Vector{b.Declare(ty)});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -45,13 +44,14 @@
TEST_F(SpvGeneratorImplTest, FunctionVar_WithInit) {
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>(
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
auto* v = b.Declare(ty);
- func->start_target->instructions.Push(v);
- v->initializer = b.Constant(42_i);
+ v->SetInitializer(b.Constant(42_i));
+
+ func->StartTarget()->SetInstructions(utils::Vector{v});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -71,12 +71,12 @@
TEST_F(SpvGeneratorImplTest, FunctionVar_Name) {
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>(
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
auto* v = b.Declare(ty);
- func->start_target->instructions.Push(v);
+ func->StartTarget()->SetInstructions(utils::Vector{v});
mod.SetName(v, "myvar");
generator_.EmitFunction(func);
@@ -96,22 +96,22 @@
TEST_F(SpvGeneratorImplTest, FunctionVar_DeclInsideBlock) {
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>(
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
auto* v = b.Declare(ty);
- v->initializer = b.Constant(42_i);
+ v->SetInitializer(b.Constant(42_i));
auto* i = b.CreateIf(b.Constant(true));
- b.Branch(i->false_.target->As<ir::Block>(), func->end_target);
- b.Branch(i->merge.target->As<ir::Block>(), func->end_target);
+ i->False().target->As<ir::Block>()->BranchTo(func->EndTarget());
+ i->Merge().target->As<ir::Block>()->BranchTo(func->EndTarget());
- auto* true_block = i->true_.target->As<ir::Block>();
- true_block->instructions.Push(v);
- b.Branch(true_block, i->merge.target);
+ auto* true_block = i->True().target->As<ir::Block>();
+ true_block->SetInstructions(utils::Vector{v});
+ true_block->BranchTo(i->Merge().target);
- b.Branch(func->start_target, i);
+ func->StartTarget()->BranchTo(i);
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@@ -138,15 +138,39 @@
)");
}
+TEST_F(SpvGeneratorImplTest, FunctionVar_Load) {
+ auto* func = b.CreateFunction(mod.symbols.Register("foo"), mod.types.Get<type::Void>());
+ func->StartTarget()->BranchTo(func->EndTarget());
+
+ auto* store_ty = mod.types.Get<type::I32>();
+ auto* ty = mod.types.Get<type::Pointer>(store_ty, builtin::AddressSpace::kFunction,
+ builtin::Access::kReadWrite);
+ auto* v = b.Declare(ty);
+ func->StartTarget()->SetInstructions(utils::Vector{v, b.Load(v)});
+
+ generator_.EmitFunction(func);
+ EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
+%2 = OpTypeVoid
+%3 = OpTypeFunction %2
+%7 = OpTypeInt 32 1
+%6 = OpTypePointer Function %7
+%1 = OpFunction %2 None %3
+%4 = OpLabel
+%5 = OpVariable %6 Function
+%8 = OpLoad %7 %5
+OpReturn
+OpFunctionEnd
+)");
+}
+
TEST_F(SpvGeneratorImplTest, FunctionVar_Store) {
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>(
mod.types.Get<type::I32>(), builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
auto* v = b.Declare(ty);
- func->start_target->instructions.Push(v);
- func->start_target->instructions.Push(b.Store(v, b.Constant(42_i)));
+ func->StartTarget()->SetInstructions(utils::Vector{v, b.Store(v, b.Constant(42_i))});
generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"