diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 481c2671be..20e5728b25 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -1656,6 +1656,7 @@ if (tint_build_unittests) { "reader/spirv/function_var_test.cc", "reader/spirv/namer_test.cc", "reader/spirv/parser_impl_barrier_test.cc", + "reader/spirv/parser_impl_constant_test.cc", "reader/spirv/parser_impl_convert_member_decoration_test.cc", "reader/spirv/parser_impl_convert_type_test.cc", "reader/spirv/parser_impl_function_decl_test.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index bdb1bbf9f5..4100d6c05b 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -1065,6 +1065,7 @@ if(TINT_BUILD_TESTS) reader/spirv/function_var_test.cc reader/spirv/namer_test.cc reader/spirv/parser_impl_barrier_test.cc + reader/spirv/parser_impl_constant_test.cc reader/spirv/parser_impl_convert_member_decoration_test.cc reader/spirv/parser_impl_convert_type_test.cc reader/spirv/parser_impl_function_decl_test.cc diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc index 59b64b178c..15af5b5eee 100644 --- a/src/tint/reader/spirv/parser_impl.cc +++ b/src/tint/reader/spirv/parser_impl.cc @@ -1953,11 +1953,20 @@ TypedExpression ParserImpl::MakeConstantExpressionForScalarSpirvConstant( // See https://bugs.chromium.org/p/tint/issues/detail?id=34 return Switch( ast_type, - [&](const I32*) { - return TypedExpression{ty_.I32(), - create( - source, static_cast(spirv_const->GetS32()), - ast::IntLiteralExpression::Suffix::kI)}; + [&](const I32*) -> TypedExpression { + const auto value = spirv_const->GetS32(); + if (value == std::numeric_limits::min()) { + // Avoid overflowing i-suffixed literal. + return {ty_.I32(), + builder_.Construct( + source, builder_.ty.i32(), + create( + source, value, ast::IntLiteralExpression::Suffix::kNone))}; + } else { + return {ty_.I32(), + create(source, static_cast(value), + ast::IntLiteralExpression::Suffix::kI)}; + } }, [&](const U32*) { return TypedExpression{ty_.U32(), diff --git a/src/tint/reader/spirv/parser_impl_constant_test.cc b/src/tint/reader/spirv/parser_impl_constant_test.cc new file mode 100644 index 0000000000..4e342f7f5f --- /dev/null +++ b/src/tint/reader/spirv/parser_impl_constant_test.cc @@ -0,0 +1,142 @@ +// 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 "gmock/gmock.h" +#include "src/tint/reader/spirv/parser_impl_test_helper.h" +#include "src/tint/reader/spirv/spirv_tools_helpers_test.h" + +namespace tint::reader::spirv { +namespace { + +using ::testing::Eq; +using ::testing::HasSubstr; + +std::string Preamble() { + return R"( + OpCapability Shader + OpCapability Sampled1D + OpCapability Image1D + OpCapability StorageImageExtendedFormats + OpCapability ImageQuery + OpMemoryModel Logical Simple + )"; +} + +std::string FragMain() { + return R"( + OpEntryPoint Fragment %main "main" ; assume no IO + OpExecutionMode %main OriginUpperLeft + )"; +} + +std::string MainBody() { + return R"( + %main = OpFunction %void None %voidfn + %main_entry = OpLabel + OpReturn + OpFunctionEnd + )"; +} + +std::string CommonTypes() { + return R"( + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + + %bool = OpTypeBool + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + + %v2int = OpTypeVector %int 2 + %v3int = OpTypeVector %int 3 + %v4int = OpTypeVector %int 4 + %v2uint = OpTypeVector %uint 2 + %v3uint = OpTypeVector %uint 3 + %v4uint = OpTypeVector %uint 4 + %v2float = OpTypeVector %float 2 + %v3float = OpTypeVector %float 3 + %v4float = OpTypeVector %float 4 + + %true = OpConstantTrue %bool + %false = OpConstantFalse %bool + + %int_1 = OpConstant %int 1 + %int_m5 = OpConstant %int -5 + %int_min = OpConstant %int 0x80000000 + %int_max = OpConstant %int 0x7fffffff + %uint_0 = OpConstant %uint 0 + %uint_max = OpConstant %uint 0xffffffff + + %float_minus_5 = OpConstant %float -5 + %float_half = OpConstant %float 0.5 + %float_ten = OpConstant %float 10 + )"; +} + +struct ConstantCase { + std::string spirv_type; + std::string spirv_value; + std::string wgsl_value; +}; +inline std::ostream& operator<<(std::ostream& out, const ConstantCase& c) { + out << "ConstantCase(" << c.spirv_type << ", " << c.spirv_value << ", " << c.wgsl_value << ")"; + return out; +} + +using SpvParserConstantTest = SpvParserTestBase<::testing::TestWithParam>; + +TEST_P(SpvParserConstantTest, ReturnValue) { + const auto spirv_type = GetParam().spirv_type; + const auto spirv_value = GetParam().spirv_value; + const auto wgsl_value = GetParam().wgsl_value; + const auto assembly = Preamble() + FragMain() + CommonTypes() + R"( + %fty = OpTypeFunction )" + + spirv_type + R"( + + %200 = OpFunction )" + + spirv_type + R"( None %fty + %fentry = OpLabel + OpReturnValue )" + spirv_value + + R"( + OpFunctionEnd + )" + MainBody(); + auto p = parser(test::Assemble(assembly)); + ASSERT_TRUE(p->Parse()); + auto fe = p->function_emitter(200); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + EXPECT_TRUE(p->error().empty()); + const auto got = test::ToString(p->program(), fe.ast_body()); + const auto expect = std::string("return ") + wgsl_value + std::string(";\n"); + + EXPECT_EQ(got, expect); +} + +INSTANTIATE_TEST_SUITE_P(Scalars, + SpvParserConstantTest, + ::testing::ValuesIn(std::vector{ + {"%bool", "%true", "true"}, + {"%bool", "%false", "false"}, + {"%int", "%int_1", "1i"}, + {"%int", "%int_m5", "-5i"}, + {"%int", "%int_min", "i32(-2147483648)"}, + {"%int", "%int_max", "2147483647i"}, + {"%uint", "%uint_0", "0u"}, + {"%uint", "%uint_max", "4294967295u"}, + {"%float", "%float_minus_5", "-5.0f"}, + {"%float", "%float_half", "0.5f"}, + {"%float", "%float_ten", "10.0f"}})); + +} // namespace +} // namespace tint::reader::spirv