From e272eaf30f35389e626d91f64a832d1195c379b9 Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Tue, 29 Nov 2022 23:27:46 +0000 Subject: [PATCH] [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 Commit-Queue: Dan Sinclair Kokoro: Kokoro --- src/tint/CMakeLists.txt | 7 +- src/tint/ir/builder.cc | 6 +- src/tint/ir/builder.h | 24 +-- src/tint/ir/builder_impl.cc | 10 +- src/tint/ir/builder_impl_test.cc | 33 ++-- src/tint/ir/constant.cc | 56 +++++++ src/tint/ir/constant.h | 114 ++++++++++++++ src/tint/ir/constant_test.cc | 125 +++++++++++++++ src/tint/ir/instruction.h | 1 + src/tint/ir/instruction_test.cc | 252 ++++++++++++++++++------------- src/tint/ir/temp.cc | 32 ++++ src/tint/ir/temp.h | 54 +++++++ src/tint/ir/temp_test.cc | 41 +++++ src/tint/ir/value.cc | 52 ++----- src/tint/ir/value.h | 117 ++------------ src/tint/ir/value_test.cc | 137 ----------------- 16 files changed, 644 insertions(+), 417 deletions(-) create mode 100644 src/tint/ir/constant.cc create mode 100644 src/tint/ir/constant.h create mode 100644 src/tint/ir/constant_test.cc create mode 100644 src/tint/ir/temp.cc create mode 100644 src/tint/ir/temp.h create mode 100644 src/tint/ir/temp_test.cc delete mode 100644 src/tint/ir/value_test.cc diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index 06aa48355f..15532b2341 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -656,6 +656,8 @@ if(${TINT_BUILD_IR}) 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 @@ if(${TINT_BUILD_IR}) 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_TESTS) 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 2b5dea3f2a..6f5e9c692f 100644 --- a/src/tint/ir/builder.cc +++ b/src/tint/ir/builder.cc @@ -93,12 +93,12 @@ void Builder::Branch(Block* from, FlowNode* to) { 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 c380980491..bc30a951b5 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 @@ class Builder { /// @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 - const Value* MkValue(T val) { - return ir.values.Create(val); + const ir::Constant* Constant(T val) { + return ir.values.Create(val); } + /// Creates a new Temporary + /// @returns the new temporary + const ir::Temp* Temp() { return ir.values.Create(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 @@ class Builder { /// @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 36bcad8963..7700512e09 100644 --- a/src/tint/ir/builder_impl.cc +++ b/src/tint/ir/builder_impl.cc @@ -632,20 +632,20 @@ utils::Result BuilderImpl::EmitLiteral(const ast::LiteralExpressio return tint::Switch( // lit, [&](const ast::BoolLiteralExpression* l) { - return utils::Result(builder.MkValue(l->value)); + return utils::Result(builder.Constant(l->value)); }, [&](const ast::FloatLiteralExpression* l) { if (l->suffix == ast::FloatLiteralExpression::Suffix::kF) { return utils::Result( - builder.MkValue(f32(static_cast(l->value)))); + builder.Constant(f32(static_cast(l->value)))); } - return utils::Result(builder.MkValue(f16(static_cast(l->value)))); + return utils::Result(builder.Constant(f16(static_cast(l->value)))); }, [&](const ast::IntLiteralExpression* l) { if (l->suffix == ast::IntLiteralExpression::Suffix::kI) { - return utils::Result(builder.MkValue(i32(l->value))); + return utils::Result(builder.Constant(i32(l->value))); } - return utils::Result(builder.MkValue(u32(l->value))); + return utils::Result(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 edfe7be1b0..79e6e3feaf 100644 --- a/src/tint/ir/builder_impl_test.cc +++ b/src/tint/ir/builder_impl_test.cc @@ -101,7 +101,8 @@ TEST_F(IR_BuilderImplTest, IfStatement) { EXPECT_EQ(flow->merge_target->branch_target, func->end_target); // Check condition - auto* instr = flow->condition; + ASSERT_TRUE(flow->condition->Is()); + auto* instr = flow->condition->As(); ASSERT_TRUE(instr->IsBool()); EXPECT_TRUE(instr->AsBool()); } @@ -502,7 +503,8 @@ TEST_F(IR_BuilderImplTest, Loop_WithReturn) { EXPECT_EQ(loop_flow->merge_target->branch_target, nullptr); // Check condition - auto* instr = if_flow->condition; + ASSERT_TRUE(if_flow->condition->Is()); + auto* instr = if_flow->condition->As(); ASSERT_TRUE(instr->IsBool()); EXPECT_TRUE(instr->AsBool()); } @@ -947,7 +949,8 @@ TEST_F(IR_BuilderImplTest, While) { EXPECT_EQ(flow->merge_target->branch_target, func->end_target); // Check condition - auto* instr = if_flow->condition; + ASSERT_TRUE(if_flow->condition->Is()); + auto* instr = if_flow->condition->As(); ASSERT_TRUE(instr->IsBool()); EXPECT_FALSE(instr->AsBool()); } @@ -1071,7 +1074,8 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) { EXPECT_EQ(flow->merge_target->branch_target, func->end_target); // Check condition - auto* instr = if_flow->condition; + ASSERT_TRUE(if_flow->condition->Is()); + auto* instr = if_flow->condition->As(); ASSERT_TRUE(instr->IsBool()); EXPECT_FALSE(instr->AsBool()); } @@ -1171,7 +1175,8 @@ TEST_F(IR_BuilderImplTest, Switch) { EXPECT_EQ(flow->merge_target->branch_target, func->end_target); // Check condition - auto* instr = flow->condition; + ASSERT_TRUE(flow->condition->Is()); + auto* instr = flow->condition->As(); ASSERT_TRUE(instr->IsI32()); EXPECT_EQ(1_i, instr->AsI32()); } @@ -1341,7 +1346,8 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) { auto r = b.EmitLiteral(Expr(true)); ASSERT_TRUE(r); - auto* val = r.Get(); + ASSERT_TRUE(r.Get()->Is()); + auto* val = r.Get()->As(); EXPECT_TRUE(val->IsBool()); EXPECT_TRUE(val->AsBool()); } @@ -1351,7 +1357,8 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_False) { auto r = b.EmitLiteral(Expr(false)); ASSERT_TRUE(r); - auto val = r.Get(); + ASSERT_TRUE(r.Get()->Is()); + auto* val = r.Get()->As(); EXPECT_TRUE(val->IsBool()); EXPECT_FALSE(val->AsBool()); } @@ -1361,7 +1368,8 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F32) { auto r = b.EmitLiteral(Expr(1.2_f)); ASSERT_TRUE(r); - auto val = r.Get(); + ASSERT_TRUE(r.Get()->Is()); + auto* val = r.Get()->As(); EXPECT_TRUE(val->IsF32()); EXPECT_EQ(1.2_f, val->AsF32()); } @@ -1371,7 +1379,8 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F16) { auto r = b.EmitLiteral(Expr(1.2_h)); ASSERT_TRUE(r); - auto val = r.Get(); + ASSERT_TRUE(r.Get()->Is()); + auto* val = r.Get()->As(); EXPECT_TRUE(val->IsF16()); EXPECT_EQ(1.2_h, val->AsF16()); } @@ -1381,7 +1390,8 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_I32) { auto r = b.EmitLiteral(Expr(-2_i)); ASSERT_TRUE(r); - auto val = r.Get(); + ASSERT_TRUE(r.Get()->Is()); + auto* val = r.Get()->As(); EXPECT_TRUE(val->IsI32()); EXPECT_EQ(-2_i, val->AsI32()); } @@ -1391,7 +1401,8 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_U32) { auto r = b.EmitLiteral(Expr(2_u)); ASSERT_TRUE(r); - auto val = r.Get(); + ASSERT_TRUE(r.Get()->Is()); + auto* val = r.Get()->As(); 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 0000000000..78895bfa84 --- /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 + +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 0000000000..c06e121860 --- /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 +#include + +#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 { + 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(data_); } + /// @returns the constant data as a `f16`. + /// @note, must only be called if `IsF16()` is true + f16 AsF16() const { return std::get(data_); } + /// @returns the constant data as an `i32`. + /// @note, must only be called if `IsI32()` is true + i32 AsI32() const { return std::get(data_); } + /// @returns the constant data as a `u32`. + /// @note, must only be called if `IsU32()` is true + u32 AsU32() const { return std::get(data_); } + /// @returns the constant data as a `bool`. + /// @note, must only be called if `IsBool()` is true + bool AsBool() const { return std::get(data_); } + + private: + /// The type of data stored in this constant + Kind kind_; + /// The data stored in the constant + std::variant 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 0000000000..7b4e224efe --- /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 + +#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 ea9dec2e97..17351155ea 100644 --- a/src/tint/ir/instruction.h +++ b/src/tint/ir/instruction.h @@ -17,6 +17,7 @@ #include +#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 d93b9c72e5..d6c8d8a0c7 100644 --- a/src/tint/ir/instruction_test.cc +++ b/src/tint/ir/instruction_test.cc @@ -25,21 +25,23 @@ using IR_InstructionTest = TestHelper; 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -51,21 +53,23 @@ TEST_F(IR_InstructionTest, CreateAnd) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -77,21 +81,23 @@ TEST_F(IR_InstructionTest, CreateOr) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -103,21 +109,23 @@ TEST_F(IR_InstructionTest, CreateXor) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -129,21 +137,23 @@ TEST_F(IR_InstructionTest, CreateLogicalAnd) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -155,21 +165,23 @@ TEST_F(IR_InstructionTest, CreateLogicalOr) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -181,21 +193,23 @@ TEST_F(IR_InstructionTest, CreateEqual) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -207,21 +221,23 @@ TEST_F(IR_InstructionTest, CreateNotEqual) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -233,21 +249,23 @@ TEST_F(IR_InstructionTest, CreateLessThan) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -259,21 +277,23 @@ TEST_F(IR_InstructionTest, CreateGreaterThan) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -285,21 +305,23 @@ TEST_F(IR_InstructionTest, CreateLessThanEqual) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -311,21 +333,23 @@ TEST_F(IR_InstructionTest, CreateGreaterThanEqual) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -337,21 +361,23 @@ TEST_F(IR_InstructionTest, CreateShiftLeft) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -363,21 +389,23 @@ TEST_F(IR_InstructionTest, CreateShiftRight) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -389,21 +417,23 @@ TEST_F(IR_InstructionTest, CreateAdd) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -415,21 +445,23 @@ TEST_F(IR_InstructionTest, CreateSubtract) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -441,21 +473,23 @@ TEST_F(IR_InstructionTest, CreateMultiply) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); ASSERT_TRUE(rhs->IsI32()); EXPECT_EQ(i32(2), rhs->AsI32()); @@ -467,21 +501,23 @@ TEST_F(IR_InstructionTest, CreateDivide) { 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()); + EXPECT_EQ(Temp::Id(42), instr.Result()->As()->AsId()); ASSERT_TRUE(instr.HasLHS()); - auto lhs = instr.LHS(); + ASSERT_TRUE(instr.LHS()->Is()); + auto lhs = instr.LHS()->As(); ASSERT_TRUE(lhs->IsI32()); EXPECT_EQ(i32(4), lhs->AsI32()); ASSERT_TRUE(instr.HasRHS()); - auto rhs = instr.RHS(); + ASSERT_TRUE(instr.RHS()->Is()); + auto rhs = instr.RHS()->As(); 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 0000000000..de227ee738 --- /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 + +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 0000000000..b16baf28f8 --- /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 + +#include "src/tint/ir/value.h" + +namespace tint::ir { + +/// Temporary value in the IR. +class Temp : public Castable { + 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 0000000000..b5d817b381 --- /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 + +#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 4177f63431..a1431e30dd 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()) { + out << *c; + } else if (auto* t = ptr->As()) { + out << *t; + } else { + out << "Unknown value"; } return out; } diff --git a/src/tint/ir/value.h b/src/tint/ir/value.h index bbe8974eae..326931f70b 100644 --- a/src/tint/ir/value.h +++ b/src/tint/ir/value.h @@ -16,122 +16,29 @@ #define SRC_TINT_IR_VALUE_H_ #include -#include -#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 { 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(data_); } - /// @returns the value data as a `f16`. - /// @note, must only be called if `IsF16()` is true - f16 AsF16() const { return std::get(data_); } - /// @returns the value data as an `i32`. - /// @note, must only be called if `IsI32()` is true - i32 AsI32() const { return std::get(data_); } - /// @returns the value data as a `u32`. - /// @note, must only be called if `IsU32()` is true - u32 AsU32() const { return std::get(data_); } - /// @returns the value data as an `Id`. - /// @note, must only be called if `IsTemp()` is true - Id AsId() const { return std::get(data_); } - /// @returns the value data as a `bool`. - /// @note, must only be called if `IsBool()` is true - bool AsBool() const { return std::get(data_); } - - private: - /// The type of data stored in this value - Kind kind_; - /// The data stored in the value - std::variant 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 4ffe66e95f..0000000000 --- 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 - -#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