From 113fb07071548812cbaef322a73682ea4c734de3 Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Fri, 27 Mar 2020 00:45:34 +0000 Subject: [PATCH] [spirv-writer] Generate constants This CL updates the SPIR-V writer to generate the OpConstantTrue, OpConstantFalse and OpConstant instructions. Bug: tint:5 Change-Id: I660554c491e4eb569e3902fce0973fae3f27e6c0 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17820 Reviewed-by: David Neto --- src/CMakeLists.txt | 4 +- src/ast/bool_literal.cc | 7 +- src/ast/bool_literal.h | 6 +- src/ast/bool_literal_test.cc | 15 +- src/ast/case_statement_test.cc | 19 +- src/ast/const_initializer_expression_test.cc | 13 +- src/ast/else_statement_test.cc | 10 +- src/ast/float_literal.cc | 13 +- src/ast/float_literal.h | 6 +- src/ast/float_literal_test.cc | 20 +- src/ast/int_literal.cc | 7 +- src/ast/int_literal.h | 6 +- src/ast/int_literal_test.cc | 10 +- src/ast/literal.cc | 2 +- src/ast/literal.h | 13 +- src/ast/switch_statement_test.cc | 19 +- src/ast/uint_literal.cc | 7 +- src/ast/uint_literal.h | 6 +- src/ast/uint_literal_test.cc | 10 +- src/reader/wgsl/parser_impl.cc | 31 +++- src/writer/spirv/builder.cc | 45 ++++- src/writer/spirv/builder.h | 6 + src/writer/spirv/builder_literal_test.cc | 172 ++++++++++++++++++ .../generator_impl_array_accessor_test.cc | 4 +- src/writer/wgsl/generator_impl_case_test.cc | 4 +- .../wgsl/generator_impl_initializer_test.cc | 36 ++-- src/writer/wgsl/generator_impl_switch_test.cc | 4 +- 27 files changed, 423 insertions(+), 72 deletions(-) create mode 100644 src/writer/spirv/builder_literal_test.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 10605fda7e..dc37b6eb5e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -264,6 +264,7 @@ set(TINT_TEST_SRCS ast/else_statement_test.cc ast/entry_point_test.cc ast/fallthrough_statement_test.cc + ast/float_literal_test.cc ast/function_test.cc ast/identifier_expression_test.cc ast/if_statement_test.cc @@ -406,9 +407,10 @@ if(${TINT_BUILD_SPV_WRITER}) list(APPEND TINT_TEST_SRCS writer/spirv/binary_writer_test.cc writer/spirv/builder_test.cc - writer/spirv/builder_type_test.cc writer/spirv/builder_entry_point_test.cc writer/spirv/builder_function_test.cc + writer/spirv/builder_literal_test.cc + writer/spirv/builder_type_test.cc writer/spirv/instruction_test.cc writer/spirv/operand_test.cc writer/spirv/spv_dump.cc diff --git a/src/ast/bool_literal.cc b/src/ast/bool_literal.cc index e11e8a52db..2ab78b9f7a 100644 --- a/src/ast/bool_literal.cc +++ b/src/ast/bool_literal.cc @@ -17,7 +17,8 @@ namespace tint { namespace ast { -BoolLiteral::BoolLiteral(bool value) : value_(value) {} +BoolLiteral::BoolLiteral(ast::type::Type* type, bool value) + : Literal(type), value_(value) {} BoolLiteral::~BoolLiteral() = default; @@ -25,5 +26,9 @@ std::string BoolLiteral::to_str() const { return value_ ? "true" : "false"; } +std::string BoolLiteral::name() const { + return value_ ? "__bool_true" : "__bool_false"; +} + } // namespace ast } // namespace tint diff --git a/src/ast/bool_literal.h b/src/ast/bool_literal.h index c568f278dd..d1749b1c1b 100644 --- a/src/ast/bool_literal.h +++ b/src/ast/bool_literal.h @@ -26,8 +26,9 @@ namespace ast { class BoolLiteral : public Literal { public: /// Constructor + /// @param type the type of the literal /// @param value the bool literals value - explicit BoolLiteral(bool value); + BoolLiteral(ast::type::Type* type, bool value); ~BoolLiteral() override; /// @returns true if this is a bool literal @@ -38,6 +39,9 @@ class BoolLiteral : public Literal { /// @returns true if the bool literal is false bool IsFalse() const { return !value_; } + /// @returns the name for this literal. This name is unique to this value. + std::string name() const override; + /// @returns the literal as a string std::string to_str() const override; diff --git a/src/ast/bool_literal_test.cc b/src/ast/bool_literal_test.cc index 190a51b211..10697ee7ce 100644 --- a/src/ast/bool_literal_test.cc +++ b/src/ast/bool_literal_test.cc @@ -15,6 +15,7 @@ #include "src/ast/bool_literal.h" #include "gtest/gtest.h" +#include "src/ast/type/bool_type.h" namespace tint { namespace ast { @@ -23,21 +24,24 @@ namespace { using BoolLiteralTest = testing::Test; TEST_F(BoolLiteralTest, True) { - BoolLiteral b{true}; + ast::type::BoolType bool_type; + BoolLiteral b{&bool_type, true}; ASSERT_TRUE(b.IsBool()); ASSERT_TRUE(b.IsTrue()); ASSERT_FALSE(b.IsFalse()); } TEST_F(BoolLiteralTest, False) { - BoolLiteral b{false}; + ast::type::BoolType bool_type; + BoolLiteral b{&bool_type, false}; ASSERT_TRUE(b.IsBool()); ASSERT_FALSE(b.IsTrue()); ASSERT_TRUE(b.IsFalse()); } TEST_F(BoolLiteralTest, Is) { - BoolLiteral b{false}; + ast::type::BoolType bool_type; + BoolLiteral b{&bool_type, false}; EXPECT_TRUE(b.IsBool()); EXPECT_FALSE(b.IsInt()); EXPECT_FALSE(b.IsFloat()); @@ -45,8 +49,9 @@ TEST_F(BoolLiteralTest, Is) { } TEST_F(BoolLiteralTest, ToStr) { - BoolLiteral t{true}; - BoolLiteral f{false}; + ast::type::BoolType bool_type; + BoolLiteral t{&bool_type, true}; + BoolLiteral f{&bool_type, false}; EXPECT_EQ(t.to_str(), "true"); EXPECT_EQ(f.to_str(), "false"); diff --git a/src/ast/case_statement_test.cc b/src/ast/case_statement_test.cc index dc1f90bf88..27b94c57de 100644 --- a/src/ast/case_statement_test.cc +++ b/src/ast/case_statement_test.cc @@ -18,6 +18,7 @@ #include "src/ast/bool_literal.h" #include "src/ast/if_statement.h" #include "src/ast/nop_statement.h" +#include "src/ast/type/bool_type.h" namespace tint { namespace ast { @@ -26,7 +27,8 @@ namespace { using CaseStatementTest = testing::Test; TEST_F(CaseStatementTest, Creation) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); std::vector> stmts; stmts.push_back(std::make_unique()); @@ -40,7 +42,8 @@ TEST_F(CaseStatementTest, Creation) { } TEST_F(CaseStatementTest, Creation_WithSource) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); std::vector> stmts; stmts.push_back(std::make_unique()); @@ -60,7 +63,8 @@ TEST_F(CaseStatementTest, IsDefault_WithoutCondition) { } TEST_F(CaseStatementTest, IsDefault_WithCondition) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); CaseStatement c; c.set_condition(std::move(b)); EXPECT_FALSE(c.IsDefault()); @@ -77,7 +81,8 @@ TEST_F(CaseStatementTest, IsValid) { } TEST_F(CaseStatementTest, IsValid_NullBodyStatement) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); std::vector> stmts; stmts.push_back(std::make_unique()); stmts.push_back(nullptr); @@ -87,7 +92,8 @@ TEST_F(CaseStatementTest, IsValid_NullBodyStatement) { } TEST_F(CaseStatementTest, IsValid_InvalidBodyStatement) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); std::vector> stmts; stmts.push_back(std::make_unique()); @@ -96,7 +102,8 @@ TEST_F(CaseStatementTest, IsValid_InvalidBodyStatement) { } TEST_F(CaseStatementTest, ToStr_WithCondition) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); std::vector> stmts; stmts.push_back(std::make_unique()); CaseStatement c(std::move(b), std::move(stmts)); diff --git a/src/ast/const_initializer_expression_test.cc b/src/ast/const_initializer_expression_test.cc index a823a33ca4..243df5400c 100644 --- a/src/ast/const_initializer_expression_test.cc +++ b/src/ast/const_initializer_expression_test.cc @@ -16,6 +16,7 @@ #include "gtest/gtest.h" #include "src/ast/bool_literal.h" +#include "src/ast/type/bool_type.h" namespace tint { namespace ast { @@ -24,14 +25,16 @@ namespace { using ConstInitializerExpressionTest = testing::Test; TEST_F(ConstInitializerExpressionTest, Creation) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); auto b_ptr = b.get(); ConstInitializerExpression c(std::move(b)); EXPECT_EQ(c.literal(), b_ptr); } TEST_F(ConstInitializerExpressionTest, Creation_WithSource) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); ConstInitializerExpression c(Source{20, 2}, std::move(b)); auto src = c.source(); EXPECT_EQ(src.line, 20); @@ -39,7 +42,8 @@ TEST_F(ConstInitializerExpressionTest, Creation_WithSource) { } TEST_F(ConstInitializerExpressionTest, IsValid) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); ConstInitializerExpression c(std::move(b)); EXPECT_TRUE(c.IsValid()); } @@ -50,7 +54,8 @@ TEST_F(ConstInitializerExpressionTest, IsValid_MissingLiteral) { } TEST_F(ConstInitializerExpressionTest, ToStr) { - auto b = std::make_unique(true); + ast::type::BoolType bool_type; + auto b = std::make_unique(&bool_type, true); ConstInitializerExpression c(std::move(b)); std::ostringstream out; c.to_str(out, 2); diff --git a/src/ast/else_statement_test.cc b/src/ast/else_statement_test.cc index 9675e0ba82..3e1aadc7f9 100644 --- a/src/ast/else_statement_test.cc +++ b/src/ast/else_statement_test.cc @@ -19,6 +19,7 @@ #include "src/ast/const_initializer_expression.h" #include "src/ast/if_statement.h" #include "src/ast/nop_statement.h" +#include "src/ast/type/bool_type.h" namespace tint { namespace ast { @@ -27,8 +28,9 @@ namespace { using ElseStatementTest = testing::Test; TEST_F(ElseStatementTest, Creation) { + ast::type::BoolType bool_type; auto cond = std::make_unique( - std::make_unique(true)); + std::make_unique(&bool_type, true)); std::vector> body; body.push_back(std::make_unique()); @@ -54,8 +56,9 @@ TEST_F(ElseStatementTest, IsElse) { } TEST_F(ElseStatementTest, HasCondition) { + ast::type::BoolType bool_type; auto cond = std::make_unique( - std::make_unique(true)); + std::make_unique(&bool_type, true)); ElseStatement e(std::move(cond), {}); EXPECT_TRUE(e.HasCondition()); } @@ -102,8 +105,9 @@ TEST_F(ElseStatementTest, IsValid_InvalidBodyStatement) { } TEST_F(ElseStatementTest, ToStr) { + ast::type::BoolType bool_type; auto cond = std::make_unique( - std::make_unique(true)); + std::make_unique(&bool_type, true)); std::vector> body; body.push_back(std::make_unique()); diff --git a/src/ast/float_literal.cc b/src/ast/float_literal.cc index 1d8b40f1c9..467a7bd902 100644 --- a/src/ast/float_literal.cc +++ b/src/ast/float_literal.cc @@ -14,10 +14,13 @@ #include "src/ast/float_literal.h" +#include + namespace tint { namespace ast { -FloatLiteral::FloatLiteral(float value) : value_(value) {} +FloatLiteral::FloatLiteral(ast::type::Type* type, float value) + : Literal(type), value_(value) {} FloatLiteral::~FloatLiteral() = default; @@ -25,5 +28,13 @@ std::string FloatLiteral::to_str() const { return std::to_string(value_); } +std::string FloatLiteral::name() const { + std::ostringstream out; + out.flags(out.flags() | std::ios_base::showpoint); + out.precision(std::numeric_limits::max_digits10); + out << "__float" << value_; + return out.str(); +} + } // namespace ast } // namespace tint diff --git a/src/ast/float_literal.h b/src/ast/float_literal.h index baf088ade5..370a553ed2 100644 --- a/src/ast/float_literal.h +++ b/src/ast/float_literal.h @@ -26,8 +26,9 @@ namespace ast { class FloatLiteral : public Literal { public: /// Constructor + /// @param type the type of the literal /// @param value the float literals value - explicit FloatLiteral(float value); + FloatLiteral(ast::type::Type* type, float value); ~FloatLiteral() override; /// @returns true if this is a float literal @@ -36,6 +37,9 @@ class FloatLiteral : public Literal { /// @returns the float literal value float value() const { return value_; } + /// @returns the name for this literal. This name is unique to this value. + std::string name() const override; + /// @returns the literal as a string std::string to_str() const override; diff --git a/src/ast/float_literal_test.cc b/src/ast/float_literal_test.cc index e9b3f4e6f0..6f1101806a 100644 --- a/src/ast/float_literal_test.cc +++ b/src/ast/float_literal_test.cc @@ -15,6 +15,7 @@ #include "src/ast/float_literal.h" #include "gtest/gtest.h" +#include "src/ast/type/f32_type.h" namespace tint { namespace ast { @@ -23,13 +24,15 @@ namespace { using FloatLiteralTest = testing::Test; TEST_F(FloatLiteralTest, Value) { - FloatLiteral f{47.2}; + ast::type::F32Type f32; + FloatLiteral f{&f32, 47.2f}; ASSERT_TRUE(f.IsFloat()); - EXPECT_EQ(f.value(), 47.2); + EXPECT_EQ(f.value(), 47.2f); } TEST_F(FloatLiteralTest, Is) { - FloatLiteral f{42}; + ast::type::F32Type f32; + FloatLiteral f{&f32, 42.f}; EXPECT_FALSE(f.IsBool()); EXPECT_FALSE(f.IsInt()); EXPECT_TRUE(f.IsFloat()); @@ -37,9 +40,16 @@ TEST_F(FloatLiteralTest, Is) { } TEST_F(FloatLiteralTest, ToStr) { - FloatLiteral f{42.1}; + ast::type::F32Type f32; + FloatLiteral f{&f32, 42.1f}; - EXPECT_EQ(f.to_str(), "42.1"); + EXPECT_EQ(f.to_str(), "42.099998"); +} + +TEST_F(FloatLiteralTest, ToName) { + ast::type::F32Type f32; + FloatLiteral f{&f32, 42.1f}; + EXPECT_EQ(f.name(), "__float42.0999985"); } } // namespace diff --git a/src/ast/int_literal.cc b/src/ast/int_literal.cc index 99e476c8df..1fdf84f41d 100644 --- a/src/ast/int_literal.cc +++ b/src/ast/int_literal.cc @@ -17,7 +17,8 @@ namespace tint { namespace ast { -IntLiteral::IntLiteral(int32_t value) : value_(value) {} +IntLiteral::IntLiteral(ast::type::Type* type, int32_t value) + : Literal(type), value_(value) {} IntLiteral::~IntLiteral() = default; @@ -25,5 +26,9 @@ std::string IntLiteral::to_str() const { return std::to_string(value_); } +std::string IntLiteral::name() const { + return "__int" + std::to_string(value_); +} + } // namespace ast } // namespace tint diff --git a/src/ast/int_literal.h b/src/ast/int_literal.h index b96e3b9ad2..ccbd89c5c0 100644 --- a/src/ast/int_literal.h +++ b/src/ast/int_literal.h @@ -26,8 +26,9 @@ namespace ast { class IntLiteral : public Literal { public: /// Constructor + /// @param type the type /// @param value the int literals value - explicit IntLiteral(int32_t value); + IntLiteral(ast::type::Type* type, int32_t value); ~IntLiteral() override; /// @returns true if this is a int literal @@ -36,6 +37,9 @@ class IntLiteral : public Literal { /// @returns the int literal value int32_t value() const { return value_; } + /// @returns the name for this literal. This name is unique to this value. + std::string name() const override; + /// @returns the literal as a string std::string to_str() const override; diff --git a/src/ast/int_literal_test.cc b/src/ast/int_literal_test.cc index 8d35d5df41..42ca665bc8 100644 --- a/src/ast/int_literal_test.cc +++ b/src/ast/int_literal_test.cc @@ -15,6 +15,7 @@ #include "src/ast/int_literal.h" #include "gtest/gtest.h" +#include "src/ast/type/i32_type.h" namespace tint { namespace ast { @@ -23,13 +24,15 @@ namespace { using IntLiteralTest = testing::Test; TEST_F(IntLiteralTest, Value) { - IntLiteral i{47}; + ast::type::I32Type i32; + IntLiteral i{&i32, 47}; ASSERT_TRUE(i.IsInt()); EXPECT_EQ(i.value(), 47); } TEST_F(IntLiteralTest, Is) { - IntLiteral i{42}; + ast::type::I32Type i32; + IntLiteral i{&i32, 42}; EXPECT_FALSE(i.IsBool()); EXPECT_TRUE(i.IsInt()); EXPECT_FALSE(i.IsFloat()); @@ -37,7 +40,8 @@ TEST_F(IntLiteralTest, Is) { } TEST_F(IntLiteralTest, ToStr) { - IntLiteral i{-42}; + ast::type::I32Type i32; + IntLiteral i{&i32, -42}; EXPECT_EQ(i.to_str(), "-42"); } diff --git a/src/ast/literal.cc b/src/ast/literal.cc index 055d33db66..3759274538 100644 --- a/src/ast/literal.cc +++ b/src/ast/literal.cc @@ -24,7 +24,7 @@ namespace tint { namespace ast { -Literal::Literal() = default; +Literal::Literal(ast::type::Type* type) : type_(type) {} Literal::~Literal() = default; diff --git a/src/ast/literal.h b/src/ast/literal.h index af8b831397..9f91478a2c 100644 --- a/src/ast/literal.h +++ b/src/ast/literal.h @@ -17,6 +17,8 @@ #include +#include "src/ast/type/type.h" + namespace tint { namespace ast { @@ -48,12 +50,21 @@ class Literal { /// @returns the literal as a unsigned int literal UintLiteral* AsUint(); + /// @returns the type of the literal + ast::type::Type* type() const { return type_; } + /// @returns the literal as a string virtual std::string to_str() const = 0; + /// @returns the name for this literal. This name is unique to this value. + virtual std::string name() const = 0; + protected: /// Constructor - Literal(); + Literal(ast::type::Type* type); + + private: + ast::type::Type* type_ = nullptr; }; } // namespace ast diff --git a/src/ast/switch_statement_test.cc b/src/ast/switch_statement_test.cc index 1f065ec81f..4bb71f5bff 100644 --- a/src/ast/switch_statement_test.cc +++ b/src/ast/switch_statement_test.cc @@ -20,6 +20,7 @@ #include "src/ast/bool_literal.h" #include "src/ast/case_statement.h" #include "src/ast/identifier_expression.h" +#include "src/ast/type/bool_type.h" namespace tint { namespace ast { @@ -28,7 +29,8 @@ namespace { using SwitchStatementTest = testing::Test; TEST_F(SwitchStatementTest, Creation) { - auto lit = std::make_unique(true); + ast::type::BoolType bool_type; + auto lit = std::make_unique(&bool_type, true); auto ident = std::make_unique("ident"); std::vector> body; body.push_back(std::make_unique( @@ -59,7 +61,8 @@ TEST_F(SwitchStatementTest, IsSwitch) { } TEST_F(SwitchStatementTest, IsValid) { - auto lit = std::make_unique(true); + ast::type::BoolType bool_type; + auto lit = std::make_unique(&bool_type, true); auto ident = std::make_unique("ident"); std::vector> body; body.push_back(std::make_unique( @@ -70,7 +73,8 @@ TEST_F(SwitchStatementTest, IsValid) { } TEST_F(SwitchStatementTest, IsValid_Null_Condition) { - auto lit = std::make_unique(true); + ast::type::BoolType bool_type; + auto lit = std::make_unique(&bool_type, true); std::vector> body; body.push_back(std::make_unique( std::move(lit), std::vector>())); @@ -81,7 +85,8 @@ TEST_F(SwitchStatementTest, IsValid_Null_Condition) { } TEST_F(SwitchStatementTest, IsValid_Invalid_Condition) { - auto lit = std::make_unique(true); + ast::type::BoolType bool_type; + auto lit = std::make_unique(&bool_type, true); auto ident = std::make_unique(""); std::vector> body; body.push_back(std::make_unique( @@ -92,7 +97,8 @@ TEST_F(SwitchStatementTest, IsValid_Invalid_Condition) { } TEST_F(SwitchStatementTest, IsValid_Null_BodyStatement) { - auto lit = std::make_unique(true); + ast::type::BoolType bool_type; + auto lit = std::make_unique(&bool_type, true); auto ident = std::make_unique("ident"); std::vector> body; body.push_back(std::make_unique( @@ -132,7 +138,8 @@ TEST_F(SwitchStatementTest, ToStr_Empty) { } TEST_F(SwitchStatementTest, ToStr) { - auto lit = std::make_unique(true); + ast::type::BoolType bool_type; + auto lit = std::make_unique(&bool_type, true); auto ident = std::make_unique("ident"); std::vector> body; body.push_back(std::make_unique( diff --git a/src/ast/uint_literal.cc b/src/ast/uint_literal.cc index 273f9ca988..562d47accc 100644 --- a/src/ast/uint_literal.cc +++ b/src/ast/uint_literal.cc @@ -17,7 +17,8 @@ namespace tint { namespace ast { -UintLiteral::UintLiteral(uint32_t value) : value_(value) {} +UintLiteral::UintLiteral(ast::type::Type* type, uint32_t value) + : Literal(type), value_(value) {} UintLiteral::~UintLiteral() = default; @@ -25,5 +26,9 @@ std::string UintLiteral::to_str() const { return std::to_string(value_); } +std::string UintLiteral::name() const { + return "__uint" + std::to_string(value_); +} + } // namespace ast } // namespace tint diff --git a/src/ast/uint_literal.h b/src/ast/uint_literal.h index 0b2394e52a..c9e7731582 100644 --- a/src/ast/uint_literal.h +++ b/src/ast/uint_literal.h @@ -26,8 +26,9 @@ namespace ast { class UintLiteral : public Literal { public: /// Constructor + /// @param type the type of the literal /// @param value the uint literals value - explicit UintLiteral(uint32_t value); + UintLiteral(ast::type::Type* type, uint32_t value); ~UintLiteral() override; /// @returns true if this is a uint literal @@ -36,6 +37,9 @@ class UintLiteral : public Literal { /// @returns the uint literal value uint32_t value() const { return value_; } + /// @returns the name for this literal. This name is unique to this value. + std::string name() const override; + /// @returns the literal as a string std::string to_str() const override; diff --git a/src/ast/uint_literal_test.cc b/src/ast/uint_literal_test.cc index 137cded3c5..d19811c60d 100644 --- a/src/ast/uint_literal_test.cc +++ b/src/ast/uint_literal_test.cc @@ -15,6 +15,7 @@ #include "src/ast/uint_literal.h" #include "gtest/gtest.h" +#include "src/ast/type/u32_type.h" namespace tint { namespace ast { @@ -23,13 +24,15 @@ namespace { using UintLiteralTest = testing::Test; TEST_F(UintLiteralTest, Value) { - UintLiteral u{47}; + ast::type::U32Type u32; + UintLiteral u{&u32, 47}; ASSERT_TRUE(u.IsUint()); EXPECT_EQ(u.value(), 47); } TEST_F(UintLiteralTest, Is) { - UintLiteral u{42}; + ast::type::U32Type u32; + UintLiteral u{&u32, 42}; EXPECT_FALSE(u.IsBool()); EXPECT_FALSE(u.IsInt()); EXPECT_FALSE(u.IsFloat()); @@ -37,7 +40,8 @@ TEST_F(UintLiteralTest, Is) { } TEST_F(UintLiteralTest, ToStr) { - UintLiteral i{42}; + ast::type::U32Type u32; + UintLiteral i{&u32, 42}; EXPECT_EQ(i.to_str(), "42"); } diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 1b71bea76b..e2db44d8ac 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -2097,23 +2097,44 @@ std::unique_ptr ParserImpl::const_literal() { auto t = peek(); if (t.IsTrue()) { next(); // Consume the peek - return std::make_unique(true); + + auto type = ctx_.type_mgr->Get(std::make_unique()); + if (!type) { + return nullptr; + } + return std::make_unique(type, true); } if (t.IsFalse()) { next(); // Consume the peek - return std::make_unique(false); + auto type = ctx_.type_mgr->Get(std::make_unique()); + if (!type) { + return nullptr; + } + return std::make_unique(type, false); } if (t.IsIntLiteral()) { next(); // Consume the peek - return std::make_unique(t.to_i32()); + auto type = ctx_.type_mgr->Get(std::make_unique()); + if (!type) { + return nullptr; + } + return std::make_unique(type, t.to_i32()); } if (t.IsUintLiteral()) { next(); // Consume the peek - return std::make_unique(t.to_u32()); + auto type = ctx_.type_mgr->Get(std::make_unique()); + if (!type) { + return nullptr; + } + return std::make_unique(type, t.to_u32()); } if (t.IsFloatLiteral()) { next(); // Consume the peek - return std::make_unique(t.to_f32()); + auto type = ctx_.type_mgr->Get(std::make_unique()); + if (!type) { + return nullptr; + } + return std::make_unique(type, t.to_f32()); } return nullptr; } diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index f9c1584808..bca5b92b4c 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -1,5 +1,4 @@ -// Copyright 2020 The Tint Authors. -// +// Copyright 2020 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 @@ -17,12 +16,16 @@ #include #include "spirv/unified1/spirv.h" +#include "src/ast/bool_literal.h" +#include "src/ast/float_literal.h" +#include "src/ast/int_literal.h" #include "src/ast/struct.h" #include "src/ast/struct_member.h" #include "src/ast/struct_member_offset_decoration.h" #include "src/ast/type/matrix_type.h" #include "src/ast/type/struct_type.h" #include "src/ast/type/vector_type.h" +#include "src/ast/uint_literal.h" namespace tint { namespace writer { @@ -212,6 +215,44 @@ void Builder::GenerateImport(ast::Import* imp) { import_name_to_id_[imp->name()] = id; } +uint32_t Builder::GenerateLiteralIfNeeded(ast::Literal* lit) { + auto type_id = GenerateTypeIfNeeded(lit->type()); + if (type_id == 0) { + return 0; + } + auto name = lit->name(); + auto val = const_to_id_.find(name); + if (val != const_to_id_.end()) { + return val->second; + } + + auto result = result_op(); + auto result_id = result.to_i(); + + if (lit->IsBool()) { + if (lit->AsBool()->IsTrue()) { + push_type(spv::Op::OpConstantTrue, {Operand::Int(type_id), result}); + } else { + push_type(spv::Op::OpConstantFalse, {Operand::Int(type_id), result}); + } + } else if (lit->IsInt()) { + push_type(spv::Op::OpConstant, {Operand::Int(type_id), result, + Operand::Int(lit->AsInt()->value())}); + } else if (lit->IsUint()) { + push_type(spv::Op::OpConstant, {Operand::Int(type_id), result, + Operand::Int(lit->AsUint()->value())}); + } else if (lit->IsFloat()) { + push_type(spv::Op::OpConstant, {Operand::Int(type_id), result, + Operand::Float(lit->AsFloat()->value())}); + } else { + error_ = "unknown literal type"; + return 0; + } + + const_to_id_[name] = result_id; + return result_id; +} + uint32_t Builder::GenerateTypeIfNeeded(ast::type::Type* type) { if (type->IsAlias()) { return GenerateTypeIfNeeded(type->AsAlias()->type()); diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h index b075fa929d..3045fe2793 100644 --- a/src/writer/spirv/builder.h +++ b/src/writer/spirv/builder.h @@ -20,6 +20,7 @@ #include #include +#include "src/ast/literal.h" #include "src/ast/module.h" #include "src/ast/struct_member.h" #include "src/writer/spirv/instruction.h" @@ -136,6 +137,10 @@ class Builder { /// Generates an import instruction /// @param imp the import void GenerateImport(ast::Import* imp); + /// Generates a literal constant if needed + /// @param lit the literal to generate + /// @returns the ID on success or 0 on failure + uint32_t GenerateLiteralIfNeeded(ast::Literal* lit); /// Generates a type if not already created /// @param type the type to create /// @returns the ID to use for the given type. Returns 0 on unknown type. @@ -181,6 +186,7 @@ class Builder { std::unordered_map import_name_to_id_; std::unordered_map func_name_to_id_; std::unordered_map type_name_to_id_; + std::unordered_map const_to_id_; }; } // namespace spirv diff --git a/src/writer/spirv/builder_literal_test.cc b/src/writer/spirv/builder_literal_test.cc new file mode 100644 index 0000000000..432ac168db --- /dev/null +++ b/src/writer/spirv/builder_literal_test.cc @@ -0,0 +1,172 @@ +// Copyright 2020 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 "gtest/gtest.h" +#include "spirv/unified1/spirv.h" +#include "src/ast/bool_literal.h" +#include "src/ast/float_literal.h" +#include "src/ast/int_literal.h" +#include "src/ast/literal.h" +#include "src/ast/type/bool_type.h" +#include "src/ast/type/f32_type.h" +#include "src/ast/type/i32_type.h" +#include "src/ast/type/u32_type.h" +#include "src/ast/uint_literal.h" +#include "src/writer/spirv/builder.h" +#include "src/writer/spirv/spv_dump.h" + +namespace tint { +namespace writer { +namespace spirv { + +using BuilderTest = testing::Test; + +TEST_F(BuilderTest, Literal_Bool_True) { + ast::type::BoolType bool_type; + ast::BoolLiteral b_true(&bool_type, true); + + Builder b; + auto id = b.GenerateLiteralIfNeeded(&b_true); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(2, id); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool +%2 = OpConstantTrue %1 +)"); +} + +TEST_F(BuilderTest, Literal_Bool_False) { + ast::type::BoolType bool_type; + ast::BoolLiteral b_false(&bool_type, false); + + Builder b; + auto id = b.GenerateLiteralIfNeeded(&b_false); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(2, id); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool +%2 = OpConstantFalse %1 +)"); +} + +TEST_F(BuilderTest, Literal_Bool_Dedup) { + ast::type::BoolType bool_type; + ast::BoolLiteral b_true(&bool_type, true); + ast::BoolLiteral b_false(&bool_type, false); + + Builder b; + ASSERT_NE(b.GenerateLiteralIfNeeded(&b_true), 0); + ASSERT_FALSE(b.has_error()) << b.error(); + ASSERT_NE(b.GenerateLiteralIfNeeded(&b_false), 0); + ASSERT_FALSE(b.has_error()) << b.error(); + ASSERT_NE(b.GenerateLiteralIfNeeded(&b_true), 0); + ASSERT_FALSE(b.has_error()) << b.error(); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool +%2 = OpConstantTrue %1 +%3 = OpConstantFalse %1 +)"); +} + +TEST_F(BuilderTest, Literal_I32) { + ast::type::I32Type i32; + ast::IntLiteral i(&i32, -23); + + Builder b; + auto id = b.GenerateLiteralIfNeeded(&i); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(2, id); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1 +%2 = OpConstant %1 -23 +)"); +} + +TEST_F(BuilderTest, Literal_I32_Dedup) { + ast::type::I32Type i32; + ast::IntLiteral i1(&i32, -23); + ast::IntLiteral i2(&i32, -23); + + Builder b; + ASSERT_NE(b.GenerateLiteralIfNeeded(&i1), 0); + ASSERT_NE(b.GenerateLiteralIfNeeded(&i2), 0); + ASSERT_FALSE(b.has_error()) << b.error(); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1 +%2 = OpConstant %1 -23 +)"); +} + +TEST_F(BuilderTest, Literal_U32) { + ast::type::U32Type u32; + ast::UintLiteral i(&u32, 23); + + Builder b; + auto id = b.GenerateLiteralIfNeeded(&i); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(2, id); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0 +%2 = OpConstant %1 23 +)"); +} + +TEST_F(BuilderTest, Literal_U32_Dedup) { + ast::type::U32Type u32; + ast::UintLiteral i1(&u32, 23); + ast::UintLiteral i2(&u32, 23); + + Builder b; + ASSERT_NE(b.GenerateLiteralIfNeeded(&i1), 0); + ASSERT_NE(b.GenerateLiteralIfNeeded(&i2), 0); + ASSERT_FALSE(b.has_error()) << b.error(); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0 +%2 = OpConstant %1 23 +)"); +} + +TEST_F(BuilderTest, Literal_F32) { + ast::type::F32Type f32; + ast::FloatLiteral i(&f32, 23.245f); + + Builder b; + auto id = b.GenerateLiteralIfNeeded(&i); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(2, id); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32 +%2 = OpConstant %1 23.2450008 +)"); +} + +TEST_F(BuilderTest, Literal_F32_Dedup) { + ast::type::F32Type f32; + ast::FloatLiteral i1(&f32, 23.245f); + ast::FloatLiteral i2(&f32, 23.245f); + + Builder b; + ASSERT_NE(b.GenerateLiteralIfNeeded(&i1), 0); + ASSERT_NE(b.GenerateLiteralIfNeeded(&i2), 0); + ASSERT_FALSE(b.has_error()) << b.error(); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32 +%2 = OpConstant %1 23.2450008 +)"); +} + +} // namespace spirv +} // namespace writer +} // namespace tint +; diff --git a/src/writer/wgsl/generator_impl_array_accessor_test.cc b/src/writer/wgsl/generator_impl_array_accessor_test.cc index 51f7c6cb74..4fd4c9d538 100644 --- a/src/writer/wgsl/generator_impl_array_accessor_test.cc +++ b/src/writer/wgsl/generator_impl_array_accessor_test.cc @@ -19,6 +19,7 @@ #include "src/ast/const_initializer_expression.h" #include "src/ast/identifier_expression.h" #include "src/ast/int_literal.h" +#include "src/ast/type/i32_type.h" #include "src/writer/wgsl/generator_impl.h" namespace tint { @@ -29,7 +30,8 @@ namespace { using GeneratorImplTest = testing::Test; TEST_F(GeneratorImplTest, EmitExpression_ArrayAccessor) { - auto lit = std::make_unique(5); + ast::type::I32Type i32; + auto lit = std::make_unique(&i32, 5); auto idx = std::make_unique(std::move(lit)); auto ary = std::make_unique("ary"); diff --git a/src/writer/wgsl/generator_impl_case_test.cc b/src/writer/wgsl/generator_impl_case_test.cc index 06b66834e8..d23c7853db 100644 --- a/src/writer/wgsl/generator_impl_case_test.cc +++ b/src/writer/wgsl/generator_impl_case_test.cc @@ -20,6 +20,7 @@ #include "src/ast/case_statement.h" #include "src/ast/identifier_expression.h" #include "src/ast/int_literal.h" +#include "src/ast/type/i32_type.h" #include "src/writer/wgsl/generator_impl.h" namespace tint { @@ -30,7 +31,8 @@ namespace { using GeneratorImplTest = testing::Test; TEST_F(GeneratorImplTest, Emit_Case) { - auto cond = std::make_unique(5); + ast::type::I32Type i32; + auto cond = std::make_unique(&i32, 5); std::vector> body; body.push_back(std::make_unique()); diff --git a/src/writer/wgsl/generator_impl_initializer_test.cc b/src/writer/wgsl/generator_impl_initializer_test.cc index 6a6876fd05..44ae88af33 100644 --- a/src/writer/wgsl/generator_impl_initializer_test.cc +++ b/src/writer/wgsl/generator_impl_initializer_test.cc @@ -38,7 +38,8 @@ namespace { using GeneratorImplTest = testing::Test; TEST_F(GeneratorImplTest, EmitInitializer_Bool) { - auto lit = std::make_unique(false); + ast::type::BoolType bool_type; + auto lit = std::make_unique(&bool_type, false); ast::ConstInitializerExpression expr(std::move(lit)); GeneratorImpl g; @@ -47,7 +48,8 @@ TEST_F(GeneratorImplTest, EmitInitializer_Bool) { } TEST_F(GeneratorImplTest, EmitInitializer_Int) { - auto lit = std::make_unique(-12345); + ast::type::I32Type i32; + auto lit = std::make_unique(&i32, -12345); ast::ConstInitializerExpression expr(std::move(lit)); GeneratorImpl g; @@ -56,7 +58,8 @@ TEST_F(GeneratorImplTest, EmitInitializer_Int) { } TEST_F(GeneratorImplTest, EmitInitializer_UInt) { - auto lit = std::make_unique(56779); + ast::type::U32Type u32; + auto lit = std::make_unique(&u32, 56779); ast::ConstInitializerExpression expr(std::move(lit)); GeneratorImpl g; @@ -65,7 +68,8 @@ TEST_F(GeneratorImplTest, EmitInitializer_UInt) { } TEST_F(GeneratorImplTest, EmitInitializer_Float) { - auto lit = std::make_unique(1.5e27); + ast::type::F32Type f32; + auto lit = std::make_unique(&f32, 1.5e27); ast::ConstInitializerExpression expr(std::move(lit)); GeneratorImpl g; @@ -76,7 +80,7 @@ TEST_F(GeneratorImplTest, EmitInitializer_Float) { TEST_F(GeneratorImplTest, EmitInitializer_Type_Float) { ast::type::F32Type f32; - auto lit = std::make_unique(-1.2e-5); + auto lit = std::make_unique(&f32, -1.2e-5); std::vector> values; values.push_back( std::make_unique(std::move(lit))); @@ -91,7 +95,7 @@ TEST_F(GeneratorImplTest, EmitInitializer_Type_Float) { TEST_F(GeneratorImplTest, EmitInitializer_Type_Bool) { ast::type::BoolType b; - auto lit = std::make_unique(true); + auto lit = std::make_unique(&b, true); std::vector> values; values.push_back( std::make_unique(std::move(lit))); @@ -106,7 +110,7 @@ TEST_F(GeneratorImplTest, EmitInitializer_Type_Bool) { TEST_F(GeneratorImplTest, EmitInitializer_Type_Int) { ast::type::I32Type i32; - auto lit = std::make_unique(-12345); + auto lit = std::make_unique(&i32, -12345); std::vector> values; values.push_back( std::make_unique(std::move(lit))); @@ -121,7 +125,7 @@ TEST_F(GeneratorImplTest, EmitInitializer_Type_Int) { TEST_F(GeneratorImplTest, EmitInitializer_Type_Uint) { ast::type::U32Type u32; - auto lit = std::make_unique(12345); + auto lit = std::make_unique(&u32, 12345); std::vector> values; values.push_back( std::make_unique(std::move(lit))); @@ -137,9 +141,9 @@ TEST_F(GeneratorImplTest, EmitInitializer_Type_Vec) { ast::type::F32Type f32; ast::type::VectorType vec(&f32, 3); - auto lit1 = std::make_unique(1.f); - auto lit2 = std::make_unique(2.f); - auto lit3 = std::make_unique(3.f); + auto lit1 = std::make_unique(&f32, 1.f); + auto lit2 = std::make_unique(&f32, 2.f); + auto lit3 = std::make_unique(&f32, 3.f); std::vector> values; values.push_back( std::make_unique(std::move(lit1))); @@ -164,8 +168,8 @@ TEST_F(GeneratorImplTest, EmitInitializer_Type_Mat) { std::vector> mat_values; for (size_t i = 0; i < 3; i++) { - auto lit1 = std::make_unique(1.f + (i * 2)); - auto lit2 = std::make_unique(2.f + (i * 2)); + auto lit1 = std::make_unique(&f32, 1.f + (i * 2)); + auto lit2 = std::make_unique(&f32, 2.f + (i * 2)); std::vector> values; values.push_back( @@ -195,9 +199,9 @@ TEST_F(GeneratorImplTest, EmitInitializer_Type_Array) { std::vector> ary_values; for (size_t i = 0; i < 3; i++) { - auto lit1 = std::make_unique(1.f + (i * 3)); - auto lit2 = std::make_unique(2.f + (i * 3)); - auto lit3 = std::make_unique(3.f + (i * 3)); + auto lit1 = std::make_unique(&f32, 1.f + (i * 3)); + auto lit2 = std::make_unique(&f32, 2.f + (i * 3)); + auto lit3 = std::make_unique(&f32, 3.f + (i * 3)); std::vector> values; values.push_back( diff --git a/src/writer/wgsl/generator_impl_switch_test.cc b/src/writer/wgsl/generator_impl_switch_test.cc index 22f8f43972..af82f6d0be 100644 --- a/src/writer/wgsl/generator_impl_switch_test.cc +++ b/src/writer/wgsl/generator_impl_switch_test.cc @@ -21,6 +21,7 @@ #include "src/ast/identifier_expression.h" #include "src/ast/int_literal.h" #include "src/ast/switch_statement.h" +#include "src/ast/type/i32_type.h" #include "src/writer/wgsl/generator_impl.h" namespace tint { @@ -36,7 +37,8 @@ TEST_F(GeneratorImplTest, Emit_Switch) { def_body.push_back(std::make_unique()); def->set_body(std::move(def_body)); - auto case_val = std::make_unique(5); + ast::type::I32Type i32; + auto case_val = std::make_unique(&i32, 5); std::vector> case_body; case_body.push_back(std::make_unique());