// Copyright 2021 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/transform/inline_pointer_lets.h" #include #include #include #include "src/transform/test_helper.h" namespace tint { namespace transform { namespace { using InlinePointerLetsTest = TransformTest; TEST_F(InlinePointerLetsTest, EmptyModule) { auto* src = ""; auto* expect = ""; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(InlinePointerLetsTest, Basic) { auto* src = R"( fn f() { var v : i32; let p : ptr = &v; let x : i32 = *p; } )"; auto* expect = R"( fn f() { var v : i32; let x : i32 = *(&(v)); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(InlinePointerLetsTest, ComplexChain) { auto* src = R"( fn f() { var a : array, 4>; let ap : ptr, 4>> = &a; let mp : ptr> = &(*ap)[3]; let vp : ptr> = &(*mp)[2]; let v : vec4 = *vp; } )"; auto* expect = R"( fn f() { var a : array, 4>; let v : vec4 = *(&((*(&((*(&(a)))[3])))[2])); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(InlinePointerLetsTest, SavedVars) { auto* src = R"( struct S { i : i32; }; fn arr() { var a : array; var i : i32 = 0; var j : i32 = 0; let p : ptr = &a[i + j].i; i = 2; *p = 4; } fn matrix() { var m : mat3x3; var i : i32 = 0; var j : i32 = 0; let p : ptr> = &m[i + j]; i = 2; *p = vec3(4.0, 5.0, 6.0); } )"; auto* expect = R"( struct S { i : i32; }; fn arr() { var a : array; var i : i32 = 0; var j : i32 = 0; let p_save = (i + j); i = 2; *(&(a[p_save].i)) = 4; } fn matrix() { var m : mat3x3; var i : i32 = 0; var j : i32 = 0; let p_save_1 = (i + j); i = 2; *(&(m[p_save_1])) = vec3(4.0, 5.0, 6.0); } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(InlinePointerLetsTest, DontSaveLiterals) { auto* src = R"( fn f() { var arr : array; let p1 : ptr = &arr[1]; *p1 = 4; } )"; auto* expect = R"( fn f() { var arr : array; *(&(arr[1])) = 4; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(InlinePointerLetsTest, SavedVarsChain) { auto* src = R"( fn f() { var arr : array, 2>; let i : i32 = 0; let j : i32 = 1; let p : ptr> = &arr[i]; let q : ptr = &(*p)[j]; *q = 12; } )"; auto* expect = R"( fn f() { var arr : array, 2>; let i : i32 = 0; let j : i32 = 1; let p_save = i; let q_save = j; *(&((*(&(arr[p_save])))[q_save])) = 12; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(InlinePointerLetsTest, MultiSavedVarsInSinglePtrLetExpr) { auto* src = R"( fn x() -> i32 { return 1; } fn y() -> i32 { return 1; } fn z() -> i32 { return 1; } struct Inner { a : array; }; struct Outer { a : array; }; fn f() { var arr : array; let p : ptr = &arr[x()].a[y()].a[z()]; *p = 1; *p = 2; } )"; auto* expect = R"( fn x() -> i32 { return 1; } fn y() -> i32 { return 1; } fn z() -> i32 { return 1; } struct Inner { a : array; }; struct Outer { a : array; }; fn f() { var arr : array; let p_save = x(); let p_save_1 = y(); let p_save_2 = z(); *(&(arr[p_save].a[p_save_1].a[p_save_2])) = 1; *(&(arr[p_save].a[p_save_1].a[p_save_2])) = 2; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } // TODO(crbug.com/tint/819): Enable when we support inter-scope shadowing. TEST_F(InlinePointerLetsTest, DISABLED_ModificationAfterInline) { auto* src = R"( fn x(p : ptr) -> i32 { return *p; } fn f() { var i : i32 = 1; let p : ptr = &i; if (true) { var i : i32 = 2; x(p); } } )"; auto* expect = R"()"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } } // namespace } // namespace transform } // namespace tint