// Copyright 2021 The Tint Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/tint/resolver/resolver.h" #include "gtest/gtest.h" #include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/sem/expression.h" using namespace tint::number_suffixes; // NOLINT namespace tint::resolver { namespace { using ResolverConstantsTest = ResolverTest; TEST_F(ResolverConstantsTest, Scalar_i32) { auto* expr = Expr(99_i); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); EXPECT_TRUE(sem->Type()->Is()); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 99); } TEST_F(ResolverConstantsTest, Scalar_u32) { auto* expr = Expr(99_u); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); EXPECT_TRUE(sem->Type()->Is()); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 99u); } TEST_F(ResolverConstantsTest, Scalar_f32) { auto* expr = Expr(9.9_f); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); EXPECT_TRUE(sem->Type()->Is()); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 9.9f); } TEST_F(ResolverConstantsTest, Scalar_bool) { auto* expr = Expr(true); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); EXPECT_TRUE(sem->Type()->Is()); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 1u); EXPECT_EQ(sem->ConstantValue().Element(0), true); } TEST_F(ResolverConstantsTest, Vec3_ZeroInit_i32) { auto* expr = vec3(); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 0); EXPECT_EQ(sem->ConstantValue().Element(1).value, 0); EXPECT_EQ(sem->ConstantValue().Element(2).value, 0); } TEST_F(ResolverConstantsTest, Vec3_ZeroInit_u32) { auto* expr = vec3(); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 0u); EXPECT_EQ(sem->ConstantValue().Element(1).value, 0u); EXPECT_EQ(sem->ConstantValue().Element(2).value, 0u); } TEST_F(ResolverConstantsTest, Vec3_ZeroInit_f32) { auto* expr = vec3(); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 0.0); EXPECT_EQ(sem->ConstantValue().Element(1).value, 0.0); EXPECT_EQ(sem->ConstantValue().Element(2).value, 0.0); } TEST_F(ResolverConstantsTest, Vec3_ZeroInit_bool) { auto* expr = vec3(); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0), false); EXPECT_EQ(sem->ConstantValue().Element(1), false); EXPECT_EQ(sem->ConstantValue().Element(2), false); } TEST_F(ResolverConstantsTest, Vec3_Splat_i32) { auto* expr = vec3(99_i); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 99); EXPECT_EQ(sem->ConstantValue().Element(1).value, 99); EXPECT_EQ(sem->ConstantValue().Element(2).value, 99); } TEST_F(ResolverConstantsTest, Vec3_Splat_u32) { auto* expr = vec3(99_u); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 99u); EXPECT_EQ(sem->ConstantValue().Element(1).value, 99u); EXPECT_EQ(sem->ConstantValue().Element(2).value, 99u); } TEST_F(ResolverConstantsTest, Vec3_Splat_f32) { auto* expr = vec3(9.9_f); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 9.9f); EXPECT_EQ(sem->ConstantValue().Element(1).value, 9.9f); EXPECT_EQ(sem->ConstantValue().Element(2).value, 9.9f); } TEST_F(ResolverConstantsTest, Vec3_Splat_bool) { auto* expr = vec3(true); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0), true); EXPECT_EQ(sem->ConstantValue().Element(1), true); EXPECT_EQ(sem->ConstantValue().Element(2), true); } TEST_F(ResolverConstantsTest, Vec3_FullConstruct_i32) { auto* expr = vec3(1_i, 2_i, 3_i); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 1); EXPECT_EQ(sem->ConstantValue().Element(1).value, 2); EXPECT_EQ(sem->ConstantValue().Element(2).value, 3); } TEST_F(ResolverConstantsTest, Vec3_FullConstruct_u32) { auto* expr = vec3(1_u, 2_u, 3_u); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 1); EXPECT_EQ(sem->ConstantValue().Element(1).value, 2); EXPECT_EQ(sem->ConstantValue().Element(2).value, 3); } TEST_F(ResolverConstantsTest, Vec3_FullConstruct_f32) { auto* expr = vec3(1_f, 2_f, 3_f); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 1.f); EXPECT_EQ(sem->ConstantValue().Element(1).value, 2.f); EXPECT_EQ(sem->ConstantValue().Element(2).value, 3.f); } TEST_F(ResolverConstantsTest, Vec3_FullConstruct_bool) { auto* expr = vec3(true, false, true); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0), true); EXPECT_EQ(sem->ConstantValue().Element(1), false); EXPECT_EQ(sem->ConstantValue().Element(2), true); } TEST_F(ResolverConstantsTest, Vec3_MixConstruct_i32) { auto* expr = vec3(1_i, vec2(2_i, 3_i)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 1); EXPECT_EQ(sem->ConstantValue().Element(1).value, 2); EXPECT_EQ(sem->ConstantValue().Element(2).value, 3); } TEST_F(ResolverConstantsTest, Vec3_MixConstruct_u32) { auto* expr = vec3(vec2(1_u, 2_u), 3_u); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 1); EXPECT_EQ(sem->ConstantValue().Element(1).value, 2); EXPECT_EQ(sem->ConstantValue().Element(2).value, 3); } TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32) { auto* expr = vec3(1_f, vec2(2_f, 3_f)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 1.f); EXPECT_EQ(sem->ConstantValue().Element(1).value, 2.f); EXPECT_EQ(sem->ConstantValue().Element(2).value, 3.f); } TEST_F(ResolverConstantsTest, Vec3_MixConstruct_bool) { auto* expr = vec3(vec2(true, false), true); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0), true); EXPECT_EQ(sem->ConstantValue().Element(1), false); EXPECT_EQ(sem->ConstantValue().Element(2), true); } TEST_F(ResolverConstantsTest, Vec3_Convert_f32_to_i32) { auto* expr = vec3(vec3(1.1_f, 2.2_f, 3.3_f)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 1); EXPECT_EQ(sem->ConstantValue().Element(1).value, 2); EXPECT_EQ(sem->ConstantValue().Element(2).value, 3); } TEST_F(ResolverConstantsTest, Vec3_Convert_u32_to_f32) { auto* expr = vec3(vec3(10_u, 20_u, 30_u)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 10.f); EXPECT_EQ(sem->ConstantValue().Element(1).value, 20.f); EXPECT_EQ(sem->ConstantValue().Element(2).value, 30.f); } TEST_F(ResolverConstantsTest, Vec3_Convert_Large_f32_to_i32) { auto* expr = vec3(vec3(1e10_f, -1e20_f, 1e30_f)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, i32::kHighest); EXPECT_EQ(sem->ConstantValue().Element(1).value, i32::kLowest); EXPECT_EQ(sem->ConstantValue().Element(2).value, i32::kHighest); } TEST_F(ResolverConstantsTest, Vec3_Convert_Large_f32_to_u32) { auto* expr = vec3(vec3(1e10_f, -1e20_f, 1e30_f)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, u32::kHighest); EXPECT_EQ(sem->ConstantValue().Element(1).value, u32::kLowest); EXPECT_EQ(sem->ConstantValue().Element(2).value, u32::kHighest); } // TODO(crbug.com/tint/1502): Enable when f16 overloads are implemented TEST_F(ResolverConstantsTest, DISABLED_Vec3_Convert_Large_f32_to_f16) { Enable(ast::Extension::kF16); auto* expr = vec3(vec3(0.00001_f, -0.00002_f, 0.00003_f)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); constexpr auto kInf = std::numeric_limits::infinity(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, kInf); EXPECT_EQ(sem->ConstantValue().Element(1).value, -kInf); EXPECT_EQ(sem->ConstantValue().Element(2).value, kInf); } // TODO(crbug.com/tint/1502): Enable when f16 overloads are implemented TEST_F(ResolverConstantsTest, DISABLED_Vec3_Convert_Small_f32_to_f16) { Enable(ast::Extension::kF16); auto* expr = vec3(vec3(1e-10_f, -1e20_f, 1e30_f)); WrapInFunction(expr); EXPECT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(expr); EXPECT_NE(sem, nullptr); ASSERT_TRUE(sem->Type()->Is()); EXPECT_TRUE(sem->Type()->As()->type()->Is()); EXPECT_EQ(sem->Type()->As()->Width(), 3u); EXPECT_EQ(sem->ConstantValue().Type(), sem->Type()); EXPECT_TRUE(sem->ConstantValue().ElementType()->Is()); ASSERT_EQ(sem->ConstantValue().ElementCount(), 3u); EXPECT_EQ(sem->ConstantValue().Element(0).value, 0.0); EXPECT_EQ(sem->ConstantValue().Element(1).value, -0.0); EXPECT_EQ(sem->ConstantValue().Element(2).value, 0.0); } } // namespace } // namespace tint::resolver