Convert ir::Constant over to use a constant::Value

This CL updaets the ir::Constant to store a constant::Value instead of the specific numbers
themselves.

Bug: tint:1718
Change-Id: I66b0a9643893b6079399daf61ee39ac5811e1eaf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/114362
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2022-12-15 19:17:22 +00:00 committed by Dawn LUCI CQ
parent dd1e4e39f2
commit 19ebcb2230
20 changed files with 602 additions and 500 deletions

View File

@ -1344,8 +1344,8 @@ int main(int argc, const char** argv) {
} else { } else {
auto mod = result.Move(); auto mod = result.Move();
if (options.dump_ir) { if (options.dump_ir) {
tint::ir::Disassembler d; tint::ir::Disassembler d(mod);
std::cout << d.Disassemble(mod) << std::endl; std::cout << d.Disassemble() << std::endl;
} }
if (options.dump_ir_graph) { if (options.dump_ir_graph) {
auto graph = tint::ir::Debug::AsDotGraph(&mod); auto graph = tint::ir::Debug::AsDotGraph(&mod);

View File

@ -28,9 +28,9 @@ Binary::Binary(Kind kind, const Value* result, const Value* lhs, const Value* rh
Binary::~Binary() = default; Binary::~Binary() = default;
std::ostream& Binary::ToString(std::ostream& out) const { std::ostream& Binary::ToString(std::ostream& out, const SymbolTable& st) const {
Result()->ToString(out) << " = "; Result()->ToString(out, st) << " = ";
lhs_->ToString(out) << " "; lhs_->ToString(out, st) << " ";
switch (GetKind()) { switch (GetKind()) {
case Binary::Kind::kAdd: case Binary::Kind::kAdd:
@ -89,7 +89,7 @@ std::ostream& Binary::ToString(std::ostream& out) const {
break; break;
} }
out << " "; out << " ";
rhs_->ToString(out); rhs_->ToString(out, st);
return out; return out;
} }

View File

@ -20,6 +20,7 @@
#include "src/tint/castable.h" #include "src/tint/castable.h"
#include "src/tint/ir/instruction.h" #include "src/tint/ir/instruction.h"
#include "src/tint/ir/value.h" #include "src/tint/ir/value.h"
#include "src/tint/symbol_table.h"
namespace tint::ir { namespace tint::ir {
@ -79,8 +80,9 @@ class Binary : public Castable<Binary, Instruction> {
/// Write the instruction to the given stream /// Write the instruction to the given stream
/// @param out the stream to write to /// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream /// @returns the stream
std::ostream& ToString(std::ostream& out) const override; std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
private: private:
Kind kind_; Kind kind_;

View File

@ -20,13 +20,15 @@
namespace tint::ir { namespace tint::ir {
namespace { namespace {
using namespace tint::number_suffixes; // NOLINT
//
using IR_InstructionTest = TestHelper; using IR_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, CreateAnd) { TEST_F(IR_InstructionTest, CreateAnd) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.And(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.And(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd); EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd);
@ -34,17 +36,17 @@ TEST_F(IR_InstructionTest, CreateAnd) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 & 2"); EXPECT_EQ(str.str(), "%42 = 4 & 2");
} }
@ -52,7 +54,7 @@ TEST_F(IR_InstructionTest, CreateOr) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Or(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Or(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kOr); EXPECT_EQ(instr->GetKind(), Binary::Kind::kOr);
@ -60,17 +62,17 @@ TEST_F(IR_InstructionTest, CreateOr) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 | 2"); EXPECT_EQ(str.str(), "%42 = 4 | 2");
} }
@ -78,7 +80,7 @@ TEST_F(IR_InstructionTest, CreateXor) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Xor(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Xor(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kXor); EXPECT_EQ(instr->GetKind(), Binary::Kind::kXor);
@ -86,17 +88,17 @@ TEST_F(IR_InstructionTest, CreateXor) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 ^ 2"); EXPECT_EQ(str.str(), "%42 = 4 ^ 2");
} }
@ -104,8 +106,7 @@ TEST_F(IR_InstructionTest, CreateLogicalAnd) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = const auto* instr = b.builder.LogicalAnd(b.builder.Constant(4_i), b.builder.Constant(2_i));
b.builder.LogicalAnd(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalAnd); EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalAnd);
@ -113,17 +114,17 @@ TEST_F(IR_InstructionTest, CreateLogicalAnd) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 && 2"); EXPECT_EQ(str.str(), "%42 = 4 && 2");
} }
@ -131,7 +132,7 @@ TEST_F(IR_InstructionTest, CreateLogicalOr) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.LogicalOr(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.LogicalOr(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalOr); EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalOr);
@ -139,17 +140,17 @@ TEST_F(IR_InstructionTest, CreateLogicalOr) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 || 2"); EXPECT_EQ(str.str(), "%42 = 4 || 2");
} }
@ -157,7 +158,7 @@ TEST_F(IR_InstructionTest, CreateEqual) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Equal(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Equal(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kEqual); EXPECT_EQ(instr->GetKind(), Binary::Kind::kEqual);
@ -165,17 +166,17 @@ TEST_F(IR_InstructionTest, CreateEqual) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 == 2"); EXPECT_EQ(str.str(), "%42 = 4 == 2");
} }
@ -183,7 +184,7 @@ TEST_F(IR_InstructionTest, CreateNotEqual) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.NotEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.NotEqual(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kNotEqual); EXPECT_EQ(instr->GetKind(), Binary::Kind::kNotEqual);
@ -191,17 +192,17 @@ TEST_F(IR_InstructionTest, CreateNotEqual) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 != 2"); EXPECT_EQ(str.str(), "%42 = 4 != 2");
} }
@ -209,7 +210,7 @@ TEST_F(IR_InstructionTest, CreateLessThan) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.LessThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.LessThan(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThan); EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThan);
@ -217,17 +218,17 @@ TEST_F(IR_InstructionTest, CreateLessThan) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 < 2"); EXPECT_EQ(str.str(), "%42 = 4 < 2");
} }
@ -235,8 +236,7 @@ TEST_F(IR_InstructionTest, CreateGreaterThan) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = const auto* instr = b.builder.GreaterThan(b.builder.Constant(4_i), b.builder.Constant(2_i));
b.builder.GreaterThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThan); EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThan);
@ -244,17 +244,17 @@ TEST_F(IR_InstructionTest, CreateGreaterThan) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 > 2"); EXPECT_EQ(str.str(), "%42 = 4 > 2");
} }
@ -262,8 +262,7 @@ TEST_F(IR_InstructionTest, CreateLessThanEqual) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = const auto* instr = b.builder.LessThanEqual(b.builder.Constant(4_i), b.builder.Constant(2_i));
b.builder.LessThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThanEqual); EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThanEqual);
@ -271,17 +270,17 @@ TEST_F(IR_InstructionTest, CreateLessThanEqual) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 <= 2"); EXPECT_EQ(str.str(), "%42 = 4 <= 2");
} }
@ -290,7 +289,7 @@ TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = const auto* instr =
b.builder.GreaterThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); b.builder.GreaterThanEqual(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThanEqual); EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThanEqual);
@ -298,17 +297,17 @@ TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 >= 2"); EXPECT_EQ(str.str(), "%42 = 4 >= 2");
} }
@ -316,7 +315,7 @@ TEST_F(IR_InstructionTest, CreateShiftLeft) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.ShiftLeft(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.ShiftLeft(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftLeft); EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftLeft);
@ -324,17 +323,17 @@ TEST_F(IR_InstructionTest, CreateShiftLeft) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 << 2"); EXPECT_EQ(str.str(), "%42 = 4 << 2");
} }
@ -342,8 +341,7 @@ TEST_F(IR_InstructionTest, CreateShiftRight) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = const auto* instr = b.builder.ShiftRight(b.builder.Constant(4_i), b.builder.Constant(2_i));
b.builder.ShiftRight(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftRight); EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftRight);
@ -351,17 +349,17 @@ TEST_F(IR_InstructionTest, CreateShiftRight) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 >> 2"); EXPECT_EQ(str.str(), "%42 = 4 >> 2");
} }
@ -369,7 +367,7 @@ TEST_F(IR_InstructionTest, CreateAdd) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Add(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Add(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kAdd); EXPECT_EQ(instr->GetKind(), Binary::Kind::kAdd);
@ -377,17 +375,17 @@ TEST_F(IR_InstructionTest, CreateAdd) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 + 2"); EXPECT_EQ(str.str(), "%42 = 4 + 2");
} }
@ -395,7 +393,7 @@ TEST_F(IR_InstructionTest, CreateSubtract) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Subtract(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Subtract(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kSubtract); EXPECT_EQ(instr->GetKind(), Binary::Kind::kSubtract);
@ -403,17 +401,17 @@ TEST_F(IR_InstructionTest, CreateSubtract) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 - 2"); EXPECT_EQ(str.str(), "%42 = 4 - 2");
} }
@ -421,7 +419,7 @@ TEST_F(IR_InstructionTest, CreateMultiply) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Multiply(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Multiply(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kMultiply); EXPECT_EQ(instr->GetKind(), Binary::Kind::kMultiply);
@ -429,17 +427,17 @@ TEST_F(IR_InstructionTest, CreateMultiply) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 * 2"); EXPECT_EQ(str.str(), "%42 = 4 * 2");
} }
@ -447,7 +445,7 @@ TEST_F(IR_InstructionTest, CreateDivide) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Divide(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Divide(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kDivide); EXPECT_EQ(instr->GetKind(), Binary::Kind::kDivide);
@ -455,17 +453,17 @@ TEST_F(IR_InstructionTest, CreateDivide) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 / 2"); EXPECT_EQ(str.str(), "%42 = 4 / 2");
} }
@ -473,7 +471,7 @@ TEST_F(IR_InstructionTest, CreateModulo) {
auto& b = CreateEmptyBuilder(); auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42); b.builder.next_temp_id = Temp::Id(42);
const auto* instr = b.builder.Modulo(b.builder.Constant(i32(4)), b.builder.Constant(i32(2))); const auto* instr = b.builder.Modulo(b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kModulo); EXPECT_EQ(instr->GetKind(), Binary::Kind::kModulo);
@ -481,17 +479,17 @@ TEST_F(IR_InstructionTest, CreateModulo) {
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId()); EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>()); ASSERT_TRUE(instr->LHS()->Is<Constant>());
auto lhs = instr->LHS()->As<Constant>(); auto lhs = instr->LHS()->As<Constant>()->value;
ASSERT_TRUE(lhs->IsI32()); ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(4), lhs->AsI32()); EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
ASSERT_TRUE(instr->RHS()->Is<Constant>()); ASSERT_TRUE(instr->RHS()->Is<Constant>());
auto rhs = instr->RHS()->As<Constant>(); auto rhs = instr->RHS()->As<Constant>()->value;
ASSERT_TRUE(rhs->IsI32()); ASSERT_TRUE(rhs->Is<constant::Scalar<i32>>());
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 % 2"); EXPECT_EQ(str.str(), "%42 = 4 % 2");
} }

