// 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/simplify_pointers.h" #include "src/transform/test_helper.h" #include "src/transform/unshadow.h" namespace tint { namespace transform { namespace { using SimplifyPointersTest = TransformTest; TEST_F(SimplifyPointersTest, Error_MissingSimplifyPointers) { auto* src = ""; auto* expect = "error: tint::transform::SimplifyPointers depends on " "tint::transform::Unshadow but the dependency was not run"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(SimplifyPointersTest, EmptyModule) { auto* src = ""; auto* expect = ""; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(SimplifyPointersTest, FoldPointer) { 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(SimplifyPointersTest, AddressOfDeref) { auto* src = R"( fn f() { var v : i32; let p : ptr = &(v); let x : ptr = &(*(p)); let y : ptr = &(*(&(*(p)))); let z : ptr = &(*(&(*(&(*(&(*(p)))))))); var a = *x; var b = *y; var c = *z; } )"; auto* expect = R"( fn f() { var v : i32; var a = v; var b = v; var c = v; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(SimplifyPointersTest, DerefAddressOf) { auto* src = R"( fn f() { var v : i32; let x : i32 = *(&(v)); let y : i32 = *(&(*(&(v)))); let z : i32 = *(&(*(&(*(&(*(&(v)))))))); } )"; auto* expect = R"( fn f() { var v : i32; let x : i32 = v; let y : i32 = v; let z : i32 = v; } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(SimplifyPointersTest, 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(SimplifyPointersTest, 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(SimplifyPointersTest, 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(SimplifyPointersTest, 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(SimplifyPointersTest, ForLoopInit) { auto* src = R"( fn foo() -> i32 { return 1; } @stage(fragment) fn main() { var arr = array(); for (let a = &arr[foo()]; ;) { let x = *a; break; } } )"; auto* expect = R"( fn foo() -> i32 { return 1; } @stage(fragment) fn main() { var arr = array(); let a_save = foo(); for(; ; ) { let x = arr[a_save]; break; } } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } TEST_F(SimplifyPointersTest, 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)); } TEST_F(SimplifyPointersTest, ShadowPointer) { auto* src = R"( var a : array; @stage(compute) @workgroup_size(1) fn main() { let x = &a; var a : i32 = (*x)[0]; { var a : i32 = (*x)[1]; } } )"; auto* expect = R"( var a : array; @stage(compute) @workgroup_size(1) fn main() { var a_1 : i32 = a[0]; { var a_2 : i32 = a[1]; } } )"; auto got = Run(src); EXPECT_EQ(expect, str(got)); } } // namespace } // namespace transform } // namespace tint