blob: b0c7a8d03fdf637a05af52624a97036c2a2ac42f [file] [log] [blame]
// 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/lang/core/type/depth_texture.h"
#include "src/tint/lang/core/type/texture_dimension.h"
#include "src/tint/lang/spirv/writer/ast_printer/helper_test.h"
#include "src/tint/lang/spirv/writer/common/spv_dump_test.h"
#include "src/tint/lang/wgsl/ast/call_statement.h"
#include "src/tint/lang/wgsl/ast/stage_attribute.h"
#include "src/tint/utils/text/string.h"
namespace tint::spirv::writer {
namespace {
using namespace tint::core::fluent_types; // NOLINT
using namespace tint::core::number_suffixes; // NOLINT
using BuiltinSpirvASTPrinterTest = TestHelper;
template <typename T>
using BuiltinSpirvASTPrinterTestWithParam = 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(BuiltinSpirvASTPrinterTest, Call_TextureSampleCompare_Twice) {
auto s = ty.sampler(core::type::SamplerKind::kComparisonSampler);
auto t = ty.depth_texture(core::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", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr1)),
},
tint::Empty);
Func("f2", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr2)),
},
tint::Empty);
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(BuiltinSpirvASTPrinterTest, Call_GLSLMethod_WithLoad_f32) {
auto* var = GlobalVar("ident", ty.f32(), core::AddressSpace::kPrivate);
auto* expr = Call("round", "ident");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_GLSLMethod_WithLoad_f16) {
Enable(wgsl::Extension::kF16);
auto* var = GlobalVar("ident", ty.f16(), core::AddressSpace::kPrivate);
auto* expr = Call("round", "ident");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.Diagnostics();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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 = BuiltinSpirvASTPrinterTestWithParam<BuiltinData>;
TEST_P(BuiltinBoolTest, Call_Bool_Scalar) {
auto param = GetParam();
auto* var = GlobalVar("v", ty.bool_(), core::AddressSpace::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
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>(), core::AddressSpace::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
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 = tint::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(BuiltinSpirvASTPrinterTest,
BuiltinBoolTest,
testing::Values(BuiltinData{"any", "OpAny"}, BuiltinData{"all", "OpAll"}));
TEST_F(BuiltinSpirvASTPrinterTest, Call_Select) {
auto* v3 = GlobalVar("v3", ty.vec3<f32>(), core::AddressSpace::kPrivate);
auto* bool_v3 = GlobalVar("bool_v3", ty.vec3<bool>(), core::AddressSpace::kPrivate);
auto* expr = Call("select", "v3", "v3", "bool_v3");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
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(BuiltinSpirvASTPrinterTest, Call_ArrayLength) {
auto* s = Structure("my_struct", Vector{
Member("a", ty.array<f32>()),
});
GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(1_a),
Group(2_a));
auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
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(BuiltinSpirvASTPrinterTest, Call_ArrayLength_OtherMembersInStruct) {
auto* s = Structure("my_struct", Vector{
Member("z", ty.f32()),
Member(4, "a", ty.array<f32>()),
});
GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::Access::kRead, Binding(1_a),
Group(2_a));
auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
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(BuiltinSpirvASTPrinterTest, Call_ArrayLength_ViaLets) {
auto* s = Structure("my_struct", Vector{
Member("a", ty.array<f32>()),
});
GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::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", tint::Empty, ty.void_(),
Vector{
Decl(p),
Decl(p2),
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
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(BuiltinSpirvASTPrinterTest, 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", Vector{
Member("a", ty.array<f32>()),
});
GlobalVar("b", ty.Of(s), core::AddressSpace::kStorage, core::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", tint::Empty, ty.void_(),
Vector{
Decl(p),
Decl(p2),
Decl(p3),
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
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 = BuiltinSpirvASTPrinterTestWithParam<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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(wgsl::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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(wgsl::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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest,
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(BuiltinSpirvASTPrinterTest, Call_Length_Scalar_f32) {
auto* scalar = Var("a", Expr(1_f));
auto* expr = Call("length", scalar);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Length_Scalar_f16) {
Enable(wgsl::Extension::kF16);
auto* scalar = Var("a", Expr(1_h));
auto* expr = Call("length", scalar);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, 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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Length_Vector_f16) {
Enable(wgsl::Extension::kF16);
auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h));
auto* expr = Call("length", vec);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Normalize_f32) {
auto* vec = Var("a", Call<vec2<f32>>(1_f, 1_f));
auto* expr = Call("normalize", vec);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Normalize_f16) {
Enable(wgsl::Extension::kF16);
auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h));
auto* expr = Call("normalize", vec);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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 = BuiltinSpirvASTPrinterTestWithParam<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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(wgsl::Extension::kF16);
auto param = GetParam();
auto* scalar = Var("scalar", Expr(1_h));
auto* expr = Call(param.name, scalar, scalar);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(wgsl::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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest,
Builtin_Builder_DualParam_Float_Test,
testing::Values(BuiltinData{"atan2", "Atan2"},
BuiltinData{"max", "NMax"},
BuiltinData{"min", "NMin"},
BuiltinData{"pow", "Pow"},
BuiltinData{"step", "Step"}));
TEST_F(BuiltinSpirvASTPrinterTest, 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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Reflect_Vector_f16) {
Enable(wgsl::Extension::kF16);
auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h));
auto* expr = Call("reflect", vec, vec);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Distance_Scalar_f32) {
auto* scalar = Var("scalar", Expr(1_f));
auto* expr = Call("distance", scalar, scalar);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Distance_Scalar_f16) {
Enable(wgsl::Extension::kF16);
auto* scalar = Var("scalar", Expr(1_h));
auto* expr = Call("distance", scalar, scalar);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, 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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Distance_Vector_f16) {
Enable(wgsl::Extension::kF16);
auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h));
auto* expr = Call("distance", vec, vec);
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, 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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_Cross_f16) {
Enable(wgsl::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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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 = BuiltinSpirvASTPrinterTestWithParam<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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(wgsl::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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(wgsl::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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest,
Builtin_Builder_ThreeParam_Float_Test,
testing::Values(BuiltinData{"clamp", "NClamp"},
BuiltinData{"fma", "Fma"},
BuiltinData{"mix", "FMix"},
BuiltinData{"smoothstep", "SmoothStep"}));
TEST_F(BuiltinSpirvASTPrinterTest, 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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_FaceForward_Vector_f16) {
Enable(wgsl::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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Runtime_Call_Modf_f32) {
auto* vec = Var("vec", Call<vec2<f32>>(1_f, 2_f));
auto* expr = Call("modf", vec);
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Runtime_Call_Modf_f16) {
Enable(wgsl::Extension::kF16);
auto* vec = Var("vec", Call<vec2<f16>>(1_h, 2_h));
auto* expr = Call("modf", vec);
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Const_Call_Modf_f32) {
auto* expr = Call("modf", Call<vec2<f32>>(1_f, 2_f));
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Const_Call_Modf_f16) {
Enable(wgsl::Extension::kF16);
auto* expr = Call("modf", Call<vec2<f16>>(1_h, 2_h));
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Runtime_Call_Frexp_f32) {
auto* vec = Var("vec", Call<vec2<f32>>(1_f, 2_f));
auto* expr = Call("frexp", vec);
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Runtime_Call_Frexp_f16) {
Enable(wgsl::Extension::kF16);
auto* vec = Var("vec", Call<vec2<f16>>(1_h, 2_h));
auto* expr = Call("frexp", vec);
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Const_Call_Frexp_f32) {
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", Call("frexp", Call<vec2<f32>>(1_f, 2_f)))),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Const_Call_Frexp_f16) {
Enable(wgsl::Extension::kF16);
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", Call("frexp", Call<vec2<f16>>(1_h, 2_h)))),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_QuantizeToF16_Scalar) {
GlobalVar("v", Expr(2_f), core::AddressSpace::kPrivate);
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", Call("quantizeToF16", "v"))),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest, Call_QuantizeToF16_Vector) {
GlobalVar("v", Call<vec3<f32>>(2_f), core::AddressSpace::kPrivate);
Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", Call("quantizeToF16", "v"))),
},
Vector{
Stage(ast::PipelineStage::kFragment),
});
Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build()) << b.Diagnostics();
auto got = DumpModule(b.Module());
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 = BuiltinSpirvASTPrinterTestWithParam<BuiltinData>;
TEST_P(BuiltinIntTest, Call_SInt_Scalar) {
auto param = GetParam();
auto* var = GlobalVar("v", ty.i32(), core::AddressSpace::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
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 = tint::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>(), core::AddressSpace::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
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 = tint::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(), core::AddressSpace::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
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 = tint::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>(), core::AddressSpace::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", tint::Empty, ty.void_(),
Vector{
Decl(Let("l", expr)),
});
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 = tint::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(BuiltinSpirvASTPrinterTest,
BuiltinIntTest,
testing::Values(BuiltinData{"countOneBits", "OpBitCount"},
BuiltinData{"reverseBits", "OpBitReverse"}));
using Builtin_Builder_SingleParam_Sint_Test = BuiltinSpirvASTPrinterTestWithParam<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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest,
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 = BuiltinSpirvASTPrinterTest;
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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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 = BuiltinSpirvASTPrinterTestWithParam<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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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", tint::Empty, ty.void_(),
Vector{
Decl(vec),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
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(BuiltinSpirvASTPrinterTest,
Builtin_Builder_DualParam_SInt_Test,
testing::Values(BuiltinData{"max", "SMax"}, BuiltinData{"min", "SMin"}));
using Builtin_Builder_DualParam_UInt_Test = BuiltinSpirvASTPrinterTestWithParam<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", tint::Empty, ty.void_(),
Vector{
Decl(scalar),
Decl(Let("l", expr)),
});
Builder& b = Build();
ASSERT_TRUE(b.GenerateFunction(func)) << b.Diagnostics();
auto got = DumpModule(b.Module());
auto expect = R"(%11 = OpExtInstImport "GLSL.std.450"
OpName %3 "a_func"
OpName %7 "scalar"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%5 = OpTypeInt 32 0
%6 = OpConstant %5 1
%<