// Copyright 2022 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/transform/builtin_polyfill.h" #include #include "src/tint/transform/test_helper.h" namespace tint { namespace transform { namespace { using BuiltinPolyfillTest = TransformTest; TEST_F(BuiltinPolyfillTest, ShouldRunEmptyModule) { auto* src = R"()"; EXPECT_FALSE(ShouldRun(src)); } TEST_F(BuiltinPolyfillTest, EmptyModule) { auto* src = R"()"; auto* expect = src; auto got = Run(src); EXPECT_EQ(expect, str(got)); } //////////////////////////////////////////////////////////////////////////////// // countLeadingZeros //////////////////////////////////////////////////////////////////////////////// DataMap polyfillCountLeadingZeros() { BuiltinPolyfill::Builtins builtins; builtins.count_leading_zeros = true; DataMap data; data.Add(builtins); return data; } TEST_F(BuiltinPolyfillTest, ShouldRunCountLeadingZeros) { auto* src = R"( fn f() { countLeadingZeros(0xf); } )"; EXPECT_FALSE(ShouldRun(src)); EXPECT_TRUE(ShouldRun(src, polyfillCountLeadingZeros())); } TEST_F(BuiltinPolyfillTest, CountLeadingZeros_i32) { auto* src = R"( fn f() { let r : i32 = countLeadingZeros(15); } )"; auto* expect = R"( fn tint_count_leading_zeros(v : i32) -> i32 { var x = u32(v); let b16 = select(0u, 16u, (x <= 65535u)); x = (x << b16); let b8 = select(0u, 8u, (x <= 16777215u)); x = (x << b8); let b4 = select(0u, 4u, (x <= 268435455u)); x = (x << b4); let b2 = select(0u, 2u, (x <= 1073741823u)); x = (x << b2); let b1 = select(0u, 1u, (x <= 2147483647u)); let is_zero = select(0u, 1u, (x == 0u)); return i32((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : i32 = tint_count_leading_zeros(15); } )"; auto got = Run(src, polyfillCountLeadingZeros()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, CountLeadingZeros_u32) { auto* src = R"( fn f() { let r : u32 = countLeadingZeros(15u); } )"; auto* expect = R"( fn tint_count_leading_zeros(v : u32) -> u32 { var x = u32(v); let b16 = select(0u, 16u, (x <= 65535u)); x = (x << b16); let b8 = select(0u, 8u, (x <= 16777215u)); x = (x << b8); let b4 = select(0u, 4u, (x <= 268435455u)); x = (x << b4); let b2 = select(0u, 2u, (x <= 1073741823u)); x = (x << b2); let b1 = select(0u, 1u, (x <= 2147483647u)); let is_zero = select(0u, 1u, (x == 0u)); return u32((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : u32 = tint_count_leading_zeros(15u); } )"; auto got = Run(src, polyfillCountLeadingZeros()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, CountLeadingZeros_vec3_i32) { auto* src = R"( fn f() { let r : vec3 = countLeadingZeros(vec3(15)); } )"; auto* expect = R"( fn tint_count_leading_zeros(v : vec3) -> vec3 { var x = vec3(v); let b16 = select(vec3(0u), vec3(16u), (x <= vec3(65535u))); x = (x << b16); let b8 = select(vec3(0u), vec3(8u), (x <= vec3(16777215u))); x = (x << b8); let b4 = select(vec3(0u), vec3(4u), (x <= vec3(268435455u))); x = (x << b4); let b2 = select(vec3(0u), vec3(2u), (x <= vec3(1073741823u))); x = (x << b2); let b1 = select(vec3(0u), vec3(1u), (x <= vec3(2147483647u))); let is_zero = select(vec3(0u), vec3(1u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : vec3 = tint_count_leading_zeros(vec3(15)); } )"; auto got = Run(src, polyfillCountLeadingZeros()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, CountLeadingZeros_vec3_u32) { auto* src = R"( fn f() { let r : vec3 = countLeadingZeros(vec3(15u)); } )"; auto* expect = R"( fn tint_count_leading_zeros(v : vec3) -> vec3 { var x = vec3(v); let b16 = select(vec3(0u), vec3(16u), (x <= vec3(65535u))); x = (x << b16); let b8 = select(vec3(0u), vec3(8u), (x <= vec3(16777215u))); x = (x << b8); let b4 = select(vec3(0u), vec3(4u), (x <= vec3(268435455u))); x = (x << b4); let b2 = select(vec3(0u), vec3(2u), (x <= vec3(1073741823u))); x = (x << b2); let b1 = select(vec3(0u), vec3(1u), (x <= vec3(2147483647u))); let is_zero = select(vec3(0u), vec3(1u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : vec3 = tint_count_leading_zeros(vec3(15u)); } )"; auto got = Run(src, polyfillCountLeadingZeros()); EXPECT_EQ(expect, str(got)); } //////////////////////////////////////////////////////////////////////////////// // countTrailingZeros //////////////////////////////////////////////////////////////////////////////// DataMap polyfillCountTrailingZeros() { BuiltinPolyfill::Builtins builtins; builtins.count_trailing_zeros = true; DataMap data; data.Add(builtins); return data; } TEST_F(BuiltinPolyfillTest, ShouldRunCountTrailingZeros) { auto* src = R"( fn f() { countTrailingZeros(0xf); } )"; EXPECT_FALSE(ShouldRun(src)); EXPECT_TRUE(ShouldRun(src, polyfillCountTrailingZeros())); } TEST_F(BuiltinPolyfillTest, CountTrailingZeros_i32) { auto* src = R"( fn f() { let r : i32 = countTrailingZeros(15); } )"; auto* expect = R"( fn tint_count_trailing_zeros(v : i32) -> i32 { var x = u32(v); let b16 = select(16u, 0u, bool((x & 65535u))); x = (x >> b16); let b8 = select(8u, 0u, bool((x & 255u))); x = (x >> b8); let b4 = select(4u, 0u, bool((x & 15u))); x = (x >> b4); let b2 = select(2u, 0u, bool((x & 3u))); x = (x >> b2); let b1 = select(1u, 0u, bool((x & 1u))); let is_zero = select(0u, 1u, (x == 0u)); return i32((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : i32 = tint_count_trailing_zeros(15); } )"; auto got = Run(src, polyfillCountTrailingZeros()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, CountTrailingZeros_u32) { auto* src = R"( fn f() { let r : u32 = countTrailingZeros(15u); } )"; auto* expect = R"( fn tint_count_trailing_zeros(v : u32) -> u32 { var x = u32(v); let b16 = select(16u, 0u, bool((x & 65535u))); x = (x >> b16); let b8 = select(8u, 0u, bool((x & 255u))); x = (x >> b8); let b4 = select(4u, 0u, bool((x & 15u))); x = (x >> b4); let b2 = select(2u, 0u, bool((x & 3u))); x = (x >> b2); let b1 = select(1u, 0u, bool((x & 1u))); let is_zero = select(0u, 1u, (x == 0u)); return u32((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : u32 = tint_count_trailing_zeros(15u); } )"; auto got = Run(src, polyfillCountTrailingZeros()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, CountTrailingZeros_vec3_i32) { auto* src = R"( fn f() { let r : vec3 = countTrailingZeros(vec3(15)); } )"; auto* expect = R"( fn tint_count_trailing_zeros(v : vec3) -> vec3 { var x = vec3(v); let b16 = select(vec3(16u), vec3(0u), vec3((x & vec3(65535u)))); x = (x >> b16); let b8 = select(vec3(8u), vec3(0u), vec3((x & vec3(255u)))); x = (x >> b8); let b4 = select(vec3(4u), vec3(0u), vec3((x & vec3(15u)))); x = (x >> b4); let b2 = select(vec3(2u), vec3(0u), vec3((x & vec3(3u)))); x = (x >> b2); let b1 = select(vec3(1u), vec3(0u), vec3((x & vec3(1u)))); let is_zero = select(vec3(0u), vec3(1u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : vec3 = tint_count_trailing_zeros(vec3(15)); } )"; auto got = Run(src, polyfillCountTrailingZeros()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, CountTrailingZeros_vec3_u32) { auto* src = R"( fn f() { let r : vec3 = countTrailingZeros(vec3(15u)); } )"; auto* expect = R"( fn tint_count_trailing_zeros(v : vec3) -> vec3 { var x = vec3(v); let b16 = select(vec3(16u), vec3(0u), vec3((x & vec3(65535u)))); x = (x >> b16); let b8 = select(vec3(8u), vec3(0u), vec3((x & vec3(255u)))); x = (x >> b8); let b4 = select(vec3(4u), vec3(0u), vec3((x & vec3(15u)))); x = (x >> b4); let b2 = select(vec3(2u), vec3(0u), vec3((x & vec3(3u)))); x = (x >> b2); let b1 = select(vec3(1u), vec3(0u), vec3((x & vec3(1u)))); let is_zero = select(vec3(0u), vec3(1u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) + is_zero)); } fn f() { let r : vec3 = tint_count_trailing_zeros(vec3(15u)); } )"; auto got = Run(src, polyfillCountTrailingZeros()); EXPECT_EQ(expect, str(got)); } //////////////////////////////////////////////////////////////////////////////// // firstLeadingBit //////////////////////////////////////////////////////////////////////////////// DataMap polyfillFirstLeadingBit() { BuiltinPolyfill::Builtins builtins; builtins.first_leading_bit = true; DataMap data; data.Add(builtins); return data; } TEST_F(BuiltinPolyfillTest, ShouldRunFirstLeadingBit) { auto* src = R"( fn f() { firstLeadingBit(0xf); } )"; EXPECT_FALSE(ShouldRun(src)); EXPECT_TRUE(ShouldRun(src, polyfillFirstLeadingBit())); } TEST_F(BuiltinPolyfillTest, FirstLeadingBit_i32) { auto* src = R"( fn f() { let r : i32 = firstLeadingBit(15); } )"; auto* expect = R"( fn tint_first_leading_bit(v : i32) -> i32 { var x = select(u32(v), u32(~(v)), (v < 0)); let b16 = select(0u, 16u, bool((x & 4294901760u))); x = (x >> b16); let b8 = select(0u, 8u, bool((x & 65280u))); x = (x >> b8); let b4 = select(0u, 4u, bool((x & 240u))); x = (x >> b4); let b2 = select(0u, 2u, bool((x & 12u))); x = (x >> b2); let b1 = select(0u, 1u, bool((x & 2u))); let is_zero = select(0u, 4294967295u, (x == 0u)); return i32((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : i32 = tint_first_leading_bit(15); } )"; auto got = Run(src, polyfillFirstLeadingBit()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, FirstLeadingBit_u32) { auto* src = R"( fn f() { let r : u32 = firstLeadingBit(15u); } )"; auto* expect = R"( fn tint_first_leading_bit(v : u32) -> u32 { var x = v; let b16 = select(0u, 16u, bool((x & 4294901760u))); x = (x >> b16); let b8 = select(0u, 8u, bool((x & 65280u))); x = (x >> b8); let b4 = select(0u, 4u, bool((x & 240u))); x = (x >> b4); let b2 = select(0u, 2u, bool((x & 12u))); x = (x >> b2); let b1 = select(0u, 1u, bool((x & 2u))); let is_zero = select(0u, 4294967295u, (x == 0u)); return u32((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : u32 = tint_first_leading_bit(15u); } )"; auto got = Run(src, polyfillFirstLeadingBit()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, FirstLeadingBit_vec3_i32) { auto* src = R"( fn f() { let r : vec3 = firstLeadingBit(vec3(15)); } )"; auto* expect = R"( fn tint_first_leading_bit(v : vec3) -> vec3 { var x = select(vec3(v), vec3(~(v)), (v < vec3(0))); let b16 = select(vec3(0u), vec3(16u), vec3((x & vec3(4294901760u)))); x = (x >> b16); let b8 = select(vec3(0u), vec3(8u), vec3((x & vec3(65280u)))); x = (x >> b8); let b4 = select(vec3(0u), vec3(4u), vec3((x & vec3(240u)))); x = (x >> b4); let b2 = select(vec3(0u), vec3(2u), vec3((x & vec3(12u)))); x = (x >> b2); let b1 = select(vec3(0u), vec3(1u), vec3((x & vec3(2u)))); let is_zero = select(vec3(0u), vec3(4294967295u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : vec3 = tint_first_leading_bit(vec3(15)); } )"; auto got = Run(src, polyfillFirstLeadingBit()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, FirstLeadingBit_vec3_u32) { auto* src = R"( fn f() { let r : vec3 = firstLeadingBit(vec3(15u)); } )"; auto* expect = R"( fn tint_first_leading_bit(v : vec3) -> vec3 { var x = v; let b16 = select(vec3(0u), vec3(16u), vec3((x & vec3(4294901760u)))); x = (x >> b16); let b8 = select(vec3(0u), vec3(8u), vec3((x & vec3(65280u)))); x = (x >> b8); let b4 = select(vec3(0u), vec3(4u), vec3((x & vec3(240u)))); x = (x >> b4); let b2 = select(vec3(0u), vec3(2u), vec3((x & vec3(12u)))); x = (x >> b2); let b1 = select(vec3(0u), vec3(1u), vec3((x & vec3(2u)))); let is_zero = select(vec3(0u), vec3(4294967295u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : vec3 = tint_first_leading_bit(vec3(15u)); } )"; auto got = Run(src, polyfillFirstLeadingBit()); EXPECT_EQ(expect, str(got)); } //////////////////////////////////////////////////////////////////////////////// // firstTrailingBit //////////////////////////////////////////////////////////////////////////////// DataMap polyfillFirstTrailingBit() { BuiltinPolyfill::Builtins builtins; builtins.first_trailing_bit = true; DataMap data; data.Add(builtins); return data; } TEST_F(BuiltinPolyfillTest, ShouldRunFirstTrailingBit) { auto* src = R"( fn f() { firstTrailingBit(0xf); } )"; EXPECT_FALSE(ShouldRun(src)); EXPECT_TRUE(ShouldRun(src, polyfillFirstTrailingBit())); } TEST_F(BuiltinPolyfillTest, FirstTrailingBit_i32) { auto* src = R"( fn f() { let r : i32 = firstTrailingBit(15); } )"; auto* expect = R"( fn tint_first_trailing_bit(v : i32) -> i32 { var x = u32(v); let b16 = select(16u, 0u, bool((x & 65535u))); x = (x >> b16); let b8 = select(8u, 0u, bool((x & 255u))); x = (x >> b8); let b4 = select(4u, 0u, bool((x & 15u))); x = (x >> b4); let b2 = select(2u, 0u, bool((x & 3u))); x = (x >> b2); let b1 = select(1u, 0u, bool((x & 1u))); let is_zero = select(0u, 4294967295u, (x == 0u)); return i32((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : i32 = tint_first_trailing_bit(15); } )"; auto got = Run(src, polyfillFirstTrailingBit()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, FirstTrailingBit_u32) { auto* src = R"( fn f() { let r : u32 = firstTrailingBit(15u); } )"; auto* expect = R"( fn tint_first_trailing_bit(v : u32) -> u32 { var x = u32(v); let b16 = select(16u, 0u, bool((x & 65535u))); x = (x >> b16); let b8 = select(8u, 0u, bool((x & 255u))); x = (x >> b8); let b4 = select(4u, 0u, bool((x & 15u))); x = (x >> b4); let b2 = select(2u, 0u, bool((x & 3u))); x = (x >> b2); let b1 = select(1u, 0u, bool((x & 1u))); let is_zero = select(0u, 4294967295u, (x == 0u)); return u32((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : u32 = tint_first_trailing_bit(15u); } )"; auto got = Run(src, polyfillFirstTrailingBit()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, FirstTrailingBit_vec3_i32) { auto* src = R"( fn f() { let r : vec3 = firstTrailingBit(vec3(15)); } )"; auto* expect = R"( fn tint_first_trailing_bit(v : vec3) -> vec3 { var x = vec3(v); let b16 = select(vec3(16u), vec3(0u), vec3((x & vec3(65535u)))); x = (x >> b16); let b8 = select(vec3(8u), vec3(0u), vec3((x & vec3(255u)))); x = (x >> b8); let b4 = select(vec3(4u), vec3(0u), vec3((x & vec3(15u)))); x = (x >> b4); let b2 = select(vec3(2u), vec3(0u), vec3((x & vec3(3u)))); x = (x >> b2); let b1 = select(vec3(1u), vec3(0u), vec3((x & vec3(1u)))); let is_zero = select(vec3(0u), vec3(4294967295u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : vec3 = tint_first_trailing_bit(vec3(15)); } )"; auto got = Run(src, polyfillFirstTrailingBit()); EXPECT_EQ(expect, str(got)); } TEST_F(BuiltinPolyfillTest, FirstTrailingBit_vec3_u32) { auto* src = R"( fn f() { let r : vec3 = firstTrailingBit(vec3(15u)); } )"; auto* expect = R"( fn tint_first_trailing_bit(v : vec3) -> vec3 { var x = vec3(v); let b16 = select(vec3(16u), vec3(0u), vec3((x & vec3(65535u)))); x = (x >> b16); let b8 = select(vec3(8u), vec3(0u), vec3((x & vec3(255u)))); x = (x >> b8); let b4 = select(vec3(4u), vec3(0u), vec3((x & vec3(15u)))); x = (x >> b4); let b2 = select(vec3(2u), vec3(0u), vec3((x & vec3(3u)))); x = (x >> b2); let b1 = select(vec3(1u), vec3(0u), vec3((x & vec3(1u)))); let is_zero = select(vec3(0u), vec3(4294967295u), (x == vec3(0u))); return vec3((((((b16 | b8) | b4) | b2) | b1) | is_zero)); } fn f() { let r : vec3 = tint_first_trailing_bit(vec3(15u)); } )"; auto got = Run(src, polyfillFirstTrailingBit()); EXPECT_EQ(expect, str(got)); } } // namespace } // namespace transform } // namespace tint