[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>
This commit is contained in:
dan sinclair 2022-11-29 23:27:46 +00:00 committed by Dawn LUCI CQ
parent 0982dcea69
commit e272eaf30f
16 changed files with 644 additions and 417 deletions

View File

@ -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()

View File

@ -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) {

View File

@ -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 <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 @@ 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

View File

@ -632,20 +632,20 @@ utils::Result<const Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpressio
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,

View File

@ -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<Constant>());
auto* instr = flow->condition->As<Constant>();
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<Constant>());
auto* instr = if_flow->condition->As<Constant>();
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<Constant>());
auto* instr = if_flow->condition->As<Constant>();
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<Constant>());
auto* instr = if_flow->condition->As<Constant>();
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<Constant>());
auto* instr = flow->condition->As<Constant>();
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<Constant>());
auto* val = r.Get()->As<Constant>();
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<Constant>());
auto* val = r.Get()->As<Constant>();
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<Constant>());
auto* val = r.Get()->As<Constant>();
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<Constant>());
auto* val = r.Get()->As<Constant>();
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<Constant>());
auto* val = r.Get()->As<Constant>();
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<Constant>());
auto* val = r.Get()->As<Constant>();
EXPECT_TRUE(val->IsU32());
EXPECT_EQ(2_u, val->AsU32());
}

56
src/tint/ir/constant.cc Normal file
View File

@ -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

114
src/tint/ir/constant.h Normal file
View File

@ -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_

View File

@ -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

View File

@ -17,6 +17,7 @@
#include <ostream>
#include "src/tint/debug.h"
#include "src/tint/ir/value.h"
#include "src/tint/utils/vector.h"

View File

@ -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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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, 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<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());

32
src/tint/ir/temp.cc Normal file
View File

@ -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

54
src/tint/ir/temp.h Normal file
View File

@ -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_

41
src/tint/ir/temp_test.cc Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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