blob: 3d64e8c23d707bf9a7ffc3029c8fde7b53687829 [file]
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/spirv/reader/helper_test.h"
namespace tint::spirv::reader {
namespace {
std::string Preamble(const std::string& names = "") {
return R"(
OpCapability Shader
OpCapability Float16
%glsl = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %100 "main"
OpExecutionMode %100 LocalSize 1 1 1
)" + names +
R"(
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%uint = OpTypeInt 32 0
%int = OpTypeInt 32 1
%float = OpTypeFloat 32
%half = OpTypeFloat 16
%uint_10 = OpConstant %uint 10
%uint_15 = OpConstant %uint 15
%uint_20 = OpConstant %uint 20
%int_30 = OpConstant %int 30
%int_35 = OpConstant %int 35
%int_40 = OpConstant %int 40
%float_50 = OpConstant %float 50
%float_60 = OpConstant %float 60
%float_70 = OpConstant %float 70
%half_50 = OpConstant %half 50
%half_60 = OpConstant %half 60
%half_70 = OpConstant %half 70
%v2uint = OpTypeVector %uint 2
%v2int = OpTypeVector %int 2
%v2float = OpTypeVector %float 2
%v3float = OpTypeVector %float 3
%v4float = OpTypeVector %float 4
%v2half = OpTypeVector %half 2
%v3half = OpTypeVector %half 3
%v4half = OpTypeVector %half 4
%mat2v2float = OpTypeMatrix %v2float 2
%mat3v3float = OpTypeMatrix %v3float 3
%mat4v4float = OpTypeMatrix %v4float 4
%mat2v2half = OpTypeMatrix %v2half 2
%mat3v3half = OpTypeMatrix %v3half 3
%mat4v4half = OpTypeMatrix %v4half 4
%modf_result_type = OpTypeStruct %float %float
%modf_v2_result_type = OpTypeStruct %v2float %v2float
%ptr_function_modf_result_type = OpTypePointer Function %modf_result_type
%ptr_function_modf_v2_result_type = OpTypePointer Function %modf_v2_result_type
%frexp_result_type_unsigned = OpTypeStruct %float %uint
%frexp_result_type_signed = OpTypeStruct %float %int
%frexp_v2_result_type_unsigned = OpTypeStruct %v2float %v2uint
%frexp_v2_result_type_signed = OpTypeStruct %v2float %v2int
%ptr_function_frexp_result_type_unsigned = OpTypePointer Function %frexp_result_type_unsigned
%ptr_function_frexp_result_type_signed = OpTypePointer Function %frexp_result_type_signed
%ptr_function_frexp_v2_result_type_unsigned = OpTypePointer Function %frexp_v2_result_type_unsigned
%ptr_function_frexp_v2_result_type_signed = OpTypePointer Function %frexp_v2_result_type_signed
%v2uint_10_20 = OpConstantComposite %v2uint %uint_10 %uint_20
%v2uint_20_10 = OpConstantComposite %v2uint %uint_20 %uint_10
%v2uint_15_15 = OpConstantComposite %v2uint %uint_15 %uint_15
%v2int_30_40 = OpConstantComposite %v2int %int_30 %int_40
%v2int_40_30 = OpConstantComposite %v2int %int_40 %int_30
%v2int_35_35 = OpConstantComposite %v2int %int_35 %int_35
%v2float_50_60 = OpConstantComposite %v2float %float_50 %float_60
%v2float_60_50 = OpConstantComposite %v2float %float_60 %float_50
%v2float_70_70 = OpConstantComposite %v2float %float_70 %float_70
%v2half_50_60 = OpConstantComposite %v2half %half_50 %half_60
%v3float_50_60_70 = OpConstantComposite %v3float %float_50 %float_60 %float_70
%v3float_60_70_50 = OpConstantComposite %v3float %float_60 %float_70 %float_50
%v3half_50_60_70 = OpConstantComposite %v3half %half_50 %half_60 %half_70
%v4float_50_50_50_50 = OpConstantComposite %v4float %float_50 %float_50 %float_50 %float_50
%v4half_50_50_50_50 = OpConstantComposite %v4half %half_50 %half_50 %half_50 %half_50
%mat2v2float_50_60 = OpConstantComposite %mat2v2float %v2float_50_60 %v2float_50_60
%mat3v3float_50_60_70 = OpConstantComposite %mat3v3float %v3float_50_60_70 %v3float_50_60_70 %v3float_50_60_70
%mat4v4float_50_50_50_50 = OpConstantComposite %mat4v4float %v4float_50_50_50_50 %v4float_50_50_50_50 %v4float_50_50_50_50 %v4float_50_50_50_50
%mat2v2half_50_60 = OpConstantComposite %mat2v2half %v2half_50_60 %v2half_50_60
%mat3v3half_50_60_70 = OpConstantComposite %mat3v3half %v3half_50_60_70 %v3half_50_60_70 %v3half_50_60_70
%mat4v4half_50_50_50_50 = OpConstantComposite %mat4v4half %v4half_50_50_50_50 %v4half_50_50_50_50 %v4half_50_50_50_50 %v4half_50_50_50_50
%fn_float_float = OpTypeFunction %float %float
%fn_float_v2float = OpTypeFunction %float %v2float
%fn_float_v3float = OpTypeFunction %float %v3float
%fn_float_v4float = OpTypeFunction %float %v4float
%fn_v2float_v2float = OpTypeFunction %v2float %v2float
%fn_v3float_v3float = OpTypeFunction %v3float %v3float
%fn_v4float_v4float = OpTypeFunction %v4float %v4float
%fn_int_int = OpTypeFunction %int %int
%fn_v2int_v2int = OpTypeFunction %v2int %v2int
%fn_uint_uint = OpTypeFunction %uint %uint
%fn_v2uint_v2uint = OpTypeFunction %v2uint %v2uint
%fn_float_float_float = OpTypeFunction %float %float %float
%fn_float_v2float_v2float = OpTypeFunction %float %v2float %v2float
%fn_v2float_v2float_v2float = OpTypeFunction %v2float %v2float %v2float
%fn_v3float_v3float_v3float = OpTypeFunction %v3float %v3float %v3float
%fn_float_float_int = OpTypeFunction %float %float %int
%fn_v2float_v2float_v2int = OpTypeFunction %v2float %v2float %v2int
%fn_float_float_float_float = OpTypeFunction %float %float %float %float
%fn_v2float_v2float_v2float_v2float = OpTypeFunction %v2float %v2float %v2float %v2float
%fn_uint_v2float = OpTypeFunction %uint %v2float
%fn_uint_v4float = OpTypeFunction %uint %v4float
%fn_v2float_uint = OpTypeFunction %v2float %uint
%fn_v4float_uint = OpTypeFunction %v4float %uint
%fn_float_mat2v2float = OpTypeFunction %float %mat2v2float
%fn_float_mat3v3float = OpTypeFunction %float %mat3v3float
%fn_float_mat4v4float = OpTypeFunction %float %mat4v4float
%fn_half_mat2v2half = OpTypeFunction %half %mat2v2half
%fn_half_mat3v3half = OpTypeFunction %half %mat3v3half
%fn_half_mat4v4half = OpTypeFunction %half %mat4v4half
%fn_modf_float = OpTypeFunction %modf_result_type %float
%fn_modf_v2float = OpTypeFunction %modf_v2_result_type %v2float
%fn_frexp_u_float = OpTypeFunction %frexp_result_type_unsigned %float
%fn_frexp_s_float = OpTypeFunction %frexp_result_type_signed %float
%fn_frexp_u_v2float = OpTypeFunction %frexp_v2_result_type_unsigned %v2float
%fn_frexp_s_v2float = OpTypeFunction %frexp_v2_result_type_signed %v2float
%fn_void_float = OpTypeFunction %void %float
%fn_void_v2float = OpTypeFunction %void %v2float
%fn_void_rectify = OpTypeFunction %void %int %v2int %uint %v2uint
)";
}
struct GlslStd450Case {
std::string opcode;
std::string wgsl_func;
};
inline std::ostream& operator<<(std::ostream& out, GlslStd450Case c) {
out << "GlslStd450Case(" << c.opcode << " " << c.wgsl_func << ")";
return out;
}
// Nomenclature:
// Float = scalar float
// Floating = scalar float or vector-of-float
// Float3 = 3-element vector of float
// Int = scalar signed int
// Inting = scalar int or vector-of-int
// Uint = scalar unsigned int
// Uinting = scalar unsigned or vector-of-unsigned
using SpirvReaderTest_GlslStd450_Float_Floating = SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Float_FloatingFloating = SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Floating_Floating = SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Floating_FloatingFloating =
SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Floating_FloatingFloatingFloating =
SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Floating_FloatingInting = SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Float3_Float3Float3 = SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Inting_Inting = SpirvReaderTestWithParam<GlslStd450Case>;
using SpirvReaderTest_GlslStd450_Uinting_Uinting = SpirvReaderTestWithParam<GlslStd450Case>;
TEST_P(SpirvReaderTest_GlslStd450_Float_Floating, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %float None %fn_float_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:f32):f32 {
$B1: {
%3:f32 = )" + GetParam().wgsl_func +
R"( %x
ret %3
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Float_Floating, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %float None %fn_float_v2float
%x = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %v2float_50_60
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<f32>):f32 {
$B1: {
%3:f32 = )" + GetParam().wgsl_func +
R"( %x
ret %3
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Float_FloatingFloating, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
)") + R"(
%foo = OpFunction %float None %fn_float_float_float
%x = OpFunctionParameter %float
%y = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x %y
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50 %float_60
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:f32, %y:f32):f32 {
$B1: {
%4:f32 = )" + GetParam().wgsl_func +
R"( %x, %y
ret %4
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Float_FloatingFloating, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
)") + R"(
%foo = OpFunction %float None %fn_float_v2float_v2float
%x = OpFunctionParameter %v2float
%y = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x %y
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %v2float_50_60 %v2float_60_50
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<f32>, %y:vec2<f32>):f32 {
$B1: {
%4:f32 = )" + GetParam().wgsl_func +
R"( %x, %y
ret %4
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_Floating, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %float None %fn_float_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:f32):f32 {
$B1: {
%3:f32 = )" + GetParam().wgsl_func +
R"( %x
ret %3
}
})");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_Floating, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %v2float None %fn_v2float_v2float
%x = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %v2float %glsl )" +
GetParam().opcode + R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2float %foo %v2float_50_60
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<f32>):vec2<f32> {
$B1: {
%3:vec2<f32> = )" +
GetParam().wgsl_func +
R"( %x
ret %3
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_FloatingFloating, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
)") + R"(
%foo = OpFunction %float None %fn_float_float_float
%x = OpFunctionParameter %float
%y = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x %y
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50 %float_60
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:f32, %y:f32):f32 {
$B1: {
%4:f32 = )" + GetParam().wgsl_func +
R"( %x, %y
ret %4
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_FloatingFloating, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
)") + R"(
%foo = OpFunction %v2float None %fn_v2float_v2float_v2float
%x = OpFunctionParameter %v2float
%y = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %v2float %glsl )" +
GetParam().opcode + R"( %x %y
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2float %foo %v2float_50_60 %v2float_60_50
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<f32>, %y:vec2<f32>):vec2<f32> {
$B1: {
%4:vec2<f32> = )" +
GetParam().wgsl_func +
R"( %x, %y
ret %4
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_FloatingFloatingFloating, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
OpName %z "z"
)") + R"(
%foo = OpFunction %float None %fn_float_float_float_float
%x = OpFunctionParameter %float
%y = OpFunctionParameter %float
%z = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x %y %z
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50 %float_60 %float_70
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:f32, %y:f32, %z:f32):f32 {
$B1: {
%5:f32 = )" + GetParam().wgsl_func +
R"( %x, %y, %z
ret %5
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_FloatingFloatingFloating, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
OpName %z "z"
)") + R"(
%foo = OpFunction %v2float None %fn_v2float_v2float_v2float_v2float
%x = OpFunctionParameter %v2float
%y = OpFunctionParameter %v2float
%z = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %v2float %glsl )" +
GetParam().opcode +
R"( %x %y %z
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2float %foo %v2float_50_60 %v2float_60_50 %v2float_70_70
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<f32>, %y:vec2<f32>, %z:vec2<f32>):vec2<f32> {
$B1: {
%5:vec2<f32> = )" +
GetParam().wgsl_func +
R"( %x, %y, %z
ret %5
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_FloatingInting, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
)") + R"(
%foo = OpFunction %float None %fn_float_float_int
%x = OpFunctionParameter %float
%y = OpFunctionParameter %int
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl )" +
GetParam().opcode + R"( %x %y
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50 %int_30
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:f32, %y:i32):f32 {
$B1: {
%4:f32 = )" + GetParam().wgsl_func +
R"( %x, %y
ret %4
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Floating_FloatingInting, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
)") + R"(
%foo = OpFunction %v2float None %fn_v2float_v2float_v2int
%x = OpFunctionParameter %v2float
%y = OpFunctionParameter %v2int
%foo_entry = OpLabel
%1 = OpExtInst %v2float %glsl )" +
GetParam().opcode +
R"( %x %y
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2float %foo %v2float_50_60 %v2int_30_40
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<f32>, %y:vec2<i32>):vec2<f32> {
$B1: {
%4:vec2<f32> = )" +
GetParam().wgsl_func +
R"( %x, %y
ret %4
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Float3_Float3Float3, SpirvParser) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
OpName %y "y"
)") + R"(
%foo = OpFunction %v3float None %fn_v3float_v3float_v3float
%x = OpFunctionParameter %v3float
%y = OpFunctionParameter %v3float
%foo_entry = OpLabel
%1 = OpExtInst %v3float %glsl )" +
GetParam().opcode +
R"( %x %y
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v3float %foo %v3float_50_60_70 %v3float_60_70_50
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec3<f32>, %y:vec3<f32>):vec3<f32> {
$B1: {
%4:vec3<f32> = )" +
GetParam().wgsl_func +
R"( %x, %y
ret %4
}
}
)");
}
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Float_Floating,
::testing::Values(GlslStd450Case{"Length", "length"}));
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Float_FloatingFloating,
::testing::Values(GlslStd450Case{"Distance", "distance"}));
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Floating_Floating,
::testing::ValuesIn(std::vector<GlslStd450Case>{
{"Acos", "acos"}, //
{"Acosh", "acosh"}, //
{"Asin", "asin"}, //
{"Asinh", "asinh"}, //
{"Atan", "atan"}, //
{"Atanh", "atanh"}, //
{"Ceil", "ceil"}, //
{"Cos", "cos"}, //
{"Cosh", "cosh"}, //
{"Degrees", "degrees"}, //
{"Exp", "exp"}, //
{"Exp2", "exp2"}, //
{"FAbs", "abs"}, //
{"FSign", "sign"}, //
{"Floor", "floor"}, //
{"Fract", "fract"}, //
{"InverseSqrt", "inverseSqrt"}, //
{"Log", "log"}, //
{"Log2", "log2"}, //
{"Radians", "radians"}, //
{"Round", "round"}, //
{"RoundEven", "round"}, //
{"Sin", "sin"}, //
{"Sinh", "sinh"}, //
{"Sqrt", "sqrt"}, //
{"Tan", "tan"}, //
{"Tanh", "tanh"}, //
{"Trunc", "trunc"}, //
}));
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Floating_FloatingFloating,
::testing::ValuesIn(std::vector<GlslStd450Case>{
{"Atan2", "atan2"},
{"NMax", "max"},
{"NMin", "min"},
{"FMax", "max"}, // WGSL max promises more for NaN
{"FMin", "min"}, // WGSL min promises more for NaN
{"Pow", "pow"},
{"Step", "step"},
}));
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Floating_FloatingInting,
::testing::Values(GlslStd450Case{"Ldexp", "ldexp"}));
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Float3_Float3Float3,
::testing::Values(GlslStd450Case{"Cross", "cross"}));
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Floating_FloatingFloatingFloating,
::testing::ValuesIn(std::vector<GlslStd450Case>{
{"NClamp", "clamp"},
{"FClamp", "clamp"}, // WGSL FClamp promises more for NaN
{"Fma", "fma"},
{"FMix", "mix"},
{"SmoothStep", "smoothstep"}}));
TEST_P(SpirvReaderTest_GlslStd450_Inting_Inting, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %int None %fn_int_int
%x = OpFunctionParameter %int
%foo_entry = OpLabel
%1 = OpExtInst %int %glsl )" +
GetParam().opcode +
R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %int %foo %int_30
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:i32):i32 {
$B1: {
%3:i32 = )" + GetParam().wgsl_func +
R"( %x
ret %3
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Inting_Inting, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %v2int None %fn_v2int_v2int
%x = OpFunctionParameter %v2int
%foo_entry = OpLabel
%1 = OpExtInst %v2int %glsl )" +
GetParam().opcode +
R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2int %foo %v2int_30_40
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<i32>):vec2<i32> {
$B1: {
%3:vec2<i32> = )" +
GetParam().wgsl_func +
R"( %x
ret %3
}
}
)");
}
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Inting_Inting,
::testing::Values(GlslStd450Case{"FindILsb", "firstTrailingBit"},
GlslStd450Case{"FindSMsb", "firstLeadingBit"}));
TEST_P(SpirvReaderTest_GlslStd450_Uinting_Uinting, Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %uint None %fn_uint_uint
%x = OpFunctionParameter %uint
%foo_entry = OpLabel
%1 = OpExtInst %uint %glsl )" +
GetParam().opcode +
R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %uint %foo %uint_10
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:u32):u32 {
$B1: {
%3:u32 = )" + GetParam().wgsl_func +
R"( %x
ret %3
}
}
)");
}
TEST_P(SpirvReaderTest_GlslStd450_Uinting_Uinting, Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %v2uint None %fn_v2uint_v2uint
%x = OpFunctionParameter %v2uint
%foo_entry = OpLabel
%1 = OpExtInst %v2uint %glsl )" +
GetParam().opcode +
R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2uint %foo %v2uint_10_20
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<u32>):vec2<u32> {
$B1: {
%3:vec2<u32> = )" +
GetParam().wgsl_func +
R"( %x
ret %3
}
}
)");
}
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_Uinting_Uinting,
::testing::Values(GlslStd450Case{"FindILsb", "firstTrailingBit"},
GlslStd450Case{"FindUMsb", "firstLeadingBit"}));
// Test Normalize. WGSL does not have a scalar form of the normalize builtin.
// So we have to test it separately, as it does not fit the patterns tested
// above.
TEST_F(SpirvReaderTest, Normalize_Scalar) {
// Scalar normalize maps to sign.
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %float None %fn_float_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %float %glsl Normalize %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:f32):f32 {
$B1: {
%3:f32 = sign %x
ret %3
}
}
)");
}
TEST_F(SpirvReaderTest, Normalize_Vector2) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %v2float None %fn_v2float_v2float
%x = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %v2float %glsl Normalize %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2float %foo %v2float_50_60
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec2<f32>):vec2<f32> {
$B1: {
%3:vec2<f32> = normalize %x
ret %3
}
}
)");
}
TEST_F(SpirvReaderTest, Normalize_Vector3) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %v3float None %fn_v3float_v3float
%x = OpFunctionParameter %v3float
%foo_entry = OpLabel
%1 = OpExtInst %v3float %glsl Normalize %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v3float %foo %v3float_50_60_70
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec3<f32>):vec3<f32> {
$B1: {
%3:vec3<f32> = normalize %x
ret %3
}
}
)");
}
TEST_F(SpirvReaderTest, Normalize_Vector4) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %v4float None %fn_v4float_v4float
%x = OpFunctionParameter %v4float
%foo_entry = OpLabel
%1 = OpExtInst %v4float %glsl Normalize %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v4float %foo %v4float_50_50_50_50
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:vec4<f32>):vec4<f32> {
$B1: {
%3:vec4<f32> = normalize %x
ret %3
}
}
)");
}
TEST_F(SpirvReaderTest, RectifyOperandsAndResult_FindUMsb) {
// Check signedness conversion of arguments and results.
// SPIR-V signed arg -> cast arg to unsigned
// signed result -> cast result to signed
// unsigned result -> keep it
//
// SPIR-V unsigned arg -> keep it
// signed result -> cast result to signed
// unsigned result -> keep it
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %a "a"
OpName %b "b"
OpName %c "c"
OpName %d "d"
)") + R"(
%foo = OpFunction %void None %fn_void_rectify
%a = OpFunctionParameter %int
%b = OpFunctionParameter %v2int
%c = OpFunctionParameter %uint
%d = OpFunctionParameter %v2uint
%foo_entry = OpLabel
; signed arg
; signed result
%1 = OpExtInst %int %glsl FindUMsb %a
%2 = OpExtInst %v2int %glsl FindUMsb %b
; signed arg
; unsigned result
%3 = OpExtInst %uint %glsl FindUMsb %a
%4 = OpExtInst %v2uint %glsl FindUMsb %b
; unsigned arg
; signed result
%5 = OpExtInst %int %glsl FindUMsb %c
%6 = OpExtInst %v2int %glsl FindUMsb %d
; unsigned arg
; unsigned result
%7 = OpExtInst %uint %glsl FindUMsb %c
%8 = OpExtInst %v2uint %glsl FindUMsb %d
OpReturn
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %void %foo %int_30 %v2int_30_40 %uint_10 %v2uint_10_20
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%a:i32, %b:vec2<i32>, %c:u32, %d:vec2<u32>):void {
$B1: {
%6:u32 = bitcast<u32> %a
%7:u32 = firstLeadingBit %6
%8:i32 = bitcast<i32> %7
%9:vec2<u32> = bitcast<vec2<u32>> %b
%10:vec2<u32> = firstLeadingBit %9
%11:vec2<i32> = bitcast<vec2<i32>> %10
%12:u32 = bitcast<u32> %a
%13:u32 = firstLeadingBit %12
%14:vec2<u32> = bitcast<vec2<u32>> %b
%15:vec2<u32> = firstLeadingBit %14
%16:u32 = firstLeadingBit %c
%17:i32 = bitcast<i32> %16
%18:vec2<u32> = firstLeadingBit %d
%19:vec2<i32> = bitcast<vec2<i32>> %18
%20:u32 = firstLeadingBit %c
%21:vec2<u32> = firstLeadingBit %d
ret
}
}
)");
}
struct DataPackingCase {
std::string opcode;
std::string wgsl_func;
uint32_t vec_size;
};
inline std::ostream& operator<<(std::ostream& out, DataPackingCase c) {
out << "DataPacking(" << c.opcode << ")";
return out;
}
using SpirvReaderTest_GlslStd450_DataPacking = SpirvReaderTestWithParam<DataPackingCase>;
TEST_P(SpirvReaderTest_GlslStd450_DataPacking, Valid) {
auto param = GetParam();
auto fn_ty = param.vec_size == 2 ? "%fn_uint_v2float" : "%fn_uint_v4float";
auto in_ty = param.vec_size == 2 ? "%v2float" : "%v4float";
auto in_val = param.vec_size == 2 ? "%v2float_50_60" : "%v4float_50_50_50_50";
auto wgsl_in_ty = "vec" + std::to_string(param.vec_size) + "<f32>";
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %uint None )" +
fn_ty + R"(
%x = OpFunctionParameter )" +
in_ty + R"(
%foo_entry = OpLabel
%1 = OpExtInst %uint %glsl )" +
param.opcode + R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %uint %foo )" +
in_val + R"(
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:)" +
wgsl_in_ty + R"():u32 {
$B1: {
%3:u32 = )" + param.wgsl_func +
R"( %x
ret %3
}
}
)");
}
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_DataPacking,
::testing::ValuesIn(std::vector<DataPackingCase>{
{"PackSnorm4x8", "pack4x8snorm", 4},
{"PackUnorm4x8", "pack4x8unorm", 4},
{"PackSnorm2x16", "pack2x16snorm", 2},
{"PackUnorm2x16", "pack2x16unorm", 2},
{"PackHalf2x16", "pack2x16float", 2}}));
using SpirvReaderTest_GlslStd450_DataUnpacking = SpirvReaderTestWithParam<DataPackingCase>;
TEST_P(SpirvReaderTest_GlslStd450_DataUnpacking, Valid) {
auto param = GetParam();
auto type = param.vec_size == 2 ? "%v2float" : "%v4float";
auto fn_ty = param.vec_size == 2 ? "%fn_v2float_uint" : "%fn_v4float_uint";
auto wgsl_type = "vec" + std::to_string(param.vec_size) + "<f32>";
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction )" +
type + R"( None )" + fn_ty + R"(
%x = OpFunctionParameter %uint
%foo_entry = OpLabel
%1 = OpExtInst )" +
type + std::string(" %glsl ") + param.opcode + R"( %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall )" +
type + R"( %foo %uint_10
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:u32):)" +
wgsl_type + R"( {
$B1: {
%3:)" + wgsl_type +
" = " + param.wgsl_func +
R"( %x
ret %3
}
}
)");
}
INSTANTIATE_TEST_SUITE_P(SpirvReader,
SpirvReaderTest_GlslStd450_DataUnpacking,
::testing::ValuesIn(std::vector<DataPackingCase>{
{"UnpackSnorm4x8", "unpack4x8snorm", 4},
{"UnpackUnorm4x8", "unpack4x8unorm", 4},
{"UnpackSnorm2x16", "unpack2x16snorm", 2},
{"UnpackUnorm2x16", "unpack2x16unorm", 2},
{"UnpackHalf2x16", "unpack2x16float", 2}}));
struct DeterminantData {
std::string in;
std::string in_type;
std::string out;
std::string ty;
std::string ty_name;
std::string fn_type;
};
[[maybe_unused]] inline std::ostream& operator<<(std::ostream& out, DeterminantData c) {
out << "Determinant(" << c.in << ")";
return out;
}
using SpirvReaderTest_GlslStd450_Determinant = SpirvReaderTestWithParam<DeterminantData>;
TEST_P(SpirvReaderTest_GlslStd450_Determinant, Test) {
auto param = GetParam();
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %)" +
param.ty_name + R"( None %)" + param.fn_type + R"(
%x = OpFunctionParameter %)" +
param.in_type + R"(
%foo_entry = OpLabel
%1 = OpExtInst %)" +
param.ty_name + R"( %glsl Determinant %x
OpReturnValue %1
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %)" +
param.ty_name + R"( %foo %)" + param.in + R"(
OpReturn
OpFunctionEnd
)",
R"(
%foo = func(%x:)" +
param.out + R"():)" + param.ty + R"( {
$B1: {
%3:)" + param.ty +
R"( = determinant %x
ret %3
}
}
)");
}
INSTANTIATE_TEST_SUITE_P(
SpirvReader,
SpirvReaderTest_GlslStd450_Determinant,
::testing::Values(DeterminantData{"mat2v2float_50_60", "mat2v2float", "mat2x2<f32>", "f32",
"float", "fn_float_mat2v2float"},
DeterminantData{"mat3v3float_50_60_70", "mat3v3float", "mat3x3<f32>", "f32",
"float", "fn_float_mat3v3float"},
DeterminantData{"mat4v4float_50_50_50_50", "mat4v4float", "mat4x4<f32>",
"f32", "float", "fn_float_mat4v4float"},
DeterminantData{"mat2v2half_50_60", "mat2v2half", "mat2x2<f16>", "f16",
"half", "fn_half_mat2v2half"},
DeterminantData{"mat3v3half_50_60_70", "mat3v3half", "mat3x3<f16>", "f16",
"half", "fn_half_mat3v3half"},
DeterminantData{"mat4v4half_50_50_50_50", "mat4v4half", "mat4x4<f16>", "f16",
"half", "fn_half_mat4v4half"}));
TEST_F(SpirvReaderTest, ModfStruct_Store) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %void None %fn_void_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpVariable %ptr_function_modf_result_type Function
%2 = OpExtInst %modf_result_type %glsl ModfStruct %x
OpStore %1 %2
OpReturn
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %void %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(4) {
tint_symbol:f32 @offset(0)
tint_symbol_1:f32 @offset(4)
}
__modf_result_f32 = struct @align(4) {
fract:f32 @offset(0)
whole:f32 @offset(4)
}
%foo = func(%x:f32):void {
$B1: {
%3:ptr<function, tint_symbol_2, read_write> = var undef
%4:__modf_result_f32 = modf %x
%5:f32 = access %4, 0u
%6:f32 = access %4, 1u
%7:tint_symbol_2 = construct %5, %6
store %3, %7
ret
}
}
)");
}
TEST_F(SpirvReaderTest, ModfStruct_Scalar) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %float None %fn_float_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %modf_result_type %glsl ModfStruct %x
%2 = OpCompositeExtract %float %1 0
OpReturnValue %2
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %float %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(4) {
tint_symbol:f32 @offset(0)
tint_symbol_1:f32 @offset(4)
}
__modf_result_f32 = struct @align(4) {
fract:f32 @offset(0)
whole:f32 @offset(4)
}
%foo = func(%x:f32):f32 {
$B1: {
%3:__modf_result_f32 = modf %x
%4:f32 = access %3, 0u
%5:f32 = access %3, 1u
%6:tint_symbol_2 = construct %4, %5
%7:f32 = access %6, 0u
ret %7
}
}
)");
}
TEST_F(SpirvReaderTest, ModfStruct_Vector) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %v2float None %fn_v2float_v2float
%x = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %modf_v2_result_type %glsl ModfStruct %x
%2 = OpCompositeExtract %v2float %1 0
OpReturnValue %2
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %v2float %foo %v2float_50_60
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(8) {
tint_symbol:vec2<f32> @offset(0)
tint_symbol_1:vec2<f32> @offset(8)
}
__modf_result_vec2_f32 = struct @align(8) {
fract:vec2<f32> @offset(0)
whole:vec2<f32> @offset(8)
}
%foo = func(%x:vec2<f32>):vec2<f32> {
$B1: {
%3:__modf_result_vec2_f32 = modf %x
%4:vec2<f32> = access %3, 0u
%5:vec2<f32> = access %3, 1u
%6:tint_symbol_2 = construct %4, %5
%7:vec2<f32> = access %6, 0u
ret %7
}
}
)");
}
TEST_F(SpirvReaderTest, FrexpStruct_Store) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %void None %fn_void_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpVariable %ptr_function_frexp_result_type_unsigned Function
%2 = OpExtInst %frexp_result_type_unsigned %glsl FrexpStruct %x
OpStore %1 %2
OpReturn
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %void %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(4) {
tint_symbol:f32 @offset(0)
tint_symbol_1:u32 @offset(4)
}
__frexp_result_f32 = struct @align(4) {
fract:f32 @offset(0)
exp:i32 @offset(4)
}
%foo = func(%x:f32):void {
$B1: {
%3:ptr<function, tint_symbol_2, read_write> = var undef
%4:__frexp_result_f32 = frexp %x
%5:f32 = access %4, 0u
%6:i32 = access %4, 1u
%7:u32 = bitcast<u32> %6
%8:tint_symbol_2 = construct %5, %7
store %3, %8
ret
}
}
)");
}
TEST_F(SpirvReaderTest, FrexpStruct_ScalarUnsigned) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %void None %fn_void_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %frexp_result_type_unsigned %glsl FrexpStruct %x
%2 = OpCompositeExtract %float %1 0
%3 = OpCompositeExtract %uint %1 1
OpReturn
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %void %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(4) {
tint_symbol:f32 @offset(0)
tint_symbol_1:u32 @offset(4)
}
__frexp_result_f32 = struct @align(4) {
fract:f32 @offset(0)
exp:i32 @offset(4)
}
%foo = func(%x:f32):void {
$B1: {
%3:__frexp_result_f32 = frexp %x
%4:f32 = access %3, 0u
%5:i32 = access %3, 1u
%6:u32 = bitcast<u32> %5
%7:tint_symbol_2 = construct %4, %6
%8:f32 = access %7, 0u
%9:u32 = access %7, 1u
ret
}
}
)");
}
TEST_F(SpirvReaderTest, FrexpStruct_ScalarSigned) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %void None %fn_void_float
%x = OpFunctionParameter %float
%foo_entry = OpLabel
%1 = OpExtInst %frexp_result_type_signed %glsl FrexpStruct %x
%2 = OpCompositeExtract %float %1 0
%3 = OpCompositeExtract %int %1 1
OpReturn
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %void %foo %float_50
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(4) {
tint_symbol:f32 @offset(0)
tint_symbol_1:i32 @offset(4)
}
__frexp_result_f32 = struct @align(4) {
fract:f32 @offset(0)
exp:i32 @offset(4)
}
%foo = func(%x:f32):void {
$B1: {
%3:__frexp_result_f32 = frexp %x
%4:f32 = access %3, 0u
%5:i32 = access %3, 1u
%6:tint_symbol_2 = construct %4, %5
%7:f32 = access %6, 0u
%8:i32 = access %6, 1u
ret
}
}
)");
}
TEST_F(SpirvReaderTest, FrexpStruct_VectorUnsigned) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %void None %fn_void_v2float
%x = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %frexp_v2_result_type_unsigned %glsl FrexpStruct %x
%2 = OpCompositeExtract %v2float %1 0
%3 = OpCompositeExtract %v2uint %1 1
OpReturn
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %void %foo %v2float_50_60
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(8) {
tint_symbol:vec2<f32> @offset(0)
tint_symbol_1:vec2<u32> @offset(8)
}
__frexp_result_vec2_f32 = struct @align(8) {
fract:vec2<f32> @offset(0)
exp:vec2<i32> @offset(8)
}
%foo = func(%x:vec2<f32>):void {
$B1: {
%3:__frexp_result_vec2_f32 = frexp %x
%4:vec2<f32> = access %3, 0u
%5:vec2<i32> = access %3, 1u
%6:vec2<u32> = bitcast<vec2<u32>> %5
%7:tint_symbol_2 = construct %4, %6
%8:vec2<f32> = access %7, 0u
%9:vec2<u32> = access %7, 1u
ret
}
}
)");
}
TEST_F(SpirvReaderTest, FrexpStruct_VectorSigned) {
EXPECT_IR(Preamble(R"( OpName %foo "foo"
OpName %x "x"
)") + R"(
%foo = OpFunction %void None %fn_void_v2float
%x = OpFunctionParameter %v2float
%foo_entry = OpLabel
%1 = OpExtInst %frexp_v2_result_type_signed %glsl FrexpStruct %x
%2 = OpCompositeExtract %v2float %1 0
%3 = OpCompositeExtract %v2int %1 1
OpReturn
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%res = OpFunctionCall %void %foo %v2float_50_60
OpReturn
OpFunctionEnd
)",
R"(
tint_symbol_2 = struct @align(8) {
tint_symbol:vec2<f32> @offset(0)
tint_symbol_1:vec2<i32> @offset(8)
}
__frexp_result_vec2_f32 = struct @align(8) {
fract:vec2<f32> @offset(0)
exp:vec2<i32> @offset(8)
}
%foo = func(%x:vec2<f32>):void {
$B1: {
%3:__frexp_result_vec2_f32 = frexp %x
%4:vec2<f32> = access %3, 0u
%5:vec2<i32> = access %3, 1u
%6:tint_symbol_2 = construct %4, %5
%7:vec2<f32> = access %6, 0u
%8:vec2<i32> = access %6, 1u
ret
}
}
)");
}
} // namespace
} // namespace tint::spirv::reader