View File

@ -15,6 +15,9 @@
#ifndef SRC_TINT_IR_BUILDER_H_ #ifndef SRC_TINT_IR_BUILDER_H_
#define SRC_TINT_IR_BUILDER_H_ #define SRC_TINT_IR_BUILDER_H_
#include <utility>
#include "src/tint/constant/scalar.h"
#include "src/tint/ir/binary.h" #include "src/tint/ir/binary.h"
#include "src/tint/ir/constant.h" #include "src/tint/ir/constant.h"
#include "src/tint/ir/function.h" #include "src/tint/ir/function.h"
@ -25,6 +28,11 @@
#include "src/tint/ir/temp.h" #include "src/tint/ir/temp.h"
#include "src/tint/ir/terminator.h" #include "src/tint/ir/terminator.h"
#include "src/tint/ir/value.h" #include "src/tint/ir/value.h"
#include "src/tint/type/bool.h"
#include "src/tint/type/f16.h"
#include "src/tint/type/f32.h"
#include "src/tint/type/i32.h"
#include "src/tint/type/u32.h"
// Forward Declarations // Forward Declarations
namespace tint { namespace tint {
@ -85,14 +93,56 @@ class Builder {
/// @param to the node to branch too /// @param to the node to branch too
void Branch(Block* from, FlowNode* to); void Branch(Block* from, FlowNode* to);
/// Creates a new Constant /// Creates a constant::Value
/// @param args the arguments
/// @returns the new constant value
template <typename T, typename... ARGS>
traits::EnableIf<traits::IsTypeOrDerived<T, constant::Value>, const T>* create(ARGS&&... args) {
return ir.constants.Create<T>(std::forward<ARGS>(args)...);
}
/// Creates a new ir::Constant
/// @param val the constant value /// @param val the constant value
/// @returns the new constant /// @returns the new constant
template <typename T> const ir::Constant* Constant(const constant::Value* val) {
const ir::Constant* Constant(T val) {
return ir.values.Create<ir::Constant>(val); return ir.values.Create<ir::Constant>(val);
} }
/// Creates a ir::Constant for an i32 Scalar
/// @param v the value
/// @returns the new constant
const ir::Constant* Constant(i32 v) {
return Constant(create<constant::Scalar<i32>>(ir.types.Get<type::I32>(), v));
}
/// Creates a ir::Constant for a u32 Scalar
/// @param v the value
/// @returns the new constant
const ir::Constant* Constant(u32 v) {
return Constant(create<constant::Scalar<u32>>(ir.types.Get<type::U32>(), v));
}
/// Creates a ir::Constant for a f32 Scalar
/// @param v the value
/// @returns the new constant
const ir::Constant* Constant(f32 v) {
return Constant(create<constant::Scalar<f32>>(ir.types.Get<type::F32>(), v));
}
/// Creates a ir::Constant for a f16 Scalar
/// @param v the value
/// @returns the new constant
const ir::Constant* Constant(f16 v) {
return Constant(create<constant::Scalar<f16>>(ir.types.Get<type::F16>(), v));
}
/// Creates a ir::Constant for a bool Scalar
/// @param v the value
/// @returns the new constant
const ir::Constant* Constant(bool v) {
return Constant(create<constant::Scalar<bool>>(ir.types.Get<type::Bool>(), v));
}
/// Creates a new Temporary /// Creates a new Temporary
/// @returns the new temporary /// @returns the new temporary
const ir::Temp* Temp() { return ir.values.Create<ir::Temp>(AllocateTempId()); } const ir::Temp* Temp() { return ir.values.Create<ir::Temp>(AllocateTempId()); }

View File

@ -41,6 +41,7 @@
#include "src/tint/ir/switch.h" #include "src/tint/ir/switch.h"
#include "src/tint/ir/terminator.h" #include "src/tint/ir/terminator.h"
#include "src/tint/program.h" #include "src/tint/program.h"
#include "src/tint/sem/expression.h"
#include "src/tint/sem/module.h" #include "src/tint/sem/module.h"
namespace tint::ir { namespace tint::ir {
@ -628,30 +629,24 @@ utils::Result<const Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression*
} }
utils::Result<const Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) { utils::Result<const Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
return tint::Switch( // auto* sem = builder.ir.program->Sem().Get(lit);
lit, if (!sem) {
[&](const ast::BoolLiteralExpression* l) { diagnostics_.add_error(
return utils::Result<const Value*>(builder.Constant(l->value)); tint::diag::System::IR,
}, "Failed to get semantic information for node " + std::string(lit->TypeInfo().name),
[&](const ast::FloatLiteralExpression* l) { lit->source);
if (l->suffix == ast::FloatLiteralExpression::Suffix::kF) { return utils::Failure;
return utils::Result<const Value*>( }
builder.Constant(f32(static_cast<float>(l->value))));
} auto* cv = sem->ConstantValue();
return utils::Result<const Value*>(builder.Constant(f16(static_cast<float>(l->value)))); if (!cv) {
}, diagnostics_.add_error(
[&](const ast::IntLiteralExpression* l) { tint::diag::System::IR,
if (l->suffix == ast::IntLiteralExpression::Suffix::kI) { "Failed to get constant value for node " + std::string(lit->TypeInfo().name),
return utils::Result<const Value*>(builder.Constant(i32(l->value))); lit->source);
} return utils::Failure;
return utils::Result<const Value*>(builder.Constant(u32(l->value))); }
}, return utils::Result<const Value*>(builder.Constant(cv));
[&](Default) {
diagnostics_.add_warning(tint::diag::System::IR,
"unknown literal type: " + std::string(lit->TypeInfo().name),
lit->source);
return utils::Failure;
});
} }
bool BuilderImpl::EmitType(const ast::Type* ty) { bool BuilderImpl::EmitType(const ast::Type* ty) {

View File

@ -102,9 +102,9 @@ TEST_F(IR_BuilderImplTest, IfStatement) {
// Check condition // Check condition
ASSERT_TRUE(flow->condition->Is<Constant>()); ASSERT_TRUE(flow->condition->Is<Constant>());
auto* instr = flow->condition->As<Constant>(); auto* instr = flow->condition->As<Constant>()->value;
ASSERT_TRUE(instr->IsBool()); ASSERT_TRUE(instr->Is<constant::Scalar<bool>>());
EXPECT_TRUE(instr->AsBool()); EXPECT_TRUE(instr->As<constant::Scalar<bool>>()->ValueAs<bool>());
} }
TEST_F(IR_BuilderImplTest, IfStatement_TrueReturns) { TEST_F(IR_BuilderImplTest, IfStatement_TrueReturns) {
@ -504,9 +504,9 @@ TEST_F(IR_BuilderImplTest, Loop_WithReturn) {
// Check condition // Check condition
ASSERT_TRUE(if_flow->condition->Is<Constant>()); ASSERT_TRUE(if_flow->condition->Is<Constant>());
auto* instr = if_flow->condition->As<Constant>(); auto* instr = if_flow->condition->As<Constant>()->value;
ASSERT_TRUE(instr->IsBool()); ASSERT_TRUE(instr->Is<constant::Scalar<bool>>());
EXPECT_TRUE(instr->AsBool()); EXPECT_TRUE(instr->As<constant::Scalar<bool>>()->ValueAs<bool>());
} }
TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn) { TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn) {
@ -950,9 +950,9 @@ TEST_F(IR_BuilderImplTest, While) {
// Check condition // Check condition
ASSERT_TRUE(if_flow->condition->Is<Constant>()); ASSERT_TRUE(if_flow->condition->Is<Constant>());
auto* instr = if_flow->condition->As<Constant>(); auto* instr = if_flow->condition->As<Constant>()->value;
ASSERT_TRUE(instr->IsBool()); ASSERT_TRUE(instr->Is<constant::Scalar<bool>>());
EXPECT_FALSE(instr->AsBool()); EXPECT_FALSE(instr->As<constant::Scalar<bool>>()->ValueAs<bool>());
} }
TEST_F(IR_BuilderImplTest, While_Return) { TEST_F(IR_BuilderImplTest, While_Return) {
@ -1075,9 +1075,9 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) {
// Check condition // Check condition
ASSERT_TRUE(if_flow->condition->Is<Constant>()); ASSERT_TRUE(if_flow->condition->Is<Constant>());
auto* instr = if_flow->condition->As<Constant>(); auto* instr = if_flow->condition->As<Constant>()->value;
ASSERT_TRUE(instr->IsBool()); ASSERT_TRUE(instr->Is<constant::Scalar<bool>>());
EXPECT_FALSE(instr->AsBool()); EXPECT_FALSE(instr->As<constant::Scalar<bool>>()->ValueAs<bool>());
} }
TEST_F(IR_BuilderImplTest, For_NoInitCondOrContinuing) { TEST_F(IR_BuilderImplTest, For_NoInitCondOrContinuing) {
@ -1176,9 +1176,9 @@ TEST_F(IR_BuilderImplTest, Switch) {
// Check condition // Check condition
ASSERT_TRUE(flow->condition->Is<Constant>()); ASSERT_TRUE(flow->condition->Is<Constant>());
auto* instr = flow->condition->As<Constant>(); auto* instr = flow->condition->As<Constant>()->value;
ASSERT_TRUE(instr->IsI32()); ASSERT_TRUE(instr->Is<constant::Scalar<i32>>());
EXPECT_EQ(1_i, instr->AsI32()); EXPECT_EQ(1_i, instr->As<constant::Scalar<i32>>()->ValueAs<i32>());
} }
TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) { TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) {
@ -1342,283 +1342,378 @@ TEST_F(IR_BuilderImplTest, Switch_AllReturn) {
} }
TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) { TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) {
auto& b = CreateEmptyBuilder(); auto* expr = Expr(true);
auto r = b.EmitLiteral(Expr(true)); GlobalVar("a", ty.bool_(), ast::AddressSpace::kPrivate, expr);
ASSERT_TRUE(r);
auto& b = CreateBuilder();
auto r = b.EmitLiteral(expr);
ASSERT_TRUE(r) << b.error();
ASSERT_TRUE(r.Get()->Is<Constant>()); ASSERT_TRUE(r.Get()->Is<Constant>());
auto* val = r.Get()->As<Constant>(); auto* val = r.Get()->As<Constant>()->value;
EXPECT_TRUE(val->IsBool()); EXPECT_TRUE(val->Is<constant::Scalar<bool>>());
EXPECT_TRUE(val->AsBool()); EXPECT_TRUE(val->As<constant::Scalar<bool>>()->ValueAs<bool>());
} }
TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_False) { TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_False) {
auto& b = CreateEmptyBuilder(); auto* expr = Expr(false);
auto r = b.EmitLiteral(Expr(false)); GlobalVar("a", ty.bool_(), ast::AddressSpace::kPrivate, expr);
ASSERT_TRUE(r);
auto& b = CreateBuilder();
auto r = b.EmitLiteral(expr);
ASSERT_TRUE(r) << b.error();
ASSERT_TRUE(r.Get()->Is<Constant>()); ASSERT_TRUE(r.Get()->Is<Constant>());
auto* val = r.Get()->As<Constant>(); auto* val = r.Get()->As<Constant>()->value;
EXPECT_TRUE(val->IsBool()); EXPECT_TRUE(val->Is<constant::Scalar<bool>>());
EXPECT_FALSE(val->AsBool()); EXPECT_FALSE(val->As<constant::Scalar<bool>>()->ValueAs<bool>());
} }
TEST_F(IR_BuilderImplTest, EmitLiteral_F32) { TEST_F(IR_BuilderImplTest, EmitLiteral_F32) {
auto& b = CreateEmptyBuilder(); auto* expr = Expr(1.2_f);
auto r = b.EmitLiteral(Expr(1.2_f)); GlobalVar("a", ty.f32(), ast::AddressSpace::kPrivate, expr);
ASSERT_TRUE(r);
auto& b = CreateBuilder();
auto r = b.EmitLiteral(expr);
ASSERT_TRUE(r) << b.error();
ASSERT_TRUE(r.Get()->Is<Constant>()); ASSERT_TRUE(r.Get()->Is<Constant>());
auto* val = r.Get()->As<Constant>(); auto* val = r.Get()->As<Constant>()->value;
EXPECT_TRUE(val->IsF32()); EXPECT_TRUE(val->Is<constant::Scalar<f32>>());
EXPECT_EQ(1.2_f, val->AsF32()); EXPECT_EQ(1.2_f, val->As<constant::Scalar<f32>>()->ValueAs<f32>());
} }
TEST_F(IR_BuilderImplTest, EmitLiteral_F16) { TEST_F(IR_BuilderImplTest, EmitLiteral_F16) {
auto& b = CreateEmptyBuilder(); Enable(ast::Extension::kF16);
auto r = b.EmitLiteral(Expr(1.2_h)); auto* expr = Expr(1.2_h);
ASSERT_TRUE(r); GlobalVar("a", ty.f16(), ast::AddressSpace::kPrivate, expr);
auto& b = CreateBuilder();
auto r = b.EmitLiteral(expr);
ASSERT_TRUE(r) << b.error();
ASSERT_TRUE(r.Get()->Is<Constant>()); ASSERT_TRUE(r.Get()->Is<Constant>());
auto* val = r.Get()->As<Constant>(); auto* val = r.Get()->As<Constant>()->value;
EXPECT_TRUE(val->IsF16()); EXPECT_TRUE(val->Is<constant::Scalar<f16>>());
EXPECT_EQ(1.2_h, val->AsF16()); EXPECT_EQ(1.2_h, val->As<constant::Scalar<f16>>()->ValueAs<f32>());
} }
TEST_F(IR_BuilderImplTest, EmitLiteral_I32) { TEST_F(IR_BuilderImplTest, EmitLiteral_I32) {
auto& b = CreateEmptyBuilder(); auto* expr = Expr(-2_i);
auto r = b.EmitLiteral(Expr(-2_i)); GlobalVar("a", ty.i32(), ast::AddressSpace::kPrivate, expr);
ASSERT_TRUE(r);
auto& b = CreateBuilder();
auto r = b.EmitLiteral(expr);
ASSERT_TRUE(r) << b.error();
ASSERT_TRUE(r.Get()->Is<Constant>()); ASSERT_TRUE(r.Get()->Is<Constant>());
auto* val = r.Get()->As<Constant>(); auto* val = r.Get()->As<Constant>()->value;
EXPECT_TRUE(val->IsI32()); EXPECT_TRUE(val->Is<constant::Scalar<i32>>());
EXPECT_EQ(-2_i, val->AsI32()); EXPECT_EQ(-2_i, val->As<constant::Scalar<i32>>()->ValueAs<f32>());
} }
TEST_F(IR_BuilderImplTest, EmitLiteral_U32) { TEST_F(IR_BuilderImplTest, EmitLiteral_U32) {
auto& b = CreateEmptyBuilder(); auto* expr = Expr(2_u);
auto r = b.EmitLiteral(Expr(2_u)); GlobalVar("a", ty.u32(), ast::AddressSpace::kPrivate, expr);
ASSERT_TRUE(r);
auto& b = CreateBuilder();
auto r = b.EmitLiteral(expr);
ASSERT_TRUE(r) << b.error();
ASSERT_TRUE(r.Get()->Is<Constant>()); ASSERT_TRUE(r.Get()->Is<Constant>());
auto* val = r.Get()->As<Constant>(); auto* val = r.Get()->As<Constant>()->value;
EXPECT_TRUE(val->IsU32()); EXPECT_TRUE(val->Is<constant::Scalar<u32>>());
EXPECT_EQ(2_u, val->AsU32()); EXPECT_EQ(2_u, val->As<constant::Scalar<u32>>()->ValueAs<f32>());
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Add) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Add) {
auto& b = CreateEmptyBuilder(); auto* expr = Add(3_u, 4_u);
auto r = b.EmitExpression(Add(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 + 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 + 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Subtract) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Subtract) {
auto& b = CreateEmptyBuilder(); auto* expr = Sub(3_u, 4_u);
auto r = b.EmitExpression(Sub(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 - 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 - 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Multiply) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Multiply) {
auto& b = CreateEmptyBuilder(); auto* expr = Mul(3_u, 4_u);
auto r = b.EmitExpression(Mul(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 * 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 * 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Div) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Div) {
auto& b = CreateEmptyBuilder(); auto* expr = Div(3_u, 4_u);
auto r = b.EmitExpression(Div(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 / 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 / 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Modulo) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Modulo) {
auto& b = CreateEmptyBuilder(); auto* expr = Mod(3_u, 4_u);
auto r = b.EmitExpression(Mod(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 % 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 % 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_And) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_And) {
auto& b = CreateEmptyBuilder(); auto* expr = And(3_u, 4_u);
auto r = b.EmitExpression(And(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 & 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 & 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Or) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Or) {
auto& b = CreateEmptyBuilder(); auto* expr = Or(3_u, 4_u);
auto r = b.EmitExpression(Or(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 | 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 | 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Xor) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Xor) {
auto& b = CreateEmptyBuilder(); auto* expr = Xor(3_u, 4_u);
auto r = b.EmitExpression(Xor(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 ^ 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 ^ 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalAnd) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalAnd) {
auto& b = CreateEmptyBuilder(); auto* expr = LogicalAnd(true, false);
auto r = b.EmitExpression(LogicalAnd(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 && 4 EXPECT_EQ(d.AsString(), R"(%1 = true && false
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalOr) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalOr) {
auto& b = CreateEmptyBuilder(); auto* expr = LogicalOr(false, true);
auto r = b.EmitExpression(LogicalOr(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 || 4 EXPECT_EQ(d.AsString(), R"(%1 = false || true
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Eqaul) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Equal) {
auto& b = CreateEmptyBuilder(); auto* expr = Equal(3_u, 4_u);
auto r = b.EmitExpression(Equal(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 == 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 == 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_NotEqual) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_NotEqual) {
auto& b = CreateEmptyBuilder(); auto* expr = NotEqual(3_u, 4_u);
auto r = b.EmitExpression(NotEqual(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 != 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 != 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThan) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThan) {
auto& b = CreateEmptyBuilder(); auto* expr = LessThan(3_u, 4_u);
auto r = b.EmitExpression(LessThan(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 < 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 < 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThan) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThan) {
auto& b = CreateEmptyBuilder(); auto* expr = GreaterThan(3_u, 4_u);
auto r = b.EmitExpression(GreaterThan(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 > 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 > 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThanEqual) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThanEqual) {
auto& b = CreateEmptyBuilder(); auto* expr = LessThanEqual(3_u, 4_u);
auto r = b.EmitExpression(LessThanEqual(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 <= 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 <= 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThanEqual) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThanEqual) {
auto& b = CreateEmptyBuilder(); auto* expr = GreaterThanEqual(3_u, 4_u);
auto r = b.EmitExpression(GreaterThanEqual(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 >= 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 >= 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftLeft) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftLeft) {
auto& b = CreateEmptyBuilder(); auto* expr = Shl(3_u, 4_u);
auto r = b.EmitExpression(Shl(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 << 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 << 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftRight) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftRight) {
auto& b = CreateEmptyBuilder(); auto* expr = Shr(3_u, 4_u);
auto r = b.EmitExpression(Shr(3_u, 4_u)); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4
)"); )");
} }
TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) { TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) {
auto& b = CreateEmptyBuilder(); auto* expr = LogicalOr(LessThan(1_u, Add(Shr(3_u, 4_u), 9_u)),
auto r = b.EmitExpression(LogicalOr( // GreaterThan(2.5_f, Div(6.7_f, Mul(2.3_f, 5.5_f))));
LessThan(1_u, Add(Shr(3_u, 4_u), 9_u)), GreaterThan(2.5_f, Div(6.7_f, Mul(2.3_f, 5.5_f))))); WrapInFunction(expr);
ASSERT_TRUE(r);
Disassembler d; auto& b = CreateBuilder();
InjectFlowBlock();
auto r = b.EmitExpression(expr);
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block); d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4 EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4
%2 = %1 + 9 %2 = %1 + 9
%3 = 1 < %2 %3 = 1 < %2
%4 = 2.300000 * 5.500000 %4 = 2.3 * 5.5
%5 = 6.700000 / %4 %5 = 6.7 / %4
%6 = 2.500000 > %5 %6 = 2.5 > %5
%7 = %3 || %6 %7 = %3 || %6
)"); )");
} }

View File

@ -16,40 +16,48 @@
#include <string> #include <string>
#include "src/tint/constant/composite.h"
#include "src/tint/constant/scalar.h"
#include "src/tint/constant/splat.h"
TINT_INSTANTIATE_TYPEINFO(tint::ir::Constant); TINT_INSTANTIATE_TYPEINFO(tint::ir::Constant);
namespace tint::ir { namespace tint::ir {
Constant::Constant(f32 f) : kind_(Kind::kF32), data_(f) {} Constant::Constant(const constant::Value* val) : value(val) {}
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; Constant::~Constant() = default;
std::ostream& Constant::ToString(std::ostream& out) const { std::ostream& Constant::ToString(std::ostream& out, const SymbolTable& st) const {
switch (GetKind()) { std::function<void(const constant::Value*)> emit = [&](const constant::Value* c) {
case Constant::Kind::kF32: Switch(
out << std::to_string(AsF32().value); c,
break; [&](const constant::Scalar<AFloat>* scalar) { out << scalar->ValueAs<AFloat>().value; },
case Constant::Kind::kF16: [&](const constant::Scalar<AInt>* scalar) { out << scalar->ValueAs<AInt>().value; },
out << std::to_string(AsF16().value); [&](const constant::Scalar<i32>* scalar) { out << scalar->ValueAs<i32>().value; },
break; [&](const constant::Scalar<u32>* scalar) { out << scalar->ValueAs<u32>().value; },
case Constant::Kind::kI32: [&](const constant::Scalar<f32>* scalar) { out << scalar->ValueAs<f32>().value; },
out << std::to_string(AsI32().value); [&](const constant::Scalar<f16>* scalar) { out << scalar->ValueAs<f16>().value; },
break; [&](const constant::Scalar<bool>* scalar) {
case Constant::Kind::kU32: out << (scalar->ValueAs<bool>() ? "true" : "false");
out << std::to_string(AsU32().value); },
break; [&](const constant::Splat* splat) {
case Constant::Kind::kBool: out << splat->Type()->FriendlyName(st) << "(";
out << (AsBool() ? "true" : "false"); emit(splat->Index(0));
break; out << ")";
} },
[&](const constant::Composite* composite) {
out << composite->Type()->FriendlyName(st) << "(";
for (const auto* elem : composite->elements) {
if (elem != composite->elements[0]) {
out << ", ";
}
emit(elem);
}
out << ")";
});
};
emit(value);
return out; return out;
} }

View File

@ -16,100 +16,29 @@
#define SRC_TINT_IR_CONSTANT_H_ #define SRC_TINT_IR_CONSTANT_H_
#include <ostream> #include <ostream>
#include <variant>
#include "src/tint/constant/value.h"
#include "src/tint/ir/value.h" #include "src/tint/ir/value.h"
#include "src/tint/number.h" #include "src/tint/symbol_table.h"
namespace tint::ir { namespace tint::ir {
/// Constant in the IR. The constant can be one of several types these include, but aren't limited /// Constant in the IR.
/// to, `f32`, `u32`, `bool`. The type of the constant determines the type of data stored.
class Constant : public Castable<Constant, Value> { class Constant : public Castable<Constant, Value> {
public: 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 /// Constructor
/// @param b the `bool` constant to store in the constant /// @param val the value stored in the constant
explicit Constant(bool b); explicit Constant(const constant::Value* val);
/// 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() 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_); }
/// Write the constant to the given stream /// Write the constant to the given stream
/// @param out the stream to write to /// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream /// @returns the stream
std::ostream& ToString(std::ostream& out) const override; std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
private: /// The constants value
/// The type of data stored in this constant const constant::Value* const value;
Kind kind_;
/// The data stored in the constant
std::variant<f32, f16, u32, i32, bool> data_;
}; };
} // namespace tint::ir } // namespace tint::ir

View File

@ -29,17 +29,17 @@ TEST_F(IR_ConstantTest, f32) {
std::stringstream str; std::stringstream str;
auto* val = b.builder.Constant(1.2_f); auto* c = b.builder.Constant(1.2_f);
EXPECT_EQ(1.2_f, val->AsF32()); EXPECT_EQ(1.2_f, c->value->As<constant::Scalar<f32>>()->ValueAs<f32>());
val->ToString(str); c->ToString(str, program->Symbols());
EXPECT_EQ("1.200000", str.str()); EXPECT_EQ("1.2", str.str());
EXPECT_TRUE(val->IsF32()); EXPECT_TRUE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(val->IsF16()); EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
EXPECT_FALSE(val->IsI32()); EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
EXPECT_FALSE(val->IsU32()); EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
EXPECT_FALSE(val->IsBool()); EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
} }
TEST_F(IR_ConstantTest, f16) { TEST_F(IR_ConstantTest, f16) {
@ -47,17 +47,17 @@ TEST_F(IR_ConstantTest, f16) {
std::stringstream str; std::stringstream str;
auto* val = b.builder.Constant(1.1_h); auto* c = b.builder.Constant(1.1_h);
EXPECT_EQ(1.1_h, val->AsF16()); EXPECT_EQ(1.1_h, c->value->As<constant::Scalar<f16>>()->ValueAs<f16>());
val->ToString(str); c->ToString(str, program->Symbols());
EXPECT_EQ("1.099609", str.str()); EXPECT_EQ("1.09961", str.str());
EXPECT_FALSE(val->IsF32()); EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_TRUE(val->IsF16()); EXPECT_TRUE(c->value->Is<constant::Scalar<f16>>());
EXPECT_FALSE(val->IsI32()); EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
EXPECT_FALSE(val->IsU32()); EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
EXPECT_FALSE(val->IsBool()); EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
} }
TEST_F(IR_ConstantTest, i32) { TEST_F(IR_ConstantTest, i32) {
@ -65,17 +65,17 @@ TEST_F(IR_ConstantTest, i32) {
std::stringstream str; std::stringstream str;
auto* val = b.builder.Constant(1_i); auto* c = b.builder.Constant(1_i);
EXPECT_EQ(1_i, val->AsI32()); EXPECT_EQ(1_i, c->value->As<constant::Scalar<i32>>()->ValueAs<i32>());
val->ToString(str); c->ToString(str, program->Symbols());
EXPECT_EQ("1", str.str()); EXPECT_EQ("1", str.str());
EXPECT_FALSE(val->IsF32()); EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(val->IsF16()); EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
EXPECT_TRUE(val->IsI32()); EXPECT_TRUE(c->value->Is<constant::Scalar<i32>>());
EXPECT_FALSE(val->IsU32()); EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
EXPECT_FALSE(val->IsBool()); EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
} }
TEST_F(IR_ConstantTest, u32) { TEST_F(IR_ConstantTest, u32) {
@ -83,17 +83,17 @@ TEST_F(IR_ConstantTest, u32) {
std::stringstream str; std::stringstream str;
auto* val = b.builder.Constant(2_u); auto* c = b.builder.Constant(2_u);
EXPECT_EQ(2_u, val->AsU32()); EXPECT_EQ(2_u, c->value->As<constant::Scalar<u32>>()->ValueAs<u32>());
val->ToString(str); c->ToString(str, program->Symbols());
EXPECT_EQ("2", str.str()); EXPECT_EQ("2", str.str());
EXPECT_FALSE(val->IsF32()); EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(val->IsF16()); EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
EXPECT_FALSE(val->IsI32()); EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
EXPECT_TRUE(val->IsU32()); EXPECT_TRUE(c->value->Is<constant::Scalar<u32>>());
EXPECT_FALSE(val->IsBool()); EXPECT_FALSE(c->value->Is<constant::Scalar<bool>>());
} }
TEST_F(IR_ConstantTest, bool) { TEST_F(IR_ConstantTest, bool) {
@ -101,24 +101,24 @@ TEST_F(IR_ConstantTest, bool) {
std::stringstream str; std::stringstream str;
auto* val = b.builder.Constant(false); auto* c = b.builder.Constant(false);
EXPECT_FALSE(val->AsBool()); EXPECT_FALSE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
val->ToString(str); c->ToString(str, program->Symbols());
EXPECT_EQ("false", str.str()); EXPECT_EQ("false", str.str());
str.str(""); str.str("");
val = b.builder.Constant(true); c = b.builder.Constant(true);
EXPECT_TRUE(val->AsBool()); EXPECT_TRUE(c->value->As<constant::Scalar<bool>>()->ValueAs<bool>());
val->ToString(str); c->ToString(str, program->Symbols());
EXPECT_EQ("true", str.str()); EXPECT_EQ("true", str.str());
EXPECT_FALSE(val->IsF32()); EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(val->IsF16()); EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
EXPECT_FALSE(val->IsI32()); EXPECT_FALSE(c->value->Is<constant::Scalar<i32>>());
EXPECT_FALSE(val->IsU32()); EXPECT_FALSE(c->value->Is<constant::Scalar<u32>>());
EXPECT_TRUE(val->IsBool()); EXPECT_TRUE(c->value->Is<constant::Scalar<bool>>());
} }
} // namespace } // namespace

View File

@ -50,7 +50,7 @@ class ScopedIndent {
} // namespace } // namespace
Disassembler::Disassembler() = default; Disassembler::Disassembler(const Module& mod) : mod_(mod) {}
Disassembler::~Disassembler() = default; Disassembler::~Disassembler() = default;
@ -63,7 +63,7 @@ std::ostream& Disassembler::Indent() {
void Disassembler::EmitBlockInstructions(const Block* b) { void Disassembler::EmitBlockInstructions(const Block* b) {
for (const auto* instr : b->instructions) { for (const auto* instr : b->instructions) {
instr->ToString(out_) << std::endl; instr->ToString(out_, mod_.program->Symbols()) << std::endl;
} }
} }
@ -144,8 +144,8 @@ void Disassembler::Walk(const FlowNode* node) {
[&](const ir::Terminator*) { Indent() << "Function end" << std::endl; }); [&](const ir::Terminator*) { Indent() << "Function end" << std::endl; });
} }
std::string Disassembler::Disassemble(const Module& mod) { std::string Disassembler::Disassemble() {
for (const auto* func : mod.functions) { for (const auto* func : mod_.functions) {
Walk(func); Walk(func);
} }
return out_.str(); return out_.str();

View File

@ -28,13 +28,13 @@ namespace tint::ir {
class Disassembler { class Disassembler {
public: public:
/// Constructor /// Constructor
Disassembler(); /// @param mod the module
explicit Disassembler(const Module& mod);
~Disassembler(); ~Disassembler();
/// Returns the module as a string /// Returns the module as a string
/// @param mod the module to emit
/// @returns the string representation of the module /// @returns the string representation of the module
std::string Disassemble(const Module& mod); std::string Disassemble();
/// Writes the block instructions to the stream /// Writes the block instructions to the stream
/// @param b the block containing the instructions /// @param b the block containing the instructions
@ -47,6 +47,7 @@ class Disassembler {
std::ostream& Indent(); std::ostream& Indent();
void Walk(const FlowNode* node); void Walk(const FlowNode* node);
const Module& mod_;
std::stringstream out_; std::stringstream out_;
std::unordered_set<const FlowNode*> visited_; std::unordered_set<const FlowNode*> visited_;
std::unordered_set<const FlowNode*> stop_nodes_; std::unordered_set<const FlowNode*> stop_nodes_;

View File

@ -18,6 +18,7 @@
#include <ostream> #include <ostream>
#include "src/tint/castable.h" #include "src/tint/castable.h"
#include "src/tint/symbol_table.h"
namespace tint::ir { namespace tint::ir {
@ -34,8 +35,9 @@ class Instruction : public Castable<Instruction> {
/// Write the instruction to the given stream /// Write the instruction to the given stream
/// @param out the stream to write to /// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream /// @returns the stream
virtual std::ostream& ToString(std::ostream& out) const = 0; virtual std::ostream& ToString(std::ostream& out, const SymbolTable& st) const = 0;
protected: protected:
/// Constructor /// Constructor

View File

@ -44,7 +44,7 @@ TEST_F(IR_BinaryTest, CreateAnd) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 & 2"); EXPECT_EQ(str.str(), "%42 = 4 & 2");
} }
@ -70,7 +70,7 @@ TEST_F(IR_BinaryTest, CreateOr) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 | 2"); EXPECT_EQ(str.str(), "%42 = 4 | 2");
} }
@ -96,7 +96,7 @@ TEST_F(IR_BinaryTest, CreateXor) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 ^ 2"); EXPECT_EQ(str.str(), "%42 = 4 ^ 2");
} }
@ -123,7 +123,7 @@ TEST_F(IR_BinaryTest, CreateLogicalAnd) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 && 2"); EXPECT_EQ(str.str(), "%42 = 4 && 2");
} }
@ -149,7 +149,7 @@ TEST_F(IR_BinaryTest, CreateLogicalOr) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 || 2"); EXPECT_EQ(str.str(), "%42 = 4 || 2");
} }
@ -175,7 +175,7 @@ TEST_F(IR_BinaryTest, CreateEqual) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 == 2"); EXPECT_EQ(str.str(), "%42 = 4 == 2");
} }
@ -201,7 +201,7 @@ TEST_F(IR_BinaryTest, CreateNotEqual) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 != 2"); EXPECT_EQ(str.str(), "%42 = 4 != 2");
} }
@ -227,7 +227,7 @@ TEST_F(IR_BinaryTest, CreateLessThan) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 < 2"); EXPECT_EQ(str.str(), "%42 = 4 < 2");
} }
@ -254,7 +254,7 @@ TEST_F(IR_BinaryTest, CreateGreaterThan) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 > 2"); EXPECT_EQ(str.str(), "%42 = 4 > 2");
} }
@ -281,7 +281,7 @@ TEST_F(IR_BinaryTest, CreateLessThanEqual) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 <= 2"); EXPECT_EQ(str.str(), "%42 = 4 <= 2");
} }
@ -308,7 +308,7 @@ TEST_F(IR_BinaryTest, CreateGreaterThanEqual) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 >= 2"); EXPECT_EQ(str.str(), "%42 = 4 >= 2");
} }
@ -334,7 +334,7 @@ TEST_F(IR_BinaryTest, CreateShiftLeft) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 << 2"); EXPECT_EQ(str.str(), "%42 = 4 << 2");
} }
@ -361,7 +361,7 @@ TEST_F(IR_BinaryTest, CreateShiftRight) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 >> 2"); EXPECT_EQ(str.str(), "%42 = 4 >> 2");
} }
@ -387,7 +387,7 @@ TEST_F(IR_BinaryTest, CreateAdd) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 + 2"); EXPECT_EQ(str.str(), "%42 = 4 + 2");
} }
@ -413,7 +413,7 @@ TEST_F(IR_BinaryTest, CreateSubtract) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 - 2"); EXPECT_EQ(str.str(), "%42 = 4 - 2");
} }
@ -439,7 +439,7 @@ TEST_F(IR_BinaryTest, CreateMultiply) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 * 2"); EXPECT_EQ(str.str(), "%42 = 4 * 2");
} }
@ -465,7 +465,7 @@ TEST_F(IR_BinaryTest, CreateDivide) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 / 2"); EXPECT_EQ(str.str(), "%42 = 4 / 2");
} }
@ -491,7 +491,7 @@ TEST_F(IR_BinaryTest, CreateModulo) {
EXPECT_EQ(i32(2), rhs->AsI32()); EXPECT_EQ(i32(2), rhs->AsI32());
std::stringstream str; std::stringstream str;
instr->ToString(str); instr->ToString(str, program->Symbols());
EXPECT_EQ(str.str(), "%42 = 4 % 2"); EXPECT_EQ(str.str(), "%42 = 4 % 2");
} }

View File

@ -17,9 +17,11 @@
#include <string> #include <string>
#include "src/tint/constant/value.h"
#include "src/tint/ir/function.h" #include "src/tint/ir/function.h"
#include "src/tint/ir/instruction.h" #include "src/tint/ir/instruction.h"
#include "src/tint/ir/value.h" #include "src/tint/ir/value.h"
#include "src/tint/type/manager.h"
#include "src/tint/utils/block_allocator.h" #include "src/tint/utils/block_allocator.h"
#include "src/tint/utils/result.h" #include "src/tint/utils/result.h"
#include "src/tint/utils/vector.h" #include "src/tint/utils/vector.h"
@ -68,6 +70,8 @@ class Module {
/// The flow node allocator /// The flow node allocator
utils::BlockAllocator<FlowNode> flow_nodes; utils::BlockAllocator<FlowNode> flow_nodes;
/// The constant allocator
utils::BlockAllocator<constant::Value> constants;
/// The value allocator /// The value allocator
utils::BlockAllocator<Value> values; utils::BlockAllocator<Value> values;
/// The instruction allocator /// The instruction allocator
@ -80,6 +84,9 @@ class Module {
/// The source ast::Program this module was constucted from /// The source ast::Program this module was constucted from
const Program* program; const Program* program;
/// The type manager for the module
type::Manager types;
}; };
} // namespace tint::ir } // namespace tint::ir

View File

@ -24,7 +24,7 @@ Temp::Temp(Id id) : id_(id) {}
Temp::~Temp() = default; Temp::~Temp() = default;
std::ostream& Temp::ToString(std::ostream& out) const { std::ostream& Temp::ToString(std::ostream& out, const SymbolTable&) const {
out << "%" << std::to_string(AsId()); out << "%" << std::to_string(AsId());
return out; return out;
} }

View File

@ -18,6 +18,7 @@
#include <ostream> #include <ostream>
#include "src/tint/ir/value.h" #include "src/tint/ir/value.h"
#include "src/tint/symbol_table.h"
namespace tint::ir { namespace tint::ir {
@ -45,8 +46,9 @@ class Temp : public Castable<Temp, Value> {
/// Write the temp to the given stream /// Write the temp to the given stream
/// @param out the stream to write to /// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream /// @returns the stream
std::ostream& ToString(std::ostream& out) const override; std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
private: private:
Id id_ = 0; Id id_ = 0;

View File

@ -33,7 +33,7 @@ TEST_F(IR_TempTest, id) {
auto* val = b.builder.Temp(); auto* val = b.builder.Temp();
EXPECT_EQ(4u, val->AsId()); EXPECT_EQ(4u, val->AsId());
val->ToString(str); val->ToString(str, program->Symbols());
EXPECT_EQ("%4", str.str()); EXPECT_EQ("%4", str.str());
} }

View File

@ -21,6 +21,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/tint/ir/builder_impl.h" #include "src/tint/ir/builder_impl.h"
#include "src/tint/ir/disassembler.h" #include "src/tint/ir/disassembler.h"
#include "src/tint/number.h"
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
namespace tint::ir { namespace tint::ir {
@ -41,19 +42,29 @@ class TestHelperBase : public BASE, public ProgramBuilder {
if (gen_) { if (gen_) {
return *gen_; return *gen_;
} }
program = std::make_unique<Program>(std::move(*this));
diag::Formatter formatter; diag::Formatter formatter;
program = std::make_unique<Program>(std::move(*this));
[&]() { ASSERT_TRUE(program->IsValid()) << formatter.format(program->Diagnostics()); }(); [&]() { ASSERT_TRUE(program->IsValid()) << formatter.format(program->Diagnostics()); }();
gen_ = std::make_unique<BuilderImpl>(program.get()); gen_ = std::make_unique<BuilderImpl>(program.get());
return *gen_; return *gen_;
} }
/// Injects a flow block into the builder
/// @returns the injected block
ir::Block* InjectFlowBlock() {
auto* block = gen_->builder.CreateBlock();
gen_->current_flow_block = block;
return block;
}
/// Creates a BuilderImpl without an originating program. This is used for testing the /// Creates a BuilderImpl without an originating program. This is used for testing the
/// expressions which don't require the full builder implementation. The current flow block /// expressions which don't require the full builder implementation. The current flow block
/// is initialized with an empty block. /// is initialized with an empty block.
/// @returns the BuilderImpl for testing. /// @returns the BuilderImpl for testing.
BuilderImpl& CreateEmptyBuilder() { BuilderImpl& CreateEmptyBuilder() {
gen_ = std::make_unique<BuilderImpl>(nullptr); program = std::make_unique<Program>();
gen_ = std::make_unique<BuilderImpl>(program.get());
gen_->current_flow_block = gen_->builder.CreateBlock(); gen_->current_flow_block = gen_->builder.CreateBlock();
return *gen_; return *gen_;
} }

View File

@ -18,6 +18,7 @@
#include <ostream> #include <ostream>
#include "src/tint/castable.h" #include "src/tint/castable.h"
#include "src/tint/symbol_table.h"
namespace tint::ir { namespace tint::ir {
@ -35,8 +36,9 @@ class Value : public Castable<Value> {
/// Write the value to the given stream /// Write the value to the given stream
/// @param out the stream to write to /// @param out the stream to write to
/// @param st the symbol table
/// @returns the stream /// @returns the stream
virtual std::ostream& ToString(std::ostream& out) const = 0; virtual std::ostream& ToString(std::ostream& out, const SymbolTable& st) const = 0;
protected: protected:
/// Constructor /// Constructor