| // 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 "src/tint/ast/call_statement.h" |
| #include "src/tint/ast/stage_attribute.h" |
| #include "src/tint/type/depth_texture.h" |
| #include "src/tint/type/texture_dimension.h" |
| #include "src/tint/utils/string.h" |
| #include "src/tint/writer/spirv/spv_dump.h" |
| #include "src/tint/writer/spirv/test_helper.h" |
| |
| namespace tint::writer::spirv { |
| namespace { |
| |
| using namespace tint::builtin::fluent_types; // NOLINT |
| using namespace tint::number_suffixes; // NOLINT |
| |
| using BuiltinBuilderTest = TestHelper; |
| |
| template <typename T> |
| using BuiltinBuilderTestWithParam = TestParamHelper<T>; |
| |
| struct BuiltinData { |
| std::string name; |
| std::string op; |
| }; |
| inline std::ostream& operator<<(std::ostream& out, BuiltinData data) { |
| out << data.name; |
| return out; |
| } |
| |
| // This tests that we do not push OpTypeSampledImage and float_0 type twice. |
| TEST_F(BuiltinBuilderTest, Call_TextureSampleCompare_Twice) { |
| auto s = ty.sampler(type::SamplerKind::kComparisonSampler); |
| auto t = ty.depth_texture(type::TextureDimension::k2d); |
| |
| auto* tex = GlobalVar("texture", t, Binding(0_a), Group(0_a)); |
| auto* sampler = GlobalVar("sampler", s, Binding(1_a), Group(0_a)); |
| |
| auto* expr1 = |
| Call("textureSampleCompare", "texture", "sampler", Call<vec2<f32>>(1_f, 2_f), 2_f); |
| auto* expr2 = |
| Call("textureSampleCompare", "texture", "sampler", Call<vec2<f32>>(1_f, 2_f), 2_f); |
| |
| Func("f1", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr1)), |
| }, |
| utils::Empty); |
| Func("f2", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr2)), |
| }, |
| utils::Empty); |
| |
| spirv::Builder& b = Build(); |
| |
| b.PushFunctionForTesting(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.Diagnostics(); |
| |
| EXPECT_EQ(b.GenerateExpression(expr1), 8u) << b.Diagnostics(); |
| EXPECT_EQ(b.GenerateExpression(expr2), 17u) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%4 = OpTypeFloat 32 |
| %3 = OpTypeImage %4 2D 0 0 0 1 Unknown |
| %2 = OpTypePointer UniformConstant %3 |
| %1 = OpVariable %2 UniformConstant |
| %7 = OpTypeSampler |
| %6 = OpTypePointer UniformConstant %7 |
| %5 = OpVariable %6 UniformConstant |
| %11 = OpTypeSampledImage %3 |
| %13 = OpTypeVector %4 2 |
| %14 = OpConstant %4 1 |
| %15 = OpConstant %4 2 |
| %16 = OpConstantComposite %13 %14 %15 |
| )"); |
| |
| EXPECT_EQ(DumpInstructions(b.CurrentFunction().instructions()), |
| R"(%9 = OpLoad %7 %5 |
| %10 = OpLoad %3 %1 |
| %12 = OpSampledImage %11 %10 %9 |
| %8 = OpImageSampleDrefImplicitLod %4 %12 %16 %15 |
| %18 = OpLoad %7 %5 |
| %19 = OpLoad %3 %1 |
| %20 = OpSampledImage %11 %19 %18 |
| %17 = OpImageSampleDrefImplicitLod %4 %20 %16 %15 |
| )"); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad_f32) { |
| auto* var = GlobalVar("ident", ty.f32(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call("round", "ident"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = |
| R"(%10 = OpExtInstImport "GLSL.std.450" |
| OpName %1 "ident" |
| OpName %7 "a_func" |
| %3 = OpTypeFloat 32 |
| %2 = OpTypePointer Private %3 |
| %4 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %4 |
| %6 = OpTypeVoid |
| %5 = OpTypeFunction %6 |
| %7 = OpFunction %6 None %5 |
| %8 = OpLabel |
| %11 = OpLoad %3 %1 |
| %9 = OpExtInst %3 %10 RoundEven %11 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* var = GlobalVar("ident", ty.f16(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call("round", "ident"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = |
| R"(%10 = OpExtInstImport "GLSL.std.450" |
| OpName %1 "ident" |
| OpName %7 "a_func" |
| %3 = OpTypeFloat 16 |
| %2 = OpTypePointer Private %3 |
| %4 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %4 |
| %6 = OpTypeVoid |
| %5 = OpTypeFunction %6 |
| %7 = OpFunction %6 None %5 |
| %8 = OpLabel |
| %11 = OpLoad %3 %1 |
| %9 = OpExtInst %3 %10 RoundEven %11 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| // Tests for Logical builtins |
| namespace logical_builtin_tests { |
| |
| using BuiltinBoolTest = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(BuiltinBoolTest, Call_Bool_Scalar) { |
| auto param = GetParam(); |
| auto* var = GlobalVar("v", ty.bool_(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call(param.name, "v"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%3 = OpTypeBool |
| %2 = OpTypePointer Private %3 |
| %4 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %4 |
| %6 = OpTypeVoid |
| %5 = OpTypeFunction %6 |
| )"); |
| |
| // both any and all are 'passthrough' for scalar booleans |
| EXPECT_EQ(DumpInstructions(b.Module().Functions()[0].instructions()), |
| "%10 = OpLoad %3 %1\nOpReturn\n"); |
| } |
| |
| TEST_P(BuiltinBoolTest, Call_Bool_Vector) { |
| auto param = GetParam(); |
| auto* var = GlobalVar("v", ty.vec3<bool>(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call(param.name, "v"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%4 = OpTypeBool |
| %3 = OpTypeVector %4 3 |
| %2 = OpTypePointer Private %3 |
| %5 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %5 |
| %7 = OpTypeVoid |
| %6 = OpTypeFunction %7 |
| )"); |
| |
| auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 |
| %10 = ${op} %4 %11 |
| OpReturn |
| )", |
| "${op}", param.op); |
| EXPECT_EQ(DumpInstructions(b.Module().Functions()[0].instructions()), expected); |
| } |
| INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest, |
| BuiltinBoolTest, |
| testing::Values(BuiltinData{"any", "OpAny"}, BuiltinData{"all", "OpAll"})); |
| |
| TEST_F(BuiltinBuilderTest, Call_Select) { |
| auto* v3 = GlobalVar("v3", ty.vec3<f32>(), builtin::AddressSpace::kPrivate); |
| |
| auto* bool_v3 = GlobalVar("bool_v3", ty.vec3<bool>(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call("select", "v3", "v3", "bool_v3"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(v3)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateGlobalVariable(bool_v3)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%4 = OpTypeFloat 32 |
| %3 = OpTypeVector %4 3 |
| %2 = OpTypePointer Private %3 |
| %5 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %5 |
| %9 = OpTypeBool |
| %8 = OpTypeVector %9 3 |
| %7 = OpTypePointer Private %8 |
| %10 = OpConstantNull %8 |
| %6 = OpVariable %7 Private %10 |
| %12 = OpTypeVoid |
| %11 = OpTypeFunction %12 |
| )"); |
| EXPECT_EQ(DumpInstructions(b.Module().Functions()[0].instructions()), |
| R"(%16 = OpLoad %8 %6 |
| %17 = OpLoad %3 %1 |
| %18 = OpLoad %3 %1 |
| %15 = OpSelect %3 %16 %17 %18 |
| OpReturn |
| )"); |
| } |
| |
| } // namespace logical_builtin_tests |
| |
| // Tests for Array builtins |
| namespace array_builtin_tests { |
| |
| TEST_F(BuiltinBuilderTest, Call_ArrayLength) { |
| auto* s = Structure("my_struct", utils::Vector{ |
| Member("a", ty.array<f32>()), |
| }); |
| GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a), |
| Group(2_a)); |
| auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a"))); |
| |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = SanitizeAndBuild(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| |
| ASSERT_EQ(b.Module().Functions().size(), 1_u); |
| |
| auto* expected_types = R"(%5 = OpTypeFloat 32 |
| %4 = OpTypeRuntimeArray %5 |
| %3 = OpTypeStruct %4 |
| %2 = OpTypePointer StorageBuffer %3 |
| %1 = OpVariable %2 StorageBuffer |
| %7 = OpTypeVoid |
| %6 = OpTypeFunction %7 |
| %11 = OpTypeInt 32 0 |
| )"; |
| auto got_types = DumpInstructions(b.Module().Types()); |
| EXPECT_EQ(expected_types, got_types); |
| |
| auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 |
| OpReturn |
| )"; |
| auto got_instructions = DumpInstructions(b.Module().Functions()[0].instructions()); |
| EXPECT_EQ(expected_instructions, got_instructions); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_ArrayLength_OtherMembersInStruct) { |
| auto* s = Structure("my_struct", utils::Vector{ |
| Member("z", ty.f32()), |
| Member(4, "a", ty.array<f32>()), |
| }); |
| GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a), |
| Group(2_a)); |
| auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a"))); |
| |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = SanitizeAndBuild(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| |
| ASSERT_EQ(b.Module().Functions().size(), 1_u); |
| |
| auto* expected_types = R"(%4 = OpTypeFloat 32 |
| %5 = OpTypeRuntimeArray %4 |
| %3 = OpTypeStruct %4 %5 |
| %2 = OpTypePointer StorageBuffer %3 |
| %1 = OpVariable %2 StorageBuffer |
| %7 = OpTypeVoid |
| %6 = OpTypeFunction %7 |
| %11 = OpTypeInt 32 0 |
| )"; |
| auto got_types = DumpInstructions(b.Module().Types()); |
| EXPECT_EQ(expected_types, got_types); |
| |
| auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1 |
| OpReturn |
| )"; |
| auto got_instructions = DumpInstructions(b.Module().Functions()[0].instructions()); |
| EXPECT_EQ(expected_instructions, got_instructions); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets) { |
| auto* s = Structure("my_struct", utils::Vector{ |
| Member("a", ty.array<f32>()), |
| }); |
| GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a), |
| Group(2_a)); |
| |
| auto* p = Let("p", AddressOf("b")); |
| auto* p2 = Let("p2", AddressOf(MemberAccessor(Deref(p), "a"))); |
| auto* expr = Call("arrayLength", p2); |
| |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(p), |
| Decl(p2), |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = SanitizeAndBuild(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| |
| ASSERT_EQ(b.Module().Functions().size(), 1_u); |
| |
| auto* expected_types = R"(%5 = OpTypeFloat 32 |
| %4 = OpTypeRuntimeArray %5 |
| %3 = OpTypeStruct %4 |
| %2 = OpTypePointer StorageBuffer %3 |
| %1 = OpVariable %2 StorageBuffer |
| %7 = OpTypeVoid |
| %6 = OpTypeFunction %7 |
| %11 = OpTypeInt 32 0 |
| )"; |
| auto got_types = DumpInstructions(b.Module().Types()); |
| EXPECT_EQ(expected_types, got_types); |
| |
| auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 |
| OpReturn |
| )"; |
| auto got_instructions = DumpInstructions(b.Module().Functions()[0].instructions()); |
| EXPECT_EQ(expected_instructions, got_instructions); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) { |
| // struct my_struct { |
| // a : array<f32>; |
| // }; |
| // @binding(1) @group(2) var<storage, read> b : my_struct; |
| // |
| // fn a_func() { |
| // let p = &*&b; |
| // let p2 = &*p; |
| // let p3 = &((*p).a); |
| // arrayLength(&*p3); |
| // } |
| auto* s = Structure("my_struct", utils::Vector{ |
| Member("a", ty.array<f32>()), |
| }); |
| GlobalVar("b", ty.Of(s), builtin::AddressSpace::kStorage, builtin::Access::kRead, Binding(1_a), |
| Group(2_a)); |
| |
| auto* p = Let("p", AddressOf(Deref(AddressOf("b")))); |
| auto* p2 = Let("p2", AddressOf(Deref(p))); |
| auto* p3 = Let("p3", AddressOf(MemberAccessor(Deref(p2), "a"))); |
| auto* expr = Call("arrayLength", AddressOf(Deref(p3))); |
| |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(p), |
| Decl(p2), |
| Decl(p3), |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = SanitizeAndBuild(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| |
| ASSERT_EQ(b.Module().Functions().size(), 1_u); |
| |
| auto* expected_types = R"(%5 = OpTypeFloat 32 |
| %4 = OpTypeRuntimeArray %5 |
| %3 = OpTypeStruct %4 |
| %2 = OpTypePointer StorageBuffer %3 |
| %1 = OpVariable %2 StorageBuffer |
| %7 = OpTypeVoid |
| %6 = OpTypeFunction %7 |
| %11 = OpTypeInt 32 0 |
| )"; |
| auto got_types = DumpInstructions(b.Module().Types()); |
| EXPECT_EQ(expected_types, got_types); |
| |
| auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 |
| OpReturn |
| )"; |
| auto got_instructions = DumpInstructions(b.Module().Functions()[0].instructions()); |
| EXPECT_EQ(expected_instructions, got_instructions); |
| |
| Validate(b); |
| } |
| |
| } // namespace array_builtin_tests |
| |
| // Tests for Numeric builtins with float parameter |
| namespace float_builtin_tests { |
| |
| using Builtin_Builder_SingleParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Scalar_f32) { |
| auto param = GetParam(); |
| // Use a variable to prevent the function being evaluated as constant. |
| auto* scalar = Var("a", Expr(1_f)); |
| auto* expr = Call(param.name, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 32 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Scalar_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto param = GetParam(); |
| // Use a variable to prevent the function being evaluated as constant. |
| auto* scalar = Var("a", Expr(1_h)); |
| auto* expr = Call(param.name, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 16 |
| %6 = OpConstant %5 0x1p+0 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Vector_f32) { |
| auto param = GetParam(); |
| |
| // Use a variable to prevent the function being evaluated as constant. |
| auto* vec = Var("a", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call(param.name, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_SingleParam_Float_Test, Call_Vector_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto param = GetParam(); |
| |
| // Use a variable to prevent the function being evaluated as constant. |
| auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call(param.name, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest, |
| Builtin_Builder_SingleParam_Float_Test, |
| testing::Values(BuiltinData{"abs", "FAbs"}, |
| BuiltinData{"acos", "Acos"}, |
| BuiltinData{"asin", "Asin"}, |
| BuiltinData{"atan", "Atan"}, |
| BuiltinData{"ceil", "Ceil"}, |
| BuiltinData{"cos", "Cos"}, |
| BuiltinData{"cosh", "Cosh"}, |
| BuiltinData{"degrees", "Degrees"}, |
| BuiltinData{"exp", "Exp"}, |
| BuiltinData{"exp2", "Exp2"}, |
| BuiltinData{"floor", "Floor"}, |
| BuiltinData{"fract", "Fract"}, |
| BuiltinData{"inverseSqrt", "InverseSqrt"}, |
| BuiltinData{"log", "Log"}, |
| BuiltinData{"log2", "Log2"}, |
| BuiltinData{"radians", "Radians"}, |
| BuiltinData{"round", "RoundEven"}, |
| BuiltinData{"sign", "FSign"}, |
| BuiltinData{"sin", "Sin"}, |
| BuiltinData{"sinh", "Sinh"}, |
| BuiltinData{"sqrt", "Sqrt"}, |
| BuiltinData{"tan", "Tan"}, |
| BuiltinData{"tanh", "Tanh"}, |
| BuiltinData{"trunc", "Trunc"})); |
| |
| TEST_F(BuiltinBuilderTest, Call_Length_Scalar_f32) { |
| auto* scalar = Var("a", Expr(1_f)); |
| auto* expr = Call("length", scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 32 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 Length %12 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Length_Scalar_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* scalar = Var("a", Expr(1_h)); |
| auto* expr = Call("length", scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 16 |
| %6 = OpConstant %5 0x1p+0 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 Length %12 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Length_Vector_f32) { |
| auto* vec = Var("a", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call("length", vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %12 = OpExtInst %6 %13 Length %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Length_Vector_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call("length", vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %12 = OpExtInst %6 %13 Length %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Normalize_f32) { |
| auto* vec = Var("a", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call("normalize", vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 Normalize %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Normalize_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call("normalize", vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "a" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 Normalize %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| using Builtin_Builder_DualParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Scalar_f32) { |
| auto param = GetParam(); |
| auto* scalar = Var("scalar", Expr(1_f)); |
| auto* expr = Call(param.name, scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 32 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %13 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 %13 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Scalar_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto param = GetParam(); |
| auto* scalar = Var("scalar", Expr(1_h)); |
| auto* expr = Call(param.name, scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 16 |
| %6 = OpConstant %5 0x1p+0 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %13 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 %13 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Vector_f32) { |
| auto param = GetParam(); |
| auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call(param.name, vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Vector_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto param = GetParam(); |
| auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call(param.name, vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest, |
| Builtin_Builder_DualParam_Float_Test, |
| testing::Values(BuiltinData{"atan2", "Atan2"}, |
| BuiltinData{"max", "NMax"}, |
| BuiltinData{"min", "NMin"}, |
| BuiltinData{"pow", "Pow"}, |
| BuiltinData{"step", "Step"})); |
| |
| TEST_F(BuiltinBuilderTest, Call_Reflect_Vector_f32) { |
| auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call("reflect", vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 Reflect %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Reflect_Vector_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call("reflect", vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 Reflect %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Distance_Scalar_f32) { |
| auto* scalar = Var("scalar", Expr(1_f)); |
| auto* expr = Call("distance", scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 32 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %13 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 Distance %12 %13 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Distance_Scalar_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* scalar = Var("scalar", Expr(1_h)); |
| auto* expr = Call("distance", scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 16 |
| %6 = OpConstant %5 0x1p+0 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %13 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 Distance %12 %13 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Distance_Vector_f32) { |
| auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call("distance", vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %6 %13 Distance %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Distance_Vector_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call("distance", vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %6 %13 Distance %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Cross_f32) { |
| auto* vec = Var("vec", Call<vec3<f32>>(1_f, 1_f, 1_f)); |
| auto* expr = Call("cross", vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 3 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 Cross %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_Cross_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("vec", Call<vec3<f16>>(1_h, 1_h, 1_h)); |
| auto* expr = Call("cross", vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 3 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 Cross %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| using Builtin_Builder_ThreeParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Scalar_f32) { |
| auto param = GetParam(); |
| auto* scalar = Var("scalar", Expr(1_f)); |
| auto* expr = Call(param.name, scalar, scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 32 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %13 = OpLoad %5 %7 |
| %14 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 %13 %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Scalar_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto param = GetParam(); |
| auto* scalar = Var("scalar", Expr(1_h)); |
| auto* expr = Call(param.name, scalar, scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeFloat 16 |
| %6 = OpConstant %5 0x1p+0 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %13 = OpLoad %5 %7 |
| %14 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 %13 %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Vector_f32) { |
| auto param = GetParam(); |
| auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call(param.name, vec, vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %16 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 %15 %16 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Vector_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto param = GetParam(); |
| auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call(param.name, vec, vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %16 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 %15 %16 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest, |
| Builtin_Builder_ThreeParam_Float_Test, |
| testing::Values(BuiltinData{"clamp", "NClamp"}, |
| BuiltinData{"fma", "Fma"}, |
| BuiltinData{"mix", "FMix"}, |
| |
| BuiltinData{"smoothstep", "SmoothStep"})); |
| |
| TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector_f32) { |
| auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f)); |
| auto* expr = Call("faceForward", vec, vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %16 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 FaceForward %14 %15 %16 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h)); |
| auto* expr = Call("faceForward", vec, vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %16 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 FaceForward %14 %15 %16 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Runtime_Call_Modf_f32) { |
| auto* vec = Var("vec", Call<vec2<f32>>(1_f, 2_f)); |
| auto* expr = Call("modf", vec); |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| %15 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %10 "vec" |
| OpName %14 "__modf_result_vec2_f32" |
| OpMemberName %14 0 "fract" |
| OpMemberName %14 1 "whole" |
| OpMemberDecorate %14 0 Offset 0 |
| OpMemberDecorate %14 1 Offset 8 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstant %6 2 |
| %9 = OpConstantComposite %5 %7 %8 |
| %11 = OpTypePointer Function %5 |
| %12 = OpConstantNull %5 |
| %14 = OpTypeStruct %5 %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %10 = OpVariable %11 Function %12 |
| OpStore %10 %9 |
| %16 = OpLoad %5 %10 |
| %13 = OpExtInst %14 %15 ModfStruct %16 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Runtime_Call_Modf_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("vec", Call<vec2<f16>>(1_h, 2_h)); |
| auto* expr = Call("modf", vec); |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpCapability Float16 |
| OpCapability UniformAndStorageBuffer16BitAccess |
| OpCapability StorageBuffer16BitAccess |
| OpCapability StorageInputOutput16 |
| %15 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %10 "vec" |
| OpName %14 "__modf_result_vec2_f16" |
| OpMemberName %14 0 "fract" |
| OpMemberName %14 1 "whole" |
| OpMemberDecorate %14 0 Offset 0 |
| OpMemberDecorate %14 1 Offset 4 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstant %6 0x1p+1 |
| %9 = OpConstantComposite %5 %7 %8 |
| %11 = OpTypePointer Function %5 |
| %12 = OpConstantNull %5 |
| %14 = OpTypeStruct %5 %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %10 = OpVariable %11 Function %12 |
| OpStore %10 %9 |
| %16 = OpLoad %5 %10 |
| %13 = OpExtInst %14 %15 ModfStruct %16 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Const_Call_Modf_f32) { |
| auto* expr = Call("modf", Call<vec2<f32>>(1_f, 2_f)); |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %5 "__modf_result_vec2_f32" |
| OpMemberName %5 0 "fract" |
| OpMemberName %5 1 "whole" |
| OpMemberDecorate %5 0 Offset 0 |
| OpMemberDecorate %5 1 Offset 8 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %7 = OpTypeFloat 32 |
| %6 = OpTypeVector %7 2 |
| %5 = OpTypeStruct %6 %6 |
| %8 = OpConstantNull %6 |
| %9 = OpConstant %7 1 |
| %10 = OpConstant %7 2 |
| %11 = OpConstantComposite %6 %9 %10 |
| %12 = OpConstantComposite %5 %8 %11 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Const_Call_Modf_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* expr = Call("modf", Call<vec2<f16>>(1_h, 2_h)); |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpCapability Float16 |
| OpCapability UniformAndStorageBuffer16BitAccess |
| OpCapability StorageBuffer16BitAccess |
| OpCapability StorageInputOutput16 |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %5 "__modf_result_vec2_f16" |
| OpMemberName %5 0 "fract" |
| OpMemberName %5 1 "whole" |
| OpMemberDecorate %5 0 Offset 0 |
| OpMemberDecorate %5 1 Offset 4 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %7 = OpTypeFloat 16 |
| %6 = OpTypeVector %7 2 |
| %5 = OpTypeStruct %6 %6 |
| %8 = OpConstantNull %6 |
| %9 = OpConstant %7 0x1p+0 |
| %10 = OpConstant %7 0x1p+1 |
| %11 = OpConstantComposite %6 %9 %10 |
| %12 = OpConstantComposite %5 %8 %11 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Runtime_Call_Frexp_f32) { |
| auto* vec = Var("vec", Call<vec2<f32>>(1_f, 2_f)); |
| auto* expr = Call("frexp", vec); |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| %17 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %10 "vec" |
| OpName %14 "__frexp_result_vec2_f32" |
| OpMemberName %14 0 "fract" |
| OpMemberName %14 1 "exp" |
| OpMemberDecorate %14 0 Offset 0 |
| OpMemberDecorate %14 1 Offset 8 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstant %6 2 |
| %9 = OpConstantComposite %5 %7 %8 |
| %11 = OpTypePointer Function %5 |
| %12 = OpConstantNull %5 |
| %16 = OpTypeInt 32 1 |
| %15 = OpTypeVector %16 2 |
| %14 = OpTypeStruct %5 %15 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %10 = OpVariable %11 Function %12 |
| OpStore %10 %9 |
| %18 = OpLoad %5 %10 |
| %13 = OpExtInst %14 %17 FrexpStruct %18 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Runtime_Call_Frexp_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| auto* vec = Var("vec", Call<vec2<f16>>(1_h, 2_h)); |
| auto* expr = Call("frexp", vec); |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpCapability Float16 |
| OpCapability UniformAndStorageBuffer16BitAccess |
| OpCapability StorageBuffer16BitAccess |
| OpCapability StorageInputOutput16 |
| %17 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %10 "vec" |
| OpName %14 "__frexp_result_vec2_f16" |
| OpMemberName %14 0 "fract" |
| OpMemberName %14 1 "exp" |
| OpMemberDecorate %14 0 Offset 0 |
| OpMemberDecorate %14 1 Offset 8 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeFloat 16 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 0x1p+0 |
| %8 = OpConstant %6 0x1p+1 |
| %9 = OpConstantComposite %5 %7 %8 |
| %11 = OpTypePointer Function %5 |
| %12 = OpConstantNull %5 |
| %16 = OpTypeInt 32 1 |
| %15 = OpTypeVector %16 2 |
| %14 = OpTypeStruct %5 %15 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %10 = OpVariable %11 Function %12 |
| OpStore %10 %9 |
| %18 = OpLoad %5 %10 |
| %13 = OpExtInst %14 %17 FrexpStruct %18 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Const_Call_Frexp_f32) { |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", Call("frexp", Call<vec2<f32>>(1_f, 2_f)))), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %5 "__frexp_result_vec2_f32" |
| OpMemberName %5 0 "fract" |
| OpMemberName %5 1 "exp" |
| OpMemberDecorate %5 0 Offset 0 |
| OpMemberDecorate %5 1 Offset 8 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %7 = OpTypeFloat 32 |
| %6 = OpTypeVector %7 2 |
| %9 = OpTypeInt 32 1 |
| %8 = OpTypeVector %9 2 |
| %5 = OpTypeStruct %6 %8 |
| %10 = OpConstant %7 0.5 |
| %11 = OpConstantComposite %6 %10 %10 |
| %12 = OpConstant %9 1 |
| %13 = OpConstant %9 2 |
| %14 = OpConstantComposite %8 %12 %13 |
| %15 = OpConstantComposite %5 %11 %14 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Const_Call_Frexp_f16) { |
| Enable(builtin::Extension::kF16); |
| |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", Call("frexp", Call<vec2<f16>>(1_h, 2_h)))), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpCapability Float16 |
| OpCapability UniformAndStorageBuffer16BitAccess |
| OpCapability StorageBuffer16BitAccess |
| OpCapability StorageInputOutput16 |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %3 "a_func" |
| OpExecutionMode %3 OriginUpperLeft |
| OpName %3 "a_func" |
| OpName %5 "__frexp_result_vec2_f16" |
| OpMemberName %5 0 "fract" |
| OpMemberName %5 1 "exp" |
| OpMemberDecorate %5 0 Offset 0 |
| OpMemberDecorate %5 1 Offset 8 |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %7 = OpTypeFloat 16 |
| %6 = OpTypeVector %7 2 |
| %9 = OpTypeInt 32 1 |
| %8 = OpTypeVector %9 2 |
| %5 = OpTypeStruct %6 %8 |
| %10 = OpConstant %7 0x1p-1 |
| %11 = OpConstantComposite %6 %10 %10 |
| %12 = OpConstant %9 1 |
| %13 = OpConstant %9 2 |
| %14 = OpConstantComposite %8 %12 %13 |
| %15 = OpConstantComposite %5 %11 %14 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_QuantizeToF16_Scalar) { |
| GlobalVar("v", Expr(2_f), builtin::AddressSpace::kPrivate); |
| |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", Call("quantizeToF16", "v"))), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = SanitizeAndBuild(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %7 "a_func" |
| OpExecutionMode %7 OriginUpperLeft |
| OpName %3 "v" |
| OpName %7 "a_func" |
| %1 = OpTypeFloat 32 |
| %2 = OpConstant %1 2 |
| %4 = OpTypePointer Private %1 |
| %3 = OpVariable %4 Private %2 |
| %6 = OpTypeVoid |
| %5 = OpTypeFunction %6 |
| %7 = OpFunction %6 None %5 |
| %8 = OpLabel |
| %10 = OpLoad %1 %3 |
| %9 = OpQuantizeToF16 %1 %10 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| TEST_F(BuiltinBuilderTest, Call_QuantizeToF16_Vector) { |
| GlobalVar("v", Call<vec3<f32>>(2_f), builtin::AddressSpace::kPrivate); |
| |
| Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", Call("quantizeToF16", "v"))), |
| }, |
| utils::Vector{ |
| Stage(ast::PipelineStage::kFragment), |
| }); |
| |
| spirv::Builder& b = SanitizeAndBuild(); |
| |
| ASSERT_TRUE(b.Build()) << b.Diagnostics(); |
| auto got = DumpBuilder(b); |
| auto* expect = R"(OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %24 "a_func" |
| OpExecutionMode %24 OriginUpperLeft |
| OpName %5 "v" |
| OpName %8 "tint_quantizeToF16" |
| OpName %9 "v" |
| OpName %24 "a_func" |
| %2 = OpTypeFloat 32 |
| %1 = OpTypeVector %2 3 |
| %3 = OpConstant %2 2 |
| %4 = OpConstantComposite %1 %3 %3 %3 |
| %6 = OpTypePointer Private %1 |
| %5 = OpVariable %6 Private %4 |
| %7 = OpTypeFunction %1 %1 |
| %12 = OpTypeInt 32 0 |
| %13 = OpConstantNull %12 |
| %16 = OpConstant %12 1 |
| %19 = OpConstant %12 2 |
| %23 = OpTypeVoid |
| %22 = OpTypeFunction %23 |
| %8 = OpFunction %1 None %7 |
| %9 = OpFunctionParameter %1 |
| %10 = OpLabel |
| %14 = OpCompositeExtract %2 %9 0 |
| %11 = OpQuantizeToF16 %2 %14 |
| %17 = OpCompositeExtract %2 %9 1 |
| %15 = OpQuantizeToF16 %2 %17 |
| %20 = OpCompositeExtract %2 %9 2 |
| %18 = OpQuantizeToF16 %2 %20 |
| %21 = OpCompositeConstruct %1 %11 %15 %18 |
| OpReturnValue %21 |
| OpFunctionEnd |
| %24 = OpFunction %23 None %22 |
| %25 = OpLabel |
| %27 = OpLoad %1 %5 |
| %26 = OpFunctionCall %1 %8 %27 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(expect, got); |
| |
| Validate(b); |
| } |
| |
| } // namespace float_builtin_tests |
| |
| // Tests for Numeric builtins with all integer parameter |
| namespace integer_builtin_tests { |
| |
| using BuiltinIntTest = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(BuiltinIntTest, Call_SInt_Scalar) { |
| auto param = GetParam(); |
| auto* var = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call(param.name, "v"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%3 = OpTypeInt 32 1 |
| %2 = OpTypePointer Private %3 |
| %4 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %4 |
| %6 = OpTypeVoid |
| %5 = OpTypeFunction %6 |
| )"); |
| |
| auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1 |
| %9 = ${op} %3 %10 |
| OpReturn |
| )", |
| "${op}", param.op); |
| EXPECT_EQ(DumpInstructions(b.Module().Functions()[0].instructions()), expected); |
| } |
| |
| TEST_P(BuiltinIntTest, Call_SInt_Vector) { |
| auto param = GetParam(); |
| auto* var = GlobalVar("v", ty.vec3<i32>(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call(param.name, "v"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%4 = OpTypeInt 32 1 |
| %3 = OpTypeVector %4 3 |
| %2 = OpTypePointer Private %3 |
| %5 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %5 |
| %7 = OpTypeVoid |
| %6 = OpTypeFunction %7 |
| )"); |
| |
| auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 |
| %10 = ${op} %3 %11 |
| OpReturn |
| )", |
| "${op}", param.op); |
| EXPECT_EQ(DumpInstructions(b.Module().Functions()[0].instructions()), expected); |
| } |
| |
| TEST_P(BuiltinIntTest, Call_UInt_Scalar) { |
| auto param = GetParam(); |
| auto* var = GlobalVar("v", ty.u32(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call(param.name, "v"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%3 = OpTypeInt 32 0 |
| %2 = OpTypePointer Private %3 |
| %4 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %4 |
| %6 = OpTypeVoid |
| %5 = OpTypeFunction %6 |
| )"); |
| |
| auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1 |
| %9 = ${op} %3 %10 |
| OpReturn |
| )", |
| "${op}", param.op); |
| EXPECT_EQ(DumpInstructions(b.Module().Functions()[0].instructions()), expected); |
| } |
| |
| TEST_P(BuiltinIntTest, Call_UInt_Vector) { |
| auto param = GetParam(); |
| auto* var = GlobalVar("v", ty.vec3<u32>(), builtin::AddressSpace::kPrivate); |
| auto* expr = Call(param.name, "v"); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics(); |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| EXPECT_EQ(DumpInstructions(b.Module().Types()), R"(%4 = OpTypeInt 32 0 |
| %3 = OpTypeVector %4 3 |
| %2 = OpTypePointer Private %3 |
| %5 = OpConstantNull %3 |
| %1 = OpVariable %2 Private %5 |
| %7 = OpTypeVoid |
| %6 = OpTypeFunction %7 |
| )"); |
| |
| auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 |
| %10 = ${op} %3 %11 |
| OpReturn |
| )", |
| "${op}", param.op); |
| EXPECT_EQ(DumpInstructions(b.Module().Functions()[0].instructions()), expected); |
| } |
| INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest, |
| BuiltinIntTest, |
| testing::Values(BuiltinData{"countOneBits", "OpBitCount"}, |
| BuiltinData{"reverseBits", "OpBitReverse"})); |
| |
| using Builtin_Builder_SingleParam_Sint_Test = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(Builtin_Builder_SingleParam_Sint_Test, Call_Scalar) { |
| auto param = GetParam(); |
| auto* scalar = Var("scalar", Expr(1_i)); |
| auto* expr = Call(param.name, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeInt 32 1 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_SingleParam_Sint_Test, Call_Vector) { |
| auto param = GetParam(); |
| auto* vec = Var("vec", Call<vec2<i32>>(1_i, 1_i)); |
| auto* expr = Call(param.name, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeInt 32 1 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest, |
| Builtin_Builder_SingleParam_Sint_Test, |
| testing::Values(BuiltinData{"abs", "SAbs"})); |
| |
| // Calling abs() on an unsigned integer scalar / vector is a no-op. |
| using Builtin_Builder_Abs_Uint_Test = BuiltinBuilderTest; |
| TEST_F(Builtin_Builder_Abs_Uint_Test, Call_Scalar) { |
| auto* scalar = Var("scalar", Expr(1_u)); |
| auto* expr = Call("abs", scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeInt 32 0 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %11 = OpLoad %5 %7 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_F(Builtin_Builder_Abs_Uint_Test, Call_Vector) { |
| auto* scalar = Var("scalar", Call<vec2<u32>>(1_u, 1_u)); |
| auto* expr = Call("abs", scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(OpName %3 "a_func" |
| OpName %9 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeInt 32 0 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %13 = OpLoad %5 %9 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| using Builtin_Builder_DualParam_SInt_Test = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(Builtin_Builder_DualParam_SInt_Test, Call_Scalar) { |
| auto param = GetParam(); |
| auto* scalar = Var("scalar", Expr(1_i)); |
| auto* expr = Call(param.name, scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = OpTypeInt 32 1 |
| %6 = OpConstant %5 1 |
| %8 = OpTypePointer Function %5 |
| %9 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %7 = OpVariable %8 Function %9 |
| OpStore %7 %6 |
| %12 = OpLoad %5 %7 |
| %13 = OpLoad %5 %7 |
| %10 = OpExtInst %5 %11 )" + |
| param.op + |
| R"( %12 %13 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| |
| TEST_P(Builtin_Builder_DualParam_SInt_Test, Call_Vector) { |
| auto param = GetParam(); |
| auto* vec = Var("vec", Call<vec2<i32>>(1_i, 1_i)); |
| auto* expr = Call(param.name, vec, vec); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(vec), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%13 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %9 "vec" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %6 = OpTypeInt 32 1 |
| %5 = OpTypeVector %6 2 |
| %7 = OpConstant %6 1 |
| %8 = OpConstantComposite %5 %7 %7 |
| %10 = OpTypePointer Function %5 |
| %11 = OpConstantNull %5 |
| %3 = OpFunction %2 None %1 |
| %4 = OpLabel |
| %9 = OpVariable %10 Function %11 |
| OpStore %9 %8 |
| %14 = OpLoad %5 %9 |
| %15 = OpLoad %5 %9 |
| %12 = OpExtInst %5 %13 )" + |
| param.op + |
| R"( %14 %15 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| EXPECT_EQ(got, expect); |
| } |
| INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest, |
| Builtin_Builder_DualParam_SInt_Test, |
| testing::Values(BuiltinData{"max", "SMax"}, BuiltinData{"min", "SMin"})); |
| |
| using Builtin_Builder_DualParam_UInt_Test = BuiltinBuilderTestWithParam<BuiltinData>; |
| TEST_P(Builtin_Builder_DualParam_UInt_Test, Call_Scalar) { |
| auto param = GetParam(); |
| auto* scalar = Var("scalar", Expr(1_u)); |
| auto* expr = Call(param.name, scalar, scalar); |
| auto* func = Func("a_func", utils::Empty, ty.void_(), |
| utils::Vector{ |
| Decl(scalar), |
| Decl(Let("l", expr)), |
| }); |
| |
| spirv::Builder& b = Build(); |
| |
| ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics(); |
| |
| auto got = DumpBuilder(b); |
| auto expect = R"(%11 = OpExtInstImport "GLSL.std.450" |
| OpName %3 "a_func" |
| OpName %7 "scalar" |
| %2 = OpTypeVoid |
| %1 = OpTypeFunction %2 |
| %5 = |