blob: 0e1dd0aca76812b1ca54d45697135f7a6ce70583 [file] [log] [blame]
// Copyright 2023 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/core/ir/transform/builtin_polyfill.h"
#include <utility>
#include "src/tint/lang/core/ir/transform/helper_test.h"
#include "src/tint/lang/core/type/sampled_texture.h"
namespace tint::core::ir::transform {
namespace {
using namespace tint::core::fluent_types; // NOLINT
using namespace tint::core::number_suffixes; // NOLINT
class IR_BuiltinPolyfillTest : public TransformTest {
protected:
/// Helper to build a function that calls a builtin with the given result and argument types.
/// @param builtin the builtin to call
/// @param result_ty the result type of the builtin call
/// @param arg_types the arguments types for the builtin call
void Build(core::BuiltinFn builtin,
const core::type::Type* result_ty,
VectorRef<const core::type::Type*> arg_types) {
Vector<FunctionParam*, 4> args;
for (auto* arg_ty : arg_types) {
args.Push(b.FunctionParam("arg", arg_ty));
}
auto* func = b.Function("foo", result_ty);
func->SetParams(args);
b.Append(func->Block(), [&] {
auto* result = b.Call(result_ty, builtin, args);
b.Return(func, result);
mod.SetName(result, "result");
});
}
};
TEST_F(IR_BuiltinPolyfillTest, Saturate_NoPolyfill) {
Build(core::BuiltinFn::kSaturate, ty.f32(), Vector{ty.f32()});
auto* src = R"(
%foo = func(%arg:f32):f32 {
$B1: {
%result:f32 = saturate %arg
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.saturate = false;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Saturate_F32) {
Build(core::BuiltinFn::kSaturate, ty.f32(), Vector{ty.f32()});
auto* src = R"(
%foo = func(%arg:f32):f32 {
$B1: {
%result:f32 = saturate %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:f32):f32 {
$B1: {
%result:f32 = clamp %arg, 0.0f, 1.0f
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.saturate = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Saturate_F16) {
Build(core::BuiltinFn::kSaturate, ty.f16(), Vector{ty.f16()});
auto* src = R"(
%foo = func(%arg:f16):f16 {
$B1: {
%result:f16 = saturate %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:f16):f16 {
$B1: {
%result:f16 = clamp %arg, 0.0h, 1.0h
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.saturate = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Saturate_Vec2F32) {
Build(core::BuiltinFn::kSaturate, ty.vec2<f32>(), Vector{ty.vec2<f32>()});
auto* src = R"(
%foo = func(%arg:vec2<f32>):vec2<f32> {
$B1: {
%result:vec2<f32> = saturate %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec2<f32>):vec2<f32> {
$B1: {
%result:vec2<f32> = clamp %arg, vec2<f32>(0.0f), vec2<f32>(1.0f)
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.saturate = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Saturate_Vec4F16) {
Build(core::BuiltinFn::kSaturate, ty.vec4<f16>(), Vector{ty.vec4<f16>()});
auto* src = R"(
%foo = func(%arg:vec4<f16>):vec4<f16> {
$B1: {
%result:vec4<f16> = saturate %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec4<f16>):vec4<f16> {
$B1: {
%result:vec4<f16> = clamp %arg, vec4<f16>(0.0h), vec4<f16>(1.0h)
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.saturate = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_NoPolyfill) {
Build(core::BuiltinFn::kCountLeadingZeros, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = countLeadingZeros %arg
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_leading_zeros = false;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_U32) {
Build(core::BuiltinFn::kCountLeadingZeros, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = countLeadingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%3:bool = lte %arg, 65535u
%4:u32 = select 0u, 16u, %3
%5:u32 = shl %arg, %4
%6:bool = lte %5, 16777215u
%7:u32 = select 0u, 8u, %6
%8:u32 = shl %5, %7
%9:bool = lte %8, 268435455u
%10:u32 = select 0u, 4u, %9
%11:u32 = shl %8, %10
%12:bool = lte %11, 1073741823u
%13:u32 = select 0u, 2u, %12
%14:u32 = shl %11, %13
%15:bool = lte %14, 2147483647u
%16:u32 = select 0u, 1u, %15
%17:bool = eq %14, 0u
%18:u32 = select 0u, 1u, %17
%19:u32 = or %16, %18
%20:u32 = or %13, %19
%21:u32 = or %10, %20
%22:u32 = or %7, %21
%23:u32 = or %4, %22
%result:u32 = add %23, %18
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_leading_zeros = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_I32) {
Build(core::BuiltinFn::kCountLeadingZeros, ty.i32(), Vector{ty.i32()});
auto* src = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%result:i32 = countLeadingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%3:u32 = bitcast %arg
%4:bool = lte %3, 65535u
%5:u32 = select 0u, 16u, %4
%6:u32 = shl %3, %5
%7:bool = lte %6, 16777215u
%8:u32 = select 0u, 8u, %7
%9:u32 = shl %6, %8
%10:bool = lte %9, 268435455u
%11:u32 = select 0u, 4u, %10
%12:u32 = shl %9, %11
%13:bool = lte %12, 1073741823u
%14:u32 = select 0u, 2u, %13
%15:u32 = shl %12, %14
%16:bool = lte %15, 2147483647u
%17:u32 = select 0u, 1u, %16
%18:bool = eq %15, 0u
%19:u32 = select 0u, 1u, %18
%20:u32 = or %17, %19
%21:u32 = or %14, %20
%22:u32 = or %11, %21
%23:u32 = or %8, %22
%24:u32 = or %5, %23
%25:u32 = add %24, %19
%result:i32 = bitcast %25
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_leading_zeros = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_Vec2U32) {
Build(core::BuiltinFn::kCountLeadingZeros, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
auto* src = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%result:vec2<u32> = countLeadingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%3:vec2<bool> = lte %arg, vec2<u32>(65535u)
%4:vec2<u32> = select vec2<u32>(0u), vec2<u32>(16u), %3
%5:vec2<u32> = shl %arg, %4
%6:vec2<bool> = lte %5, vec2<u32>(16777215u)
%7:vec2<u32> = select vec2<u32>(0u), vec2<u32>(8u), %6
%8:vec2<u32> = shl %5, %7
%9:vec2<bool> = lte %8, vec2<u32>(268435455u)
%10:vec2<u32> = select vec2<u32>(0u), vec2<u32>(4u), %9
%11:vec2<u32> = shl %8, %10
%12:vec2<bool> = lte %11, vec2<u32>(1073741823u)
%13:vec2<u32> = select vec2<u32>(0u), vec2<u32>(2u), %12
%14:vec2<u32> = shl %11, %13
%15:vec2<bool> = lte %14, vec2<u32>(2147483647u)
%16:vec2<u32> = select vec2<u32>(0u), vec2<u32>(1u), %15
%17:vec2<bool> = eq %14, vec2<u32>(0u)
%18:vec2<u32> = select vec2<u32>(0u), vec2<u32>(1u), %17
%19:vec2<u32> = or %16, %18
%20:vec2<u32> = or %13, %19
%21:vec2<u32> = or %10, %20
%22:vec2<u32> = or %7, %21
%23:vec2<u32> = or %4, %22
%result:vec2<u32> = add %23, %18
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_leading_zeros = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_Vec4I32) {
Build(core::BuiltinFn::kCountLeadingZeros, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
auto* src = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%result:vec4<i32> = countLeadingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%3:vec4<u32> = bitcast %arg
%4:vec4<bool> = lte %3, vec4<u32>(65535u)
%5:vec4<u32> = select vec4<u32>(0u), vec4<u32>(16u), %4
%6:vec4<u32> = shl %3, %5
%7:vec4<bool> = lte %6, vec4<u32>(16777215u)
%8:vec4<u32> = select vec4<u32>(0u), vec4<u32>(8u), %7
%9:vec4<u32> = shl %6, %8
%10:vec4<bool> = lte %9, vec4<u32>(268435455u)
%11:vec4<u32> = select vec4<u32>(0u), vec4<u32>(4u), %10
%12:vec4<u32> = shl %9, %11
%13:vec4<bool> = lte %12, vec4<u32>(1073741823u)
%14:vec4<u32> = select vec4<u32>(0u), vec4<u32>(2u), %13
%15:vec4<u32> = shl %12, %14
%16:vec4<bool> = lte %15, vec4<u32>(2147483647u)
%17:vec4<u32> = select vec4<u32>(0u), vec4<u32>(1u), %16
%18:vec4<bool> = eq %15, vec4<u32>(0u)
%19:vec4<u32> = select vec4<u32>(0u), vec4<u32>(1u), %18
%20:vec4<u32> = or %17, %19
%21:vec4<u32> = or %14, %20
%22:vec4<u32> = or %11, %21
%23:vec4<u32> = or %8, %22
%24:vec4<u32> = or %5, %23
%25:vec4<u32> = add %24, %19
%result:vec4<i32> = bitcast %25
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_leading_zeros = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_NoPolyfill) {
Build(core::BuiltinFn::kCountTrailingZeros, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = countTrailingZeros %arg
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_trailing_zeros = false;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_U32) {
Build(core::BuiltinFn::kCountTrailingZeros, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = countTrailingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%3:u32 = and %arg, 65535u
%4:bool = eq %3, 0u
%5:u32 = select 0u, 16u, %4
%6:u32 = shr %arg, %5
%7:u32 = and %6, 255u
%8:bool = eq %7, 0u
%9:u32 = select 0u, 8u, %8
%10:u32 = shr %6, %9
%11:u32 = and %10, 15u
%12:bool = eq %11, 0u
%13:u32 = select 0u, 4u, %12
%14:u32 = shr %10, %13
%15:u32 = and %14, 3u
%16:bool = eq %15, 0u
%17:u32 = select 0u, 2u, %16
%18:u32 = shr %14, %17
%19:u32 = and %18, 1u
%20:bool = eq %19, 0u
%21:u32 = select 0u, 1u, %20
%22:bool = eq %18, 0u
%23:u32 = select 0u, 1u, %22
%24:u32 = or %17, %21
%25:u32 = or %13, %24
%26:u32 = or %9, %25
%27:u32 = or %5, %26
%result:u32 = add %27, %23
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_trailing_zeros = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_I32) {
Build(core::BuiltinFn::kCountTrailingZeros, ty.i32(), Vector{ty.i32()});
auto* src = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%result:i32 = countTrailingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%3:u32 = bitcast %arg
%4:u32 = and %3, 65535u
%5:bool = eq %4, 0u
%6:u32 = select 0u, 16u, %5
%7:u32 = shr %3, %6
%8:u32 = and %7, 255u
%9:bool = eq %8, 0u
%10:u32 = select 0u, 8u, %9
%11:u32 = shr %7, %10
%12:u32 = and %11, 15u
%13:bool = eq %12, 0u
%14:u32 = select 0u, 4u, %13
%15:u32 = shr %11, %14
%16:u32 = and %15, 3u
%17:bool = eq %16, 0u
%18:u32 = select 0u, 2u, %17
%19:u32 = shr %15, %18
%20:u32 = and %19, 1u
%21:bool = eq %20, 0u
%22:u32 = select 0u, 1u, %21
%23:bool = eq %19, 0u
%24:u32 = select 0u, 1u, %23
%25:u32 = or %18, %22
%26:u32 = or %14, %25
%27:u32 = or %10, %26
%28:u32 = or %6, %27
%29:u32 = add %28, %24
%result:i32 = bitcast %29
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_trailing_zeros = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_Vec2U32) {
Build(core::BuiltinFn::kCountTrailingZeros, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
auto* src = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%result:vec2<u32> = countTrailingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%3:vec2<u32> = and %arg, vec2<u32>(65535u)
%4:vec2<bool> = eq %3, vec2<u32>(0u)
%5:vec2<u32> = select vec2<u32>(0u), vec2<u32>(16u), %4
%6:vec2<u32> = shr %arg, %5
%7:vec2<u32> = and %6, vec2<u32>(255u)
%8:vec2<bool> = eq %7, vec2<u32>(0u)
%9:vec2<u32> = select vec2<u32>(0u), vec2<u32>(8u), %8
%10:vec2<u32> = shr %6, %9
%11:vec2<u32> = and %10, vec2<u32>(15u)
%12:vec2<bool> = eq %11, vec2<u32>(0u)
%13:vec2<u32> = select vec2<u32>(0u), vec2<u32>(4u), %12
%14:vec2<u32> = shr %10, %13
%15:vec2<u32> = and %14, vec2<u32>(3u)
%16:vec2<bool> = eq %15, vec2<u32>(0u)
%17:vec2<u32> = select vec2<u32>(0u), vec2<u32>(2u), %16
%18:vec2<u32> = shr %14, %17
%19:vec2<u32> = and %18, vec2<u32>(1u)
%20:vec2<bool> = eq %19, vec2<u32>(0u)
%21:vec2<u32> = select vec2<u32>(0u), vec2<u32>(1u), %20
%22:vec2<bool> = eq %18, vec2<u32>(0u)
%23:vec2<u32> = select vec2<u32>(0u), vec2<u32>(1u), %22
%24:vec2<u32> = or %17, %21
%25:vec2<u32> = or %13, %24
%26:vec2<u32> = or %9, %25
%27:vec2<u32> = or %5, %26
%result:vec2<u32> = add %27, %23
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.count_trailing_zeros = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_Vec4I32) {
Build(core::BuiltinFn::kCountTrailingZeros, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
auto* src = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%result:vec4<i32> = countTrailingZeros %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%result:vec4<i32> = countTrailingZeros %arg
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_trailing_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, ExtractBits_NoPolyfill) {
Build(core::BuiltinFn::kExtractBits, ty.u32(), Vector{ty.u32(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:u32, %arg_1:u32, %arg_2:u32):u32 { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%result:u32 = extractBits %arg, %arg_1, %arg_2
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.extract_bits = BuiltinPolyfillLevel::kNone;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, ExtractBits_ClampArgs_U32) {
Build(core::BuiltinFn::kExtractBits, ty.u32(), Vector{ty.u32(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:u32, %arg_1:u32, %arg_2:u32):u32 { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%result:u32 = extractBits %arg, %arg_1, %arg_2
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:u32, %arg_1:u32, %arg_2:u32):u32 { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%5:u32 = min %arg_1, 32u
%6:u32 = sub 32u, %5
%7:u32 = min %arg_2, %6
%result:u32 = extractBits %arg, %5, %7
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.extract_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, ExtractBits_ClampArgs_I32) {
Build(core::BuiltinFn::kExtractBits, ty.i32(), Vector{ty.i32(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:i32, %arg_1:u32, %arg_2:u32):i32 { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%result:i32 = extractBits %arg, %arg_1, %arg_2
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:i32, %arg_1:u32, %arg_2:u32):i32 { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%5:u32 = min %arg_1, 32u
%6:u32 = sub 32u, %5
%7:u32 = min %arg_2, %6
%result:i32 = extractBits %arg, %5, %7
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.extract_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, ExtractBits_ClampArgs_Vec2U32) {
Build(core::BuiltinFn::kExtractBits, ty.vec2<u32>(),
Vector{ty.vec2<u32>(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:vec2<u32>, %arg_1:u32, %arg_2:u32):vec2<u32> { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%result:vec2<u32> = extractBits %arg, %arg_1, %arg_2
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec2<u32>, %arg_1:u32, %arg_2:u32):vec2<u32> { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%5:u32 = min %arg_1, 32u
%6:u32 = sub 32u, %5
%7:u32 = min %arg_2, %6
%result:vec2<u32> = extractBits %arg, %5, %7
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.extract_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, ExtractBits_ClampArgs_Vec4I32) {
Build(core::BuiltinFn::kExtractBits, ty.vec4<i32>(),
Vector{ty.vec4<i32>(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:vec4<i32>, %arg_1:u32, %arg_2:u32):vec4<i32> { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%result:vec4<i32> = extractBits %arg, %arg_1, %arg_2
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec4<i32>, %arg_1:u32, %arg_2:u32):vec4<i32> { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%5:u32 = min %arg_1, 32u
%6:u32 = sub 32u, %5
%7:u32 = min %arg_2, %6
%result:vec4<i32> = extractBits %arg, %5, %7
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.extract_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_NoPolyfill) {
Build(core::BuiltinFn::kFirstLeadingBit, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = firstLeadingBit %arg
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_leading_bit = false;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_U32) {
Build(core::BuiltinFn::kFirstLeadingBit, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = firstLeadingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%3:u32 = and %arg, 4294901760u
%4:bool = eq %3, 0u
%5:u32 = select 16u, 0u, %4
%6:u32 = shr %arg, %5
%7:u32 = and %6, 65280u
%8:bool = eq %7, 0u
%9:u32 = select 8u, 0u, %8
%10:u32 = shr %6, %9
%11:u32 = and %10, 240u
%12:bool = eq %11, 0u
%13:u32 = select 4u, 0u, %12
%14:u32 = shr %10, %13
%15:u32 = and %14, 12u
%16:bool = eq %15, 0u
%17:u32 = select 2u, 0u, %16
%18:u32 = shr %14, %17
%19:u32 = and %18, 2u
%20:bool = eq %19, 0u
%21:u32 = select 1u, 0u, %20
%22:u32 = or %17, %21
%23:u32 = or %13, %22
%24:u32 = or %9, %23
%25:u32 = or %5, %24
%26:bool = eq %18, 0u
%result:u32 = select %25, 4294967295u, %26
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_leading_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_I32) {
Build(core::BuiltinFn::kFirstLeadingBit, ty.i32(), Vector{ty.i32()});
auto* src = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%result:i32 = firstLeadingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%3:u32 = bitcast %arg
%4:u32 = complement %3
%5:bool = lt %3, 2147483648u
%6:u32 = select %4, %3, %5
%7:u32 = and %6, 4294901760u
%8:bool = eq %7, 0u
%9:u32 = select 16u, 0u, %8
%10:u32 = shr %6, %9
%11:u32 = and %10, 65280u
%12:bool = eq %11, 0u
%13:u32 = select 8u, 0u, %12
%14:u32 = shr %10, %13
%15:u32 = and %14, 240u
%16:bool = eq %15, 0u
%17:u32 = select 4u, 0u, %16
%18:u32 = shr %14, %17
%19:u32 = and %18, 12u
%20:bool = eq %19, 0u
%21:u32 = select 2u, 0u, %20
%22:u32 = shr %18, %21
%23:u32 = and %22, 2u
%24:bool = eq %23, 0u
%25:u32 = select 1u, 0u, %24
%26:u32 = or %21, %25
%27:u32 = or %17, %26
%28:u32 = or %13, %27
%29:u32 = or %9, %28
%30:bool = eq %22, 0u
%31:u32 = select %29, 4294967295u, %30
%result:i32 = bitcast %31
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_leading_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_Vec2U32) {
Build(core::BuiltinFn::kFirstLeadingBit, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
auto* src = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%result:vec2<u32> = firstLeadingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%3:vec2<u32> = and %arg, vec2<u32>(4294901760u)
%4:vec2<bool> = eq %3, vec2<u32>(0u)
%5:vec2<u32> = select vec2<u32>(16u), vec2<u32>(0u), %4
%6:vec2<u32> = shr %arg, %5
%7:vec2<u32> = and %6, vec2<u32>(65280u)
%8:vec2<bool> = eq %7, vec2<u32>(0u)
%9:vec2<u32> = select vec2<u32>(8u), vec2<u32>(0u), %8
%10:vec2<u32> = shr %6, %9
%11:vec2<u32> = and %10, vec2<u32>(240u)
%12:vec2<bool> = eq %11, vec2<u32>(0u)
%13:vec2<u32> = select vec2<u32>(4u), vec2<u32>(0u), %12
%14:vec2<u32> = shr %10, %13
%15:vec2<u32> = and %14, vec2<u32>(12u)
%16:vec2<bool> = eq %15, vec2<u32>(0u)
%17:vec2<u32> = select vec2<u32>(2u), vec2<u32>(0u), %16
%18:vec2<u32> = shr %14, %17
%19:vec2<u32> = and %18, vec2<u32>(2u)
%20:vec2<bool> = eq %19, vec2<u32>(0u)
%21:vec2<u32> = select vec2<u32>(1u), vec2<u32>(0u), %20
%22:vec2<u32> = or %17, %21
%23:vec2<u32> = or %13, %22
%24:vec2<u32> = or %9, %23
%25:vec2<u32> = or %5, %24
%26:vec2<bool> = eq %18, vec2<u32>(0u)
%result:vec2<u32> = select %25, vec2<u32>(4294967295u), %26
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_leading_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_Vec4I32) {
Build(core::BuiltinFn::kFirstLeadingBit, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
auto* src = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%result:vec4<i32> = firstLeadingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%3:vec4<u32> = bitcast %arg
%4:vec4<u32> = complement %3
%5:vec4<bool> = lt %3, vec4<u32>(2147483648u)
%6:vec4<u32> = select %4, %3, %5
%7:vec4<u32> = and %6, vec4<u32>(4294901760u)
%8:vec4<bool> = eq %7, vec4<u32>(0u)
%9:vec4<u32> = select vec4<u32>(16u), vec4<u32>(0u), %8
%10:vec4<u32> = shr %6, %9
%11:vec4<u32> = and %10, vec4<u32>(65280u)
%12:vec4<bool> = eq %11, vec4<u32>(0u)
%13:vec4<u32> = select vec4<u32>(8u), vec4<u32>(0u), %12
%14:vec4<u32> = shr %10, %13
%15:vec4<u32> = and %14, vec4<u32>(240u)
%16:vec4<bool> = eq %15, vec4<u32>(0u)
%17:vec4<u32> = select vec4<u32>(4u), vec4<u32>(0u), %16
%18:vec4<u32> = shr %14, %17
%19:vec4<u32> = and %18, vec4<u32>(12u)
%20:vec4<bool> = eq %19, vec4<u32>(0u)
%21:vec4<u32> = select vec4<u32>(2u), vec4<u32>(0u), %20
%22:vec4<u32> = shr %18, %21
%23:vec4<u32> = and %22, vec4<u32>(2u)
%24:vec4<bool> = eq %23, vec4<u32>(0u)
%25:vec4<u32> = select vec4<u32>(1u), vec4<u32>(0u), %24
%26:vec4<u32> = or %21, %25
%27:vec4<u32> = or %17, %26
%28:vec4<u32> = or %13, %27
%29:vec4<u32> = or %9, %28
%30:vec4<bool> = eq %22, vec4<u32>(0u)
%31:vec4<u32> = select %29, vec4<u32>(4294967295u), %30
%result:vec4<i32> = bitcast %31
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_leading_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_NoPolyfill) {
Build(core::BuiltinFn::kFirstTrailingBit, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = firstTrailingBit %arg
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_trailing_bit = false;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_U32) {
Build(core::BuiltinFn::kFirstTrailingBit, ty.u32(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%result:u32 = firstTrailingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:u32):u32 {
$B1: {
%3:u32 = and %arg, 65535u
%4:bool = eq %3, 0u
%5:u32 = select 0u, 16u, %4
%6:u32 = shr %arg, %5
%7:u32 = and %6, 255u
%8:bool = eq %7, 0u
%9:u32 = select 0u, 8u, %8
%10:u32 = shr %6, %9
%11:u32 = and %10, 15u
%12:bool = eq %11, 0u
%13:u32 = select 0u, 4u, %12
%14:u32 = shr %10, %13
%15:u32 = and %14, 3u
%16:bool = eq %15, 0u
%17:u32 = select 0u, 2u, %16
%18:u32 = shr %14, %17
%19:u32 = and %18, 1u
%20:bool = eq %19, 0u
%21:u32 = select 0u, 1u, %20
%22:u32 = or %17, %21
%23:u32 = or %13, %22
%24:u32 = or %9, %23
%25:u32 = or %5, %24
%26:bool = eq %18, 0u
%result:u32 = select %25, 4294967295u, %26
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_trailing_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_I32) {
Build(core::BuiltinFn::kFirstTrailingBit, ty.i32(), Vector{ty.i32()});
auto* src = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%result:i32 = firstTrailingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:i32):i32 {
$B1: {
%3:u32 = bitcast %arg
%4:u32 = and %3, 65535u
%5:bool = eq %4, 0u
%6:u32 = select 0u, 16u, %5
%7:u32 = shr %3, %6
%8:u32 = and %7, 255u
%9:bool = eq %8, 0u
%10:u32 = select 0u, 8u, %9
%11:u32 = shr %7, %10
%12:u32 = and %11, 15u
%13:bool = eq %12, 0u
%14:u32 = select 0u, 4u, %13
%15:u32 = shr %11, %14
%16:u32 = and %15, 3u
%17:bool = eq %16, 0u
%18:u32 = select 0u, 2u, %17
%19:u32 = shr %15, %18
%20:u32 = and %19, 1u
%21:bool = eq %20, 0u
%22:u32 = select 0u, 1u, %21
%23:u32 = or %18, %22
%24:u32 = or %14, %23
%25:u32 = or %10, %24
%26:u32 = or %6, %25
%27:bool = eq %19, 0u
%28:u32 = select %26, 4294967295u, %27
%result:i32 = bitcast %28
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_trailing_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_Vec2U32) {
Build(core::BuiltinFn::kFirstTrailingBit, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
auto* src = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%result:vec2<u32> = firstTrailingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec2<u32>):vec2<u32> {
$B1: {
%3:vec2<u32> = and %arg, vec2<u32>(65535u)
%4:vec2<bool> = eq %3, vec2<u32>(0u)
%5:vec2<u32> = select vec2<u32>(0u), vec2<u32>(16u), %4
%6:vec2<u32> = shr %arg, %5
%7:vec2<u32> = and %6, vec2<u32>(255u)
%8:vec2<bool> = eq %7, vec2<u32>(0u)
%9:vec2<u32> = select vec2<u32>(0u), vec2<u32>(8u), %8
%10:vec2<u32> = shr %6, %9
%11:vec2<u32> = and %10, vec2<u32>(15u)
%12:vec2<bool> = eq %11, vec2<u32>(0u)
%13:vec2<u32> = select vec2<u32>(0u), vec2<u32>(4u), %12
%14:vec2<u32> = shr %10, %13
%15:vec2<u32> = and %14, vec2<u32>(3u)
%16:vec2<bool> = eq %15, vec2<u32>(0u)
%17:vec2<u32> = select vec2<u32>(0u), vec2<u32>(2u), %16
%18:vec2<u32> = shr %14, %17
%19:vec2<u32> = and %18, vec2<u32>(1u)
%20:vec2<bool> = eq %19, vec2<u32>(0u)
%21:vec2<u32> = select vec2<u32>(0u), vec2<u32>(1u), %20
%22:vec2<u32> = or %17, %21
%23:vec2<u32> = or %13, %22
%24:vec2<u32> = or %9, %23
%25:vec2<u32> = or %5, %24
%26:vec2<bool> = eq %18, vec2<u32>(0u)
%result:vec2<u32> = select %25, vec2<u32>(4294967295u), %26
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_trailing_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_Vec4I32) {
Build(core::BuiltinFn::kFirstTrailingBit, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
auto* src = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%result:vec4<i32> = firstTrailingBit %arg
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec4<i32>):vec4<i32> {
$B1: {
%3:vec4<u32> = bitcast %arg
%4:vec4<u32> = and %3, vec4<u32>(65535u)
%5:vec4<bool> = eq %4, vec4<u32>(0u)
%6:vec4<u32> = select vec4<u32>(0u), vec4<u32>(16u), %5
%7:vec4<u32> = shr %3, %6
%8:vec4<u32> = and %7, vec4<u32>(255u)
%9:vec4<bool> = eq %8, vec4<u32>(0u)
%10:vec4<u32> = select vec4<u32>(0u), vec4<u32>(8u), %9
%11:vec4<u32> = shr %7, %10
%12:vec4<u32> = and %11, vec4<u32>(15u)
%13:vec4<bool> = eq %12, vec4<u32>(0u)
%14:vec4<u32> = select vec4<u32>(0u), vec4<u32>(4u), %13
%15:vec4<u32> = shr %11, %14
%16:vec4<u32> = and %15, vec4<u32>(3u)
%17:vec4<bool> = eq %16, vec4<u32>(0u)
%18:vec4<u32> = select vec4<u32>(0u), vec4<u32>(2u), %17
%19:vec4<u32> = shr %15, %18
%20:vec4<u32> = and %19, vec4<u32>(1u)
%21:vec4<bool> = eq %20, vec4<u32>(0u)
%22:vec4<u32> = select vec4<u32>(0u), vec4<u32>(1u), %21
%23:vec4<u32> = or %18, %22
%24:vec4<u32> = or %14, %23
%25:vec4<u32> = or %10, %24
%26:vec4<u32> = or %6, %25
%27:vec4<bool> = eq %19, vec4<u32>(0u)
%28:vec4<u32> = select %26, vec4<u32>(4294967295u), %27
%result:vec4<i32> = bitcast %28
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.first_trailing_bit = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, InsertBits_NoPolyfill) {
Build(core::BuiltinFn::kInsertBits, ty.u32(), Vector{ty.u32(), ty.u32(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:u32, %arg_1:u32, %arg_2:u32, %arg_3:u32):u32 { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%result:u32 = insertBits %arg, %arg_1, %arg_2, %arg_3
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.insert_bits = BuiltinPolyfillLevel::kNone;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, InsertBits_ClampArgs_U32) {
Build(core::BuiltinFn::kInsertBits, ty.u32(), Vector{ty.u32(), ty.u32(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:u32, %arg_1:u32, %arg_2:u32, %arg_3:u32):u32 { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%result:u32 = insertBits %arg, %arg_1, %arg_2, %arg_3
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:u32, %arg_1:u32, %arg_2:u32, %arg_3:u32):u32 { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%6:u32 = min %arg_2, 32u
%7:u32 = sub 32u, %6
%8:u32 = min %arg_3, %7
%result:u32 = insertBits %arg, %arg_1, %6, %8
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.insert_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, InsertBits_ClampArgs_I32) {
Build(core::BuiltinFn::kInsertBits, ty.i32(), Vector{ty.i32(), ty.i32(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:i32, %arg_1:i32, %arg_2:u32, %arg_3:u32):i32 { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%result:i32 = insertBits %arg, %arg_1, %arg_2, %arg_3
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:i32, %arg_1:i32, %arg_2:u32, %arg_3:u32):i32 { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%6:u32 = min %arg_2, 32u
%7:u32 = sub 32u, %6
%8:u32 = min %arg_3, %7
%result:i32 = insertBits %arg, %arg_1, %6, %8
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.insert_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, InsertBits_ClampArgs_Vec2U32) {
Build(core::BuiltinFn::kInsertBits, ty.vec2<u32>(),
Vector{ty.vec2<u32>(), ty.vec2<u32>(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:vec2<u32>, %arg_1:vec2<u32>, %arg_2:u32, %arg_3:u32):vec2<u32> { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%result:vec2<u32> = insertBits %arg, %arg_1, %arg_2, %arg_3
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec2<u32>, %arg_1:vec2<u32>, %arg_2:u32, %arg_3:u32):vec2<u32> { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%6:u32 = min %arg_2, 32u
%7:u32 = sub 32u, %6
%8:u32 = min %arg_3, %7
%result:vec2<u32> = insertBits %arg, %arg_1, %6, %8
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.insert_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, InsertBits_ClampArgs_Vec4I32) {
Build(core::BuiltinFn::kInsertBits, ty.vec4<i32>(),
Vector{ty.vec4<i32>(), ty.vec4<i32>(), ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:vec4<i32>, %arg_1:vec4<i32>, %arg_2:u32, %arg_3:u32):vec4<i32> { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%result:vec4<i32> = insertBits %arg, %arg_1, %arg_2, %arg_3
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:vec4<i32>, %arg_1:vec4<i32>, %arg_2:u32, %arg_3:u32):vec4<i32> { # %arg_1: 'arg', %arg_2: 'arg', %arg_3: 'arg'
$B1: {
%6:u32 = min %arg_2, 32u
%7:u32 = sub 32u, %6
%8:u32 = min %arg_3, %7
%result:vec4<i32> = insertBits %arg, %arg_1, %6, %8
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.insert_bits = BuiltinPolyfillLevel::kClampOrRangeCheck;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, TextureSampleBaseClampToEdge_2d_f32_NoPolyfill) {
auto* texture_ty =
ty.Get<core::type::SampledTexture>(core::type::TextureDimension::k2d, ty.f32());
Build(core::BuiltinFn::kTextureSampleBaseClampToEdge, ty.vec4<f32>(),
Vector{texture_ty, ty.sampler(), ty.vec2<f32>()});
auto* src = R"(
%foo = func(%arg:texture_2d<f32>, %arg_1:sampler, %arg_2:vec2<f32>):vec4<f32> { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%result:vec4<f32> = textureSampleBaseClampToEdge %arg, %arg_1, %arg_2
ret %result
}
}
)";
auto* expect = src;
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.texture_sample_base_clamp_to_edge_2d_f32 = false;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, TextureSampleBaseClampToEdge_2d_f32) {
auto* texture_ty =
ty.Get<core::type::SampledTexture>(core::type::TextureDimension::k2d, ty.f32());
Build(core::BuiltinFn::kTextureSampleBaseClampToEdge, ty.vec4<f32>(),
Vector{texture_ty, ty.sampler(), ty.vec2<f32>()});
auto* src = R"(
%foo = func(%arg:texture_2d<f32>, %arg_1:sampler, %arg_2:vec2<f32>):vec4<f32> { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%result:vec4<f32> = textureSampleBaseClampToEdge %arg, %arg_1, %arg_2
ret %result
}
}
)";
auto* expect = R"(
%foo = func(%arg:texture_2d<f32>, %arg_1:sampler, %arg_2:vec2<f32>):vec4<f32> { # %arg_1: 'arg', %arg_2: 'arg'
$B1: {
%5:vec2<u32> = textureDimensions %arg
%6:vec2<f32> = convert %5
%7:vec2<f32> = div vec2<f32>(0.5f), %6
%8:vec2<f32> = sub vec2<f32>(1.0f), %7
%9:vec2<f32> = clamp %arg_2, %7, %8
%result:vec4<f32> = textureSampleLevel %arg, %arg_1, %9, 0.0f
ret %result
}
}
)";
EXPECT_EQ(src, str());
BuiltinPolyfillConfig config;
config.texture_sample_base_clamp_to_edge_2d_f32 = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Pack4xI8) {
Build(core::BuiltinFn::kPack4XI8, ty.u32(), Vector{ty.vec4<i32>()});
auto* src = R"(
%foo = func(%arg:vec4<i32>):u32 {
$B1: {
%result:u32 = pack4xI8 %arg
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:vec4<i32>):u32 {
$B1: {
%3:vec4<u32> = construct 0u, 8u, 16u, 24u
%4:vec4<u32> = bitcast %arg
%5:vec4<u32> = construct 255u
%6:vec4<u32> = and %4, %5
%7:vec4<u32> = shl %6, %3
%8:vec4<u32> = construct 1u
%result:u32 = dot %7, %8
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.pack_unpack_4x8 = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Pack4xU8) {
Build(core::BuiltinFn::kPack4XU8, ty.u32(), Vector{ty.vec4<u32>()});
auto* src = R"(
%foo = func(%arg:vec4<u32>):u32 {
$B1: {
%result:u32 = pack4xU8 %arg
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:vec4<u32>):u32 {
$B1: {
%3:vec4<u32> = construct 0u, 8u, 16u, 24u
%4:vec4<u32> = construct 255u
%5:vec4<u32> = and %arg, %4
%6:vec4<u32> = shl %5, %3
%7:vec4<u32> = construct 1u
%result:u32 = dot %6, %7
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.pack_unpack_4x8 = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Pack4xI8Clamp) {
Build(core::BuiltinFn::kPack4XI8Clamp, ty.u32(), Vector{ty.vec4<i32>()});
auto* src = R"(
%foo = func(%arg:vec4<i32>):u32 {
$B1: {
%result:u32 = pack4xI8Clamp %arg
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:vec4<i32>):u32 {
$B1: {
%3:vec4<u32> = construct 0u, 8u, 16u, 24u
%4:vec4<i32> = construct -128i
%5:vec4<i32> = construct 127i
%6:vec4<i32> = clamp %arg, %4, %5
%7:vec4<u32> = bitcast %6
%8:vec4<u32> = construct 255u
%9:vec4<u32> = and %7, %8
%10:vec4<u32> = shl %9, %3
%11:vec4<u32> = construct 1u
%result:u32 = dot %10, %11
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.pack_unpack_4x8 = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Pack4xU8Clamp) {
Build(core::BuiltinFn::kPack4XU8Clamp, ty.u32(), Vector{ty.vec4<u32>()});
auto* src = R"(
%foo = func(%arg:vec4<u32>):u32 {
$B1: {
%result:u32 = pack4xU8Clamp %arg
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:vec4<u32>):u32 {
$B1: {
%3:vec4<u32> = construct 0u, 8u, 16u, 24u
%4:vec4<u32> = construct 0u
%5:vec4<u32> = construct 255u
%6:vec4<u32> = clamp %arg, %4, %5
%7:vec4<u32> = shl %6, %3
%8:vec4<u32> = construct 1u
%result:u32 = dot %7, %8
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.pack_4xu8_clamp = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Unpack4xI8) {
Build(core::BuiltinFn::kUnpack4XI8, ty.vec4<i32>(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):vec4<i32> {
$B1: {
%result:vec4<i32> = unpack4xI8 %arg
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:u32):vec4<i32> {
$B1: {
%3:vec4<u32> = construct 24u, 16u, 8u, 0u
%4:vec4<u32> = construct %arg
%5:vec4<u32> = shl %4, %3
%6:vec4<i32> = bitcast %5
%7:vec4<u32> = construct 24u
%result:vec4<i32> = shr %6, %7
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.pack_unpack_4x8 = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Unpack4xU8) {
Build(core::BuiltinFn::kUnpack4XU8, ty.vec4<u32>(), Vector{ty.u32()});
auto* src = R"(
%foo = func(%arg:u32):vec4<u32> {
$B1: {
%result:vec4<u32> = unpack4xU8 %arg
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:u32):vec4<u32> {
$B1: {
%3:vec4<u32> = construct 0u, 8u, 16u, 24u
%4:vec4<u32> = construct %arg
%5:vec4<u32> = shr %4, %3
%6:vec4<u32> = construct 255u
%result:vec4<u32> = and %5, %6
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.pack_unpack_4x8 = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Dot4I8Packed) {
Build(core::BuiltinFn::kDot4I8Packed, ty.i32(), Vector{ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:u32, %arg_1:u32):i32 { # %arg_1: 'arg'
$B1: {
%result:i32 = dot4I8Packed %arg, %arg_1
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:u32, %arg_1:u32):i32 { # %arg_1: 'arg'
$B1: {
%4:vec4<u32> = construct 24u, 16u, 8u, 0u
%5:vec4<u32> = construct %arg
%6:vec4<u32> = shl %5, %4
%7:vec4<i32> = bitcast %6
%8:vec4<u32> = construct 24u
%9:vec4<i32> = shr %7, %8
%10:vec4<u32> = construct 24u, 16u, 8u, 0u
%11:vec4<u32> = construct %arg_1
%12:vec4<u32> = shl %11, %10
%13:vec4<i32> = bitcast %12
%14:vec4<u32> = construct 24u
%15:vec4<i32> = shr %13, %14
%result:i32 = dot %9, %15
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.dot_4x8_packed = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
TEST_F(IR_BuiltinPolyfillTest, Dot4U8Packed) {
Build(core::BuiltinFn::kDot4U8Packed, ty.u32(), Vector{ty.u32(), ty.u32()});
auto* src = R"(
%foo = func(%arg:u32, %arg_1:u32):u32 { # %arg_1: 'arg'
$B1: {
%result:u32 = dot4U8Packed %arg, %arg_1
ret %result
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
%foo = func(%arg:u32, %arg_1:u32):u32 { # %arg_1: 'arg'
$B1: {
%4:vec4<u32> = construct 0u, 8u, 16u, 24u
%5:vec4<u32> = construct %arg
%6:vec4<u32> = shr %5, %4
%7:vec4<u32> = construct 255u
%8:vec4<u32> = and %6, %7
%9:vec4<u32> = construct 0u, 8u, 16u, 24u
%10:vec4<u32> = construct %arg_1
%11:vec4<u32> = shr %10, %9
%12:vec4<u32> = construct 255u
%13:vec4<u32> = and %11, %12
%result:u32 = dot %8, %13
ret %result
}
}
)";
BuiltinPolyfillConfig config;
config.dot_4x8_packed = true;
Run(BuiltinPolyfill, config);
EXPECT_EQ(expect, str());
}
} // namespace
} // namespace tint::core::ir::transform