[ir] Split Value into Temp and Constant.
This CL pulls the Temp and Constant classes out of the Value base class.
Bug: tint:1718
Change-Id: Ib7bccc7d3190ddd1c5cf493704e778dd23b5c008
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112044
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 06aa483..15532b2 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -656,6 +656,8 @@
ir/builder.h
ir/builder_impl.cc
ir/builder_impl.h
+ ir/constant.cc
+ ir/constant.h
ir/debug.cc
ir/debug.h
ir/disassembler.cc
@@ -674,6 +676,8 @@
ir/module.h
ir/switch.cc
ir/switch.h
+ ir/temp.cc
+ ir/temp.h
ir/terminator.cc
ir/terminator.h
ir/value.cc
@@ -1341,9 +1345,10 @@
if (${TINT_BUILD_IR})
list(APPEND TINT_TEST_SRCS
ir/builder_impl_test.cc
+ ir/constant_test.cc
ir/instruction_test.cc
+ ir/temp_test.cc
ir/test_helper.h
- ir/value_test.cc
)
endif()
diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc
index 2b5dea3..6f5e9c6 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -93,12 +93,12 @@
to->inbound_branches.Push(from);
}
-Value::Id Builder::AllocateValue() {
- return next_value_id++;
+Temp::Id Builder::AllocateTempId() {
+ return next_temp_id++;
}
Instruction Builder::CreateInstruction(Instruction::Kind kind, const Value* lhs, const Value* rhs) {
- return Instruction(kind, MkValue(AllocateValue()), lhs, rhs);
+ return Instruction(kind, Temp(), lhs, rhs);
}
Instruction Builder::And(const Value* lhs, const Value* rhs) {
diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h
index c380980..bc30a95 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -15,12 +15,14 @@
#ifndef SRC_TINT_IR_BUILDER_H_
#define SRC_TINT_IR_BUILDER_H_
+#include "src/tint/ir/constant.h"
#include "src/tint/ir/function.h"
#include "src/tint/ir/if.h"
#include "src/tint/ir/instruction.h"
#include "src/tint/ir/loop.h"
#include "src/tint/ir/module.h"
#include "src/tint/ir/switch.h"
+#include "src/tint/ir/temp.h"
#include "src/tint/ir/terminator.h"
#include "src/tint/ir/value.h"
@@ -83,14 +85,18 @@
/// @param to the node to branch too
void Branch(Block* from, FlowNode* to);
- /// Creates a new Value
- /// @param val the value
- /// @returns the new Value
+ /// Creates a new Constant
+ /// @param val the constant value
+ /// @returns the new constant
template <typename T>
- const Value* MkValue(T val) {
- return ir.values.Create<Value>(val);
+ const ir::Constant* Constant(T val) {
+ return ir.values.Create<ir::Constant>(val);
}
+ /// Creates a new Temporary
+ /// @returns the new temporary
+ const ir::Temp* Temp() { return ir.values.Create<ir::Temp>(AllocateTempId()); }
+
/// Creates an op for `lhs kind rhs`
/// @param kind the kind of operation
/// @param lhs the left-hand-side of the operation
@@ -206,14 +212,14 @@
/// @returns the operation
Instruction Modulo(const Value* lhs, const Value* rhs);
- /// @returns a unique Value id
- Value::Id AllocateValue();
+ /// @returns a unique temp id
+ Temp::Id AllocateTempId();
/// The IR module.
Module ir;
- /// The next Value number to allocate
- Value::Id next_value_id = 1;
+ /// The next temporary number to allocate
+ Temp::Id next_temp_id = 1;
};
} // namespace tint::ir
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index 36bcad8..7700512 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -632,20 +632,20 @@
return tint::Switch( //
lit,
[&](const ast::BoolLiteralExpression* l) {
- return utils::Result<const Value*>(builder.MkValue(l->value));
+ return utils::Result<const Value*>(builder.Constant(l->value));
},
[&](const ast::FloatLiteralExpression* l) {
if (l->suffix == ast::FloatLiteralExpression::Suffix::kF) {
return utils::Result<const Value*>(
- builder.MkValue(f32(static_cast<float>(l->value))));
+ builder.Constant(f32(static_cast<float>(l->value))));
}
- return utils::Result<const Value*>(builder.MkValue(f16(static_cast<float>(l->value))));
+ return utils::Result<const Value*>(builder.Constant(f16(static_cast<float>(l->value))));
},
[&](const ast::IntLiteralExpression* l) {
if (l->suffix == ast::IntLiteralExpression::Suffix::kI) {
- return utils::Result<const Value*>(builder.MkValue(i32(l->value)));
+ return utils::Result<const Value*>(builder.Constant(i32(l->value)));
}
- return utils::Result<const Value*>(builder.MkValue(u32(l->value)));
+ return utils::Result<const Value*>(builder.Constant(u32(l->value)));
},
[&](Default) {
diagnostics_.add_warning(tint::diag::System::IR,
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index edfe7be..79e6e3f 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -101,7 +101,8 @@
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
- auto* instr = flow->condition;
+ ASSERT_TRUE(flow->condition->Is<Constant>());
+ auto* instr = flow->condition->As<Constant>();
ASSERT_TRUE(instr->IsBool());
EXPECT_TRUE(instr->AsBool());
}
@@ -502,7 +503,8 @@
EXPECT_EQ(loop_flow->merge_target->branch_target, nullptr);
// Check condition
- auto* instr = if_flow->condition;
+ ASSERT_TRUE(if_flow->condition->Is<Constant>());
+ auto* instr = if_flow->condition->As<Constant>();
ASSERT_TRUE(instr->IsBool());
EXPECT_TRUE(instr->AsBool());
}
@@ -947,7 +949,8 @@
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
- auto* instr = if_flow->condition;
+ ASSERT_TRUE(if_flow->condition->Is<Constant>());
+ auto* instr = if_flow->condition->As<Constant>();
ASSERT_TRUE(instr->IsBool());
EXPECT_FALSE(instr->AsBool());
}
@@ -1071,7 +1074,8 @@
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
- auto* instr = if_flow->condition;
+ ASSERT_TRUE(if_flow->condition->Is<Constant>());
+ auto* instr = if_flow->condition->As<Constant>();
ASSERT_TRUE(instr->IsBool());
EXPECT_FALSE(instr->AsBool());
}
@@ -1171,7 +1175,8 @@
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
- auto* instr = flow->condition;
+ ASSERT_TRUE(flow->condition->Is<Constant>());
+ auto* instr = flow->condition->As<Constant>();
ASSERT_TRUE(instr->IsI32());
EXPECT_EQ(1_i, instr->AsI32());
}
@@ -1341,7 +1346,8 @@
auto r = b.EmitLiteral(Expr(true));
ASSERT_TRUE(r);
- auto* val = r.Get();
+ ASSERT_TRUE(r.Get()->Is<Constant>());
+ auto* val = r.Get()->As<Constant>();
EXPECT_TRUE(val->IsBool());
EXPECT_TRUE(val->AsBool());
}
@@ -1351,7 +1357,8 @@
auto r = b.EmitLiteral(Expr(false));
ASSERT_TRUE(r);
- auto val = r.Get();
+ ASSERT_TRUE(r.Get()->Is<Constant>());
+ auto* val = r.Get()->As<Constant>();
EXPECT_TRUE(val->IsBool());
EXPECT_FALSE(val->AsBool());
}
@@ -1361,7 +1368,8 @@
auto r = b.EmitLiteral(Expr(1.2_f));
ASSERT_TRUE(r);
- auto val = r.Get();
+ ASSERT_TRUE(r.Get()->Is<Constant>());
+ auto* val = r.Get()->As<Constant>();
EXPECT_TRUE(val->IsF32());
EXPECT_EQ(1.2_f, val->AsF32());
}
@@ -1371,7 +1379,8 @@
auto r = b.EmitLiteral(Expr(1.2_h));
ASSERT_TRUE(r);
- auto val = r.Get();
+ ASSERT_TRUE(r.Get()->Is<Constant>());
+ auto* val = r.Get()->As<Constant>();
EXPECT_TRUE(val->IsF16());
EXPECT_EQ(1.2_h, val->AsF16());
}
@@ -1381,7 +1390,8 @@
auto r = b.EmitLiteral(Expr(-2_i));
ASSERT_TRUE(r);
- auto val = r.Get();
+ ASSERT_TRUE(r.Get()->Is<Constant>());
+ auto* val = r.Get()->As<Constant>();
EXPECT_TRUE(val->IsI32());
EXPECT_EQ(-2_i, val->AsI32());
}
@@ -1391,7 +1401,8 @@
auto r = b.EmitLiteral(Expr(2_u));
ASSERT_TRUE(r);
- auto val = r.Get();
+ ASSERT_TRUE(r.Get()->Is<Constant>());
+ auto* val = r.Get()->As<Constant>();
EXPECT_TRUE(val->IsU32());
EXPECT_EQ(2_u, val->AsU32());
}
diff --git a/src/tint/ir/constant.cc b/src/tint/ir/constant.cc
new file mode 100644
index 0000000..78895bf
--- /dev/null
+++ b/src/tint/ir/constant.cc
@@ -0,0 +1,56 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ir/constant.h"
+
+#include <string>
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Constant);
+
+namespace tint::ir {
+
+Constant::Constant(f32 f) : kind_(Kind::kF32), data_(f) {}
+
+Constant::Constant(f16 f) : kind_(Kind::kF16), data_(f) {}
+
+Constant::Constant(u32 u) : kind_(Kind::kU32), data_(u) {}
+
+Constant::Constant(i32 i) : kind_(Kind::kI32), data_(i) {}
+
+Constant::Constant(bool b) : kind_(Kind::kBool), data_(b) {}
+
+Constant::~Constant() = default;
+
+std::ostream& operator<<(std::ostream& out, const Constant& r) {
+ switch (r.GetKind()) {
+ case Constant::Kind::kF32:
+ out << std::to_string(r.AsF32().value);
+ break;
+ case Constant::Kind::kF16:
+ out << std::to_string(r.AsF16().value);
+ break;
+ case Constant::Kind::kI32:
+ out << std::to_string(r.AsI32().value);
+ break;
+ case Constant::Kind::kU32:
+ out << std::to_string(r.AsU32().value);
+ break;
+ case Constant::Kind::kBool:
+ out << (r.AsBool() ? "true" : "false");
+ break;
+ }
+ return out;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/constant.h b/src/tint/ir/constant.h
new file mode 100644
index 0000000..c06e121
--- /dev/null
+++ b/src/tint/ir/constant.h
@@ -0,0 +1,114 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_IR_CONSTANT_H_
+#define SRC_TINT_IR_CONSTANT_H_
+
+#include <ostream>
+#include <variant>
+
+#include "src/tint/ir/value.h"
+#include "src/tint/number.h"
+
+namespace tint::ir {
+
+/// Constant in the IR. The constant can be one of several types these include, but aren't limited
+/// to, `f32`, `u32`, `bool`. The type of the constant determines the type of data stored.
+class Constant : public Castable<Constant, Value> {
+ public:
+ /// The type of the constant
+ enum class Kind {
+ /// A f32 constant
+ kF32,
+ /// A f16 constant
+ kF16,
+ /// An i32 constant
+ kI32,
+ /// A u32 constant
+ kU32,
+ /// A boolean constant
+ kBool,
+ };
+
+ /// Constructor
+ /// @param b the `bool` constant to store in the constant
+ explicit Constant(bool b);
+
+ /// Constructor
+ /// @param f the `f32` constant to store in the constant
+ explicit Constant(f32 f);
+
+ /// Constructor
+ /// @param f the `f16` constant to store in the constant
+ explicit Constant(f16 f);
+
+ /// Constructor
+ /// @param u the `u32` constant to store in the constant
+ explicit Constant(u32 u);
+
+ /// Constructor
+ /// @param i the `i32` constant to store in the constant
+ explicit Constant(i32 i);
+
+ /// Destructor
+ ~Constant() override;
+
+ Constant(const Constant&) = delete;
+ Constant(Constant&&) = delete;
+
+ Constant& operator=(const Constant&) = delete;
+ Constant& operator=(Constant&&) = delete;
+
+ /// @returns true if this is a f32 constant
+ bool IsF32() const { return kind_ == Kind::kF32; }
+ /// @returns true if this is a f16 constant
+ bool IsF16() const { return kind_ == Kind::kF16; }
+ /// @returns true if this is an i32 constant
+ bool IsI32() const { return kind_ == Kind::kI32; }
+ /// @returns true if this is a u32 constant
+ bool IsU32() const { return kind_ == Kind::kU32; }
+ /// @returns true if this is a bool constant
+ bool IsBool() const { return kind_ == Kind::kBool; }
+
+ /// @returns the kind of constant
+ Kind GetKind() const { return kind_; }
+
+ /// @returns the constant data as a `f32`.
+ /// @note, must only be called if `IsF32()` is true
+ f32 AsF32() const { return std::get<f32>(data_); }
+ /// @returns the constant data as a `f16`.
+ /// @note, must only be called if `IsF16()` is true
+ f16 AsF16() const { return std::get<f16>(data_); }
+ /// @returns the constant data as an `i32`.
+ /// @note, must only be called if `IsI32()` is true
+ i32 AsI32() const { return std::get<i32>(data_); }
+ /// @returns the constant data as a `u32`.
+ /// @note, must only be called if `IsU32()` is true
+ u32 AsU32() const { return std::get<u32>(data_); }
+ /// @returns the constant data as a `bool`.
+ /// @note, must only be called if `IsBool()` is true
+ bool AsBool() const { return std::get<bool>(data_); }
+
+ private:
+ /// The type of data stored in this constant
+ Kind kind_;
+ /// The data stored in the constant
+ std::variant<f32, f16, u32, i32, bool> data_;
+};
+
+std::ostream& operator<<(std::ostream& out, const Constant& r);
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_CONSTANT_H_
diff --git a/src/tint/ir/constant_test.cc b/src/tint/ir/constant_test.cc
new file mode 100644
index 0000000..7b4e224
--- /dev/null
+++ b/src/tint/ir/constant_test.cc
@@ -0,0 +1,125 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <sstream>
+
+#include "src/tint/ir/test_helper.h"
+#include "src/tint/ir/value.h"
+
+namespace tint::ir {
+namespace {
+
+using namespace tint::number_suffixes; // NOLINT
+
+using IR_ConstantTest = TestHelper;
+
+TEST_F(IR_ConstantTest, f32) {
+ auto& b = CreateEmptyBuilder();
+
+ std::stringstream str;
+
+ auto* val = b.builder.Constant(1.2_f);
+ EXPECT_EQ(1.2_f, val->AsF32());
+
+ str << *val;
+ EXPECT_EQ("1.200000", str.str());
+
+ EXPECT_TRUE(val->IsF32());
+ EXPECT_FALSE(val->IsF16());
+ EXPECT_FALSE(val->IsI32());
+ EXPECT_FALSE(val->IsU32());
+ EXPECT_FALSE(val->IsBool());
+}
+
+TEST_F(IR_ConstantTest, f16) {
+ auto& b = CreateEmptyBuilder();
+
+ std::stringstream str;
+
+ auto* val = b.builder.Constant(1.1_h);
+ EXPECT_EQ(1.1_h, val->AsF16());
+
+ str << *val;
+ EXPECT_EQ("1.099609", str.str());
+
+ EXPECT_FALSE(val->IsF32());
+ EXPECT_TRUE(val->IsF16());
+ EXPECT_FALSE(val->IsI32());
+ EXPECT_FALSE(val->IsU32());
+ EXPECT_FALSE(val->IsBool());
+}
+
+TEST_F(IR_ConstantTest, i32) {
+ auto& b = CreateEmptyBuilder();
+
+ std::stringstream str;
+
+ auto* val = b.builder.Constant(1_i);
+ EXPECT_EQ(1_i, val->AsI32());
+
+ str << *val;
+ EXPECT_EQ("1", str.str());
+
+ EXPECT_FALSE(val->IsF32());
+ EXPECT_FALSE(val->IsF16());
+ EXPECT_TRUE(val->IsI32());
+ EXPECT_FALSE(val->IsU32());
+ EXPECT_FALSE(val->IsBool());
+}
+
+TEST_F(IR_ConstantTest, u32) {
+ auto& b = CreateEmptyBuilder();
+
+ std::stringstream str;
+
+ auto* val = b.builder.Constant(2_u);
+ EXPECT_EQ(2_u, val->AsU32());
+
+ str << *val;
+ EXPECT_EQ("2", str.str());
+
+ EXPECT_FALSE(val->IsF32());
+ EXPECT_FALSE(val->IsF16());
+ EXPECT_FALSE(val->IsI32());
+ EXPECT_TRUE(val->IsU32());
+ EXPECT_FALSE(val->IsBool());
+}
+
+TEST_F(IR_ConstantTest, bool) {
+ auto& b = CreateEmptyBuilder();
+
+ std::stringstream str;
+
+ auto* val = b.builder.Constant(false);
+ EXPECT_FALSE(val->AsBool());
+
+ str << *val;
+ EXPECT_EQ("false", str.str());
+
+ str.str("");
+ val = b.builder.Constant(true);
+ EXPECT_TRUE(val->AsBool());
+
+ str << *val;
+ EXPECT_EQ("true", str.str());
+
+ EXPECT_FALSE(val->IsF32());
+ EXPECT_FALSE(val->IsF16());
+ EXPECT_FALSE(val->IsI32());
+ EXPECT_FALSE(val->IsU32());
+ EXPECT_TRUE(val->IsBool());
+}
+
+} // namespace
+} // namespace tint::ir
diff --git a/src/tint/ir/instruction.h b/src/tint/ir/instruction.h
index ea9dec2..1735115 100644
--- a/src/tint/ir/instruction.h
+++ b/src/tint/ir/instruction.h
@@ -17,6 +17,7 @@
#include <ostream>
+#include "src/tint/debug.h"
#include "src/tint/ir/value.h"
#include "src/tint/utils/vector.h"
diff --git a/src/tint/ir/instruction_test.cc b/src/tint/ir/instruction_test.cc
index d93b9c7..d6c8d8a 100644
--- a/src/tint/ir/instruction_test.cc
+++ b/src/tint/ir/instruction_test.cc
@@ -25,21 +25,23 @@
TEST_F(IR_InstructionTest, CreateAnd) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.And(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.And(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kAnd);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -51,21 +53,23 @@
TEST_F(IR_InstructionTest, CreateOr) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Or(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Or(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kOr);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -77,21 +81,23 @@
TEST_F(IR_InstructionTest, CreateXor) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Xor(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Xor(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kXor);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -103,21 +109,23 @@
TEST_F(IR_InstructionTest, CreateLogicalAnd) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.LogicalAnd(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.LogicalAnd(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLogicalAnd);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -129,21 +137,23 @@
TEST_F(IR_InstructionTest, CreateLogicalOr) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.LogicalOr(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.LogicalOr(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLogicalOr);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -155,21 +165,23 @@
TEST_F(IR_InstructionTest, CreateEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Equal(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Equal(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kEqual);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -181,21 +193,23 @@
TEST_F(IR_InstructionTest, CreateNotEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.NotEqual(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.NotEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kNotEqual);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -207,21 +221,23 @@
TEST_F(IR_InstructionTest, CreateLessThan) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.LessThan(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.LessThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLessThan);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -233,21 +249,23 @@
TEST_F(IR_InstructionTest, CreateGreaterThan) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.GreaterThan(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.GreaterThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kGreaterThan);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -259,21 +277,23 @@
TEST_F(IR_InstructionTest, CreateLessThanEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.LessThanEqual(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.LessThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLessThanEqual);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -285,21 +305,23 @@
TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.GreaterThanEqual(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.GreaterThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kGreaterThanEqual);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -311,21 +333,23 @@
TEST_F(IR_InstructionTest, CreateShiftLeft) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.ShiftLeft(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.ShiftLeft(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kShiftLeft);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -337,21 +361,23 @@
TEST_F(IR_InstructionTest, CreateShiftRight) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.ShiftRight(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.ShiftRight(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kShiftRight);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -363,21 +389,23 @@
TEST_F(IR_InstructionTest, CreateAdd) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Add(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Add(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kAdd);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -389,21 +417,23 @@
TEST_F(IR_InstructionTest, CreateSubtract) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Subtract(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Subtract(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kSubtract);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -415,21 +445,23 @@
TEST_F(IR_InstructionTest, CreateMultiply) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Multiply(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Multiply(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kMultiply);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -441,21 +473,23 @@
TEST_F(IR_InstructionTest, CreateDivide) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Divide(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Divide(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kDivide);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
@@ -467,21 +501,23 @@
TEST_F(IR_InstructionTest, CreateModulo) {
auto& b = CreateEmptyBuilder();
- b.builder.next_value_id = Value::Id(42);
- auto instr = b.builder.Modulo(b.builder.MkValue(i32(4)), b.builder.MkValue(i32(2)));
+ b.builder.next_temp_id = Temp::Id(42);
+ auto instr = b.builder.Modulo(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kModulo);
- ASSERT_TRUE(instr.Result()->IsTemp());
- EXPECT_EQ(Value::Id(42), instr.Result()->AsId());
+ ASSERT_TRUE(instr.Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr.HasLHS());
- auto lhs = instr.LHS();
+ ASSERT_TRUE(instr.LHS()->Is<Constant>());
+ auto lhs = instr.LHS()->As<Constant>();
ASSERT_TRUE(lhs->IsI32());
EXPECT_EQ(i32(4), lhs->AsI32());
ASSERT_TRUE(instr.HasRHS());
- auto rhs = instr.RHS();
+ ASSERT_TRUE(instr.RHS()->Is<Constant>());
+ auto rhs = instr.RHS()->As<Constant>();
ASSERT_TRUE(rhs->IsI32());
EXPECT_EQ(i32(2), rhs->AsI32());
diff --git a/src/tint/ir/temp.cc b/src/tint/ir/temp.cc
new file mode 100644
index 0000000..de227ee
--- /dev/null
+++ b/src/tint/ir/temp.cc
@@ -0,0 +1,32 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ir/temp.h"
+
+#include <string>
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Temp);
+
+namespace tint::ir {
+
+Temp::Temp(Id id) : id_(id) {}
+
+Temp::~Temp() = default;
+
+std::ostream& operator<<(std::ostream& out, const Temp& r) {
+ out << "%" << std::to_string(r.AsId());
+ return out;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/temp.h b/src/tint/ir/temp.h
new file mode 100644
index 0000000..b16baf2
--- /dev/null
+++ b/src/tint/ir/temp.h
@@ -0,0 +1,54 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_IR_TEMP_H_
+#define SRC_TINT_IR_TEMP_H_
+
+#include <ostream>
+
+#include "src/tint/ir/value.h"
+
+namespace tint::ir {
+
+/// Temporary value in the IR.
+class Temp : public Castable<Temp, Value> {
+ public:
+ /// A value id.
+ using Id = uint32_t;
+
+ /// Constructor
+ /// @param id the id for the value
+ explicit Temp(Id id);
+
+ /// Destructor
+ ~Temp() override;
+
+ Temp(const Temp&) = delete;
+ Temp(Temp&&) = delete;
+
+ Temp& operator=(const Temp&) = delete;
+ Temp& operator=(Temp&&) = delete;
+
+ /// @returns the value data as an `Id`.
+ Id AsId() const { return id_; }
+
+ private:
+ Id id_ = 0;
+};
+
+std::ostream& operator<<(std::ostream& out, const Temp& r);
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_TEMP_H_
diff --git a/src/tint/ir/temp_test.cc b/src/tint/ir/temp_test.cc
new file mode 100644
index 0000000..b5d817b
--- /dev/null
+++ b/src/tint/ir/temp_test.cc
@@ -0,0 +1,41 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <sstream>
+
+#include "src/tint/ir/temp.h"
+#include "src/tint/ir/test_helper.h"
+
+namespace tint::ir {
+namespace {
+
+using namespace tint::number_suffixes; // NOLINT
+
+using IR_TempTest = TestHelper;
+
+TEST_F(IR_TempTest, id) {
+ auto& b = CreateEmptyBuilder();
+
+ std::stringstream str;
+
+ b.builder.next_temp_id = Temp::Id(4);
+ auto* val = b.builder.Temp();
+ EXPECT_EQ(4u, val->AsId());
+
+ str << *val;
+ EXPECT_EQ("%4", str.str());
+}
+
+} // namespace
+} // namespace tint::ir
diff --git a/src/tint/ir/value.cc b/src/tint/ir/value.cc
index 4177f63..a1431e3 100644
--- a/src/tint/ir/value.cc
+++ b/src/tint/ir/value.cc
@@ -14,50 +14,26 @@
#include "src/tint/ir/value.h"
+#include "src/tint/ir/constant.h"
+#include "src/tint/ir/temp.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Value);
+
namespace tint::ir {
-Value::Value(Id id) : kind_(Kind::kTemp), data_(id) {}
-
-Value::Value(f32 f) : kind_(Kind::kF32), data_(f) {}
-
-Value::Value(f16 f) : kind_(Kind::kF16), data_(f) {}
-
-Value::Value(u32 u) : kind_(Kind::kU32), data_(u) {}
-
-Value::Value(i32 i) : kind_(Kind::kI32), data_(i) {}
-
-Value::Value(bool b) : kind_(Kind::kBool), data_(b) {}
+Value::Value() = default;
Value::~Value() = default;
-Value::Value(const Value& o) = default;
+std::ostream& operator<<(std::ostream& out, const Value& v) {
+ const auto* ptr = &v;
-Value::Value(Value&& o) = default;
-
-Value& Value::operator=(const Value& o) = default;
-
-Value& Value::operator=(Value&& o) = default;
-
-std::ostream& operator<<(std::ostream& out, const Value& r) {
- switch (r.GetKind()) {
- case Value::Kind::kTemp:
- out << "%" << std::to_string(r.AsId());
- break;
- case Value::Kind::kF32:
- out << std::to_string(r.AsF32().value);
- break;
- case Value::Kind::kF16:
- out << std::to_string(r.AsF16().value);
- break;
- case Value::Kind::kI32:
- out << std::to_string(r.AsI32().value);
- break;
- case Value::Kind::kU32:
- out << std::to_string(r.AsU32().value);
- break;
- case Value::Kind::kBool:
- out << (r.AsBool() ? "true" : "false");
- break;
+ if (auto* c = ptr->As<Constant>()) {
+ out << *c;
+ } else if (auto* t = ptr->As<Temp>()) {
+ out << *t;
+ } else {
+ out << "Unknown value";
}
return out;
}
diff --git a/src/tint/ir/value.h b/src/tint/ir/value.h
index bbe8974..326931f 100644
--- a/src/tint/ir/value.h
+++ b/src/tint/ir/value.h
@@ -16,122 +16,29 @@
#define SRC_TINT_IR_VALUE_H_
#include <ostream>
-#include <variant>
-#include "src/tint/number.h"
+#include "src/tint/castable.h"
namespace tint::ir {
-/// Value in the IR. The value can be one of several types these include, but aren't limited
-/// to, `f32`, `u32`, `temp`, `var`. The type of the value determines the type of data stored
-/// in the value.
-class Value {
+/// Value in the IR.
+class Value : public Castable<Value> {
public:
- /// A value id.
- using Id = uint32_t;
-
- /// The type of the value
- enum class Kind {
- /// A temporary allocated value
- kTemp,
- /// A f32 value
- kF32,
- /// A f16 value
- kF16,
- /// An i32 value
- kI32,
- /// A u32 value
- kU32,
- /// A boolean value
- kBool,
- };
-
- /// Constructor
- /// @param id the id for the value
- explicit Value(Id id);
-
- /// Constructor
- /// @param b the `bool` value to store in the value
- explicit Value(bool b);
-
- /// Constructor
- /// @param f the `f32` value to store in the value
- explicit Value(f32 f);
-
- /// Constructor
- /// @param f the `f16` value to store in the value
- explicit Value(f16 f);
-
- /// Constructor
- /// @param u the `u32` value to store in the value
- explicit Value(u32 u);
-
- /// Constructor
- /// @param i the `i32` value to store in the value
- explicit Value(i32 i);
-
/// Destructor
- ~Value();
+ virtual ~Value();
- /// Copy constructor
- /// @param o the value to copy from
- Value(const Value& o);
- /// Move constructor
- /// @param o the value to move from
- Value(Value&& o);
+ Value(const Value&) = delete;
+ Value(Value&&) = delete;
- /// Copy assign
- /// @param o the value to copy from
- /// @returns this
- Value& operator=(const Value& o);
- /// Move assign
- /// @param o the value to move from
- /// @returns this
- Value& operator=(Value&& o);
+ Value& operator=(const Value&) = delete;
+ Value& operator=(Value&&) = delete;
- /// @returns true if this is a temporary value
- bool IsTemp() const { return kind_ == Kind::kTemp; }
- /// @returns true if this is a f32 value
- bool IsF32() const { return kind_ == Kind::kF32; }
- /// @returns true if this is a f16 value
- bool IsF16() const { return kind_ == Kind::kF16; }
- /// @returns true if this is an i32 value
- bool IsI32() const { return kind_ == Kind::kI32; }
- /// @returns true if this is a u32 value
- bool IsU32() const { return kind_ == Kind::kU32; }
- /// @returns true if this is a bool value
- bool IsBool() const { return kind_ == Kind::kBool; }
-
- /// @returns the kind of value
- Kind GetKind() const { return kind_; }
-
- /// @returns the value data as a `f32`.
- /// @note, must only be called if `IsF32()` is true
- f32 AsF32() const { return std::get<f32>(data_); }
- /// @returns the value data as a `f16`.
- /// @note, must only be called if `IsF16()` is true
- f16 AsF16() const { return std::get<f16>(data_); }
- /// @returns the value data as an `i32`.
- /// @note, must only be called if `IsI32()` is true
- i32 AsI32() const { return std::get<i32>(data_); }
- /// @returns the value data as a `u32`.
- /// @note, must only be called if `IsU32()` is true
- u32 AsU32() const { return std::get<u32>(data_); }
- /// @returns the value data as an `Id`.
- /// @note, must only be called if `IsTemp()` is true
- Id AsId() const { return std::get<Id>(data_); }
- /// @returns the value data as a `bool`.
- /// @note, must only be called if `IsBool()` is true
- bool AsBool() const { return std::get<bool>(data_); }
-
- private:
- /// The type of data stored in this value
- Kind kind_;
- /// The data stored in the value
- std::variant<Id, f32, f16, u32, i32, bool> data_;
+ protected:
+ /// Constructor
+ Value();
};
-std::ostream& operator<<(std::ostream& out, const Value& r);
+std::ostream& operator<<(std::ostream& out, const Value& v);
} // namespace tint::ir
diff --git a/src/tint/ir/value_test.cc b/src/tint/ir/value_test.cc
deleted file mode 100644
index 4ffe66e..0000000
--- a/src/tint/ir/value_test.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2022 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <sstream>
-
-#include "src/tint/ir/test_helper.h"
-#include "src/tint/ir/value.h"
-
-namespace tint::ir {
-namespace {
-
-using namespace tint::number_suffixes; // NOLINT
-
-using IR_ValueTest = TestHelper;
-
-TEST_F(IR_ValueTest, f32) {
- std::stringstream str;
-
- Value val(1.2_f);
- EXPECT_EQ(1.2_f, val.AsF32());
-
- str << val;
- EXPECT_EQ("1.200000", str.str());
-
- EXPECT_TRUE(val.IsF32());
- EXPECT_FALSE(val.IsF16());
- EXPECT_FALSE(val.IsI32());
- EXPECT_FALSE(val.IsU32());
- EXPECT_FALSE(val.IsTemp());
- EXPECT_FALSE(val.IsBool());
-}
-
-TEST_F(IR_ValueTest, f16) {
- std::stringstream str;
-
- Value val(1.1_h);
- EXPECT_EQ(1.1_h, val.AsF16());
-
- str << val;
- EXPECT_EQ("1.099609", str.str());
-
- EXPECT_FALSE(val.IsF32());
- EXPECT_TRUE(val.IsF16());
- EXPECT_FALSE(val.IsI32());
- EXPECT_FALSE(val.IsU32());
- EXPECT_FALSE(val.IsTemp());
- EXPECT_FALSE(val.IsBool());
-}
-
-TEST_F(IR_ValueTest, i32) {
- std::stringstream str;
-
- Value val(1_i);
- EXPECT_EQ(1_i, val.AsI32());
-
- str << val;
- EXPECT_EQ("1", str.str());
-
- EXPECT_FALSE(val.IsF32());
- EXPECT_FALSE(val.IsF16());
- EXPECT_TRUE(val.IsI32());
- EXPECT_FALSE(val.IsU32());
- EXPECT_FALSE(val.IsTemp());
- EXPECT_FALSE(val.IsBool());
-}
-
-TEST_F(IR_ValueTest, u32) {
- std::stringstream str;
-
- Value val(2_u);
- EXPECT_EQ(2_u, val.AsU32());
-
- str << val;
- EXPECT_EQ("2", str.str());
-
- EXPECT_FALSE(val.IsF32());
- EXPECT_FALSE(val.IsF16());
- EXPECT_FALSE(val.IsI32());
- EXPECT_TRUE(val.IsU32());
- EXPECT_FALSE(val.IsTemp());
- EXPECT_FALSE(val.IsBool());
-}
-
-TEST_F(IR_ValueTest, id) {
- std::stringstream str;
-
- Value val(Value::Id(4));
- EXPECT_EQ(4u, val.AsId());
-
- str << val;
- EXPECT_EQ("%4", str.str());
-
- EXPECT_FALSE(val.IsF32());
- EXPECT_FALSE(val.IsF16());
- EXPECT_FALSE(val.IsI32());
- EXPECT_FALSE(val.IsU32());
- EXPECT_TRUE(val.IsTemp());
- EXPECT_FALSE(val.IsBool());
-}
-
-TEST_F(IR_ValueTest, bool) {
- std::stringstream str;
-
- Value val(false);
- EXPECT_FALSE(val.AsBool());
-
- str << val;
- EXPECT_EQ("false", str.str());
-
- str.str("");
- val = Value(true);
- EXPECT_TRUE(val.AsBool());
-
- str << val;
- EXPECT_EQ("true", str.str());
-
- EXPECT_FALSE(val.IsF32());
- EXPECT_FALSE(val.IsF16());
- EXPECT_FALSE(val.IsI32());
- EXPECT_FALSE(val.IsU32());
- EXPECT_FALSE(val.IsTemp());
- EXPECT_TRUE(val.IsBool());
-}
-
-} // namespace
-} // namespace tint::ir