1 // Copyright (c) 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <string> 16 17 #include "gmock/gmock.h" 18 #include "source/opt/build_module.h" 19 #include "source/opt/value_number_table.h" 20 #include "test/opt/assembly_builder.h" 21 #include "test/opt/pass_fixture.h" 22 #include "test/opt/pass_utils.h" 23 24 namespace spvtools { 25 namespace opt { 26 namespace { 27 28 using ::testing::HasSubstr; 29 using ::testing::MatchesRegex; 30 using PrivateToLocalTest = PassTest<::testing::Test>; 31 32 TEST_F(PrivateToLocalTest, ChangeToLocal) { 33 // Change the private variable to a local, and change the types accordingly. 34 const std::string text = R"( 35 OpCapability Shader 36 %1 = OpExtInstImport "GLSL.std.450" 37 OpMemoryModel Logical GLSL450 38 OpEntryPoint Fragment %2 "main" 39 OpExecutionMode %2 OriginUpperLeft 40 OpSource GLSL 430 41 %3 = OpTypeVoid 42 %4 = OpTypeFunction %3 43 ; CHECK: [[float:%[a-zA-Z_\d]+]] = OpTypeFloat 32 44 %5 = OpTypeFloat 32 45 ; CHECK: [[newtype:%[a-zA-Z_\d]+]] = OpTypePointer Function [[float]] 46 %6 = OpTypePointer Private %5 47 ; CHECK-NOT: OpVariable [[.+]] Private 48 %8 = OpVariable %6 Private 49 ; CHECK: OpFunction 50 %2 = OpFunction %3 None %4 51 ; CHECK: OpLabel 52 %7 = OpLabel 53 ; CHECK-NEXT: [[newvar:%[a-zA-Z_\d]+]] = OpVariable [[newtype]] Function 54 ; CHECK: OpLoad [[float]] [[newvar]] 55 %9 = OpLoad %5 %8 56 OpReturn 57 OpFunctionEnd 58 )"; 59 SinglePassRunAndMatch<PrivateToLocalPass>(text, false); 60 } 61 62 TEST_F(PrivateToLocalTest, ReuseExistingType) { 63 // Change the private variable to a local, and change the types accordingly. 64 const std::string text = R"( 65 OpCapability Shader 66 %1 = OpExtInstImport "GLSL.std.450" 67 OpMemoryModel Logical GLSL450 68 OpEntryPoint Fragment %2 "main" 69 OpExecutionMode %2 OriginUpperLeft 70 OpSource GLSL 430 71 %3 = OpTypeVoid 72 %4 = OpTypeFunction %3 73 ; CHECK: [[float:%[a-zA-Z_\d]+]] = OpTypeFloat 32 74 %5 = OpTypeFloat 32 75 %func_ptr = OpTypePointer Function %5 76 ; CHECK: [[newtype:%[a-zA-Z_\d]+]] = OpTypePointer Function [[float]] 77 ; CHECK-NOT: [[%[a-zA-Z_\d]+]] = OpTypePointer Function [[float]] 78 %6 = OpTypePointer Private %5 79 ; CHECK-NOT: OpVariable [[.+]] Private 80 %8 = OpVariable %6 Private 81 ; CHECK: OpFunction 82 %2 = OpFunction %3 None %4 83 ; CHECK: OpLabel 84 %7 = OpLabel 85 ; CHECK-NEXT: [[newvar:%[a-zA-Z_\d]+]] = OpVariable [[newtype]] Function 86 ; CHECK: OpLoad [[float]] [[newvar]] 87 %9 = OpLoad %5 %8 88 OpReturn 89 OpFunctionEnd 90 )"; 91 SinglePassRunAndMatch<PrivateToLocalPass>(text, false); 92 } 93 94 TEST_F(PrivateToLocalTest, UpdateAccessChain) { 95 // Change the private variable to a local, and change the AccessChain. 96 const std::string text = R"( 97 OpCapability Shader 98 %1 = OpExtInstImport "GLSL.std.450" 99 OpMemoryModel Logical GLSL450 100 OpEntryPoint Fragment %2 "main" 101 OpExecutionMode %2 OriginUpperLeft 102 OpSource GLSL 430 103 %uint = OpTypeInt 32 0 104 %uint_0 = OpConstant %uint 0 105 %void = OpTypeVoid 106 %6 = OpTypeFunction %void 107 ; CHECK: [[float:%[a-zA-Z_\d]+]] = OpTypeFloat 108 %float = OpTypeFloat 32 109 ; CHECK: [[struct:%[a-zA-Z_\d]+]] = OpTypeStruct 110 %_struct_8 = OpTypeStruct %float 111 %_ptr_Private_float = OpTypePointer Private %float 112 ; CHECK: [[new_struct_type:%[a-zA-Z_\d]+]] = OpTypePointer Function [[struct]] 113 ; CHECK: [[new_float_type:%[a-zA-Z_\d]+]] = OpTypePointer Function [[float]] 114 %_ptr_Private__struct_8 = OpTypePointer Private %_struct_8 115 ; CHECK-NOT: OpVariable [[.+]] Private 116 %11 = OpVariable %_ptr_Private__struct_8 Private 117 ; CHECK: OpFunction 118 %2 = OpFunction %void None %6 119 ; CHECK: OpLabel 120 %12 = OpLabel 121 ; CHECK-NEXT: [[newvar:%[a-zA-Z_\d]+]] = OpVariable [[new_struct_type]] Function 122 ; CHECK: [[member:%[a-zA-Z_\d]+]] = OpAccessChain [[new_float_type]] [[newvar]] 123 %13 = OpAccessChain %_ptr_Private_float %11 %uint_0 124 ; CHECK: OpLoad [[float]] [[member]] 125 %14 = OpLoad %float %13 126 OpReturn 127 OpFunctionEnd 128 )"; 129 SinglePassRunAndMatch<PrivateToLocalPass>(text, false); 130 } 131 132 TEST_F(PrivateToLocalTest, UseTexelPointer) { 133 // Change the private variable to a local, and change the OpImageTexelPointer. 134 const std::string text = R"( 135 OpCapability SampledBuffer 136 OpCapability StorageImageExtendedFormats 137 OpCapability ImageBuffer 138 OpCapability Shader 139 %1 = OpExtInstImport "GLSL.std.450" 140 OpMemoryModel Logical GLSL450 141 OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID 142 OpExecutionMode %2 LocalSize 64 1 1 143 OpSource HLSL 600 144 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId 145 OpDecorate %4 DescriptorSet 4 146 OpDecorate %4 Binding 70 147 %uint = OpTypeInt 32 0 148 %6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui 149 %_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6 150 %_ptr_Private_6 = OpTypePointer Private %6 151 %void = OpTypeVoid 152 %10 = OpTypeFunction %void 153 %uint_0 = OpConstant %uint 0 154 %uint_1 = OpConstant %uint 1 155 %v3uint = OpTypeVector %uint 3 156 %_ptr_Input_v3uint = OpTypePointer Input %v3uint 157 %_ptr_Image_uint = OpTypePointer Image %uint 158 %4 = OpVariable %_ptr_UniformConstant_6 UniformConstant 159 %16 = OpVariable %_ptr_Private_6 Private 160 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input 161 %2 = OpFunction %void None %10 162 %17 = OpLabel 163 ; Make sure the variable was moved. 164 ; CHECK: OpFunction 165 ; CHECK-NEXT: OpLabel 166 ; CHECK-NEXT: OpVariable %_ptr_Function_6 Function 167 %18 = OpLoad %6 %4 168 OpStore %16 %18 169 %19 = OpImageTexelPointer %_ptr_Image_uint %16 %uint_0 %uint_0 170 %20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1 171 OpReturn 172 OpFunctionEnd 173 )"; 174 SinglePassRunAndMatch<PrivateToLocalPass>(text, false); 175 } 176 177 TEST_F(PrivateToLocalTest, UsedInTwoFunctions) { 178 // Should not change because it is used in multiple functions. 179 const std::string text = R"( 180 OpCapability Shader 181 %1 = OpExtInstImport "GLSL.std.450" 182 OpMemoryModel Logical GLSL450 183 OpEntryPoint Fragment %2 "main" 184 OpExecutionMode %2 OriginUpperLeft 185 OpSource GLSL 430 186 %3 = OpTypeVoid 187 %4 = OpTypeFunction %3 188 %5 = OpTypeFloat 32 189 %6 = OpTypePointer Private %5 190 %8 = OpVariable %6 Private 191 %2 = OpFunction %3 None %4 192 %7 = OpLabel 193 %9 = OpLoad %5 %8 194 OpReturn 195 OpFunctionEnd 196 %10 = OpFunction %3 None %4 197 %11 = OpLabel 198 %12 = OpLoad %5 %8 199 OpReturn 200 OpFunctionEnd 201 )"; 202 auto result = SinglePassRunAndDisassemble<StrengthReductionPass>( 203 text, /* skip_nop = */ true, /* do_validation = */ false); 204 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 205 } 206 207 TEST_F(PrivateToLocalTest, UsedInFunctionCall) { 208 // Should not change because it is used in a function call. Changing the 209 // signature of the function would require cloning the function, which is not 210 // worth it. 211 const std::string text = R"( 212 OpCapability Shader 213 %1 = OpExtInstImport "GLSL.std.450" 214 OpMemoryModel Logical GLSL450 215 OpEntryPoint Fragment %2 "main" 216 OpExecutionMode %2 OriginUpperLeft 217 OpSource GLSL 430 218 %void = OpTypeVoid 219 %4 = OpTypeFunction %void 220 %float = OpTypeFloat 32 221 %_ptr_Private_float = OpTypePointer Private %float 222 %7 = OpTypeFunction %void %_ptr_Private_float 223 %8 = OpVariable %_ptr_Private_float Private 224 %2 = OpFunction %void None %4 225 %9 = OpLabel 226 %10 = OpFunctionCall %void %11 %8 227 OpReturn 228 OpFunctionEnd 229 %11 = OpFunction %void None %7 230 %12 = OpFunctionParameter %_ptr_Private_float 231 %13 = OpLabel 232 %14 = OpLoad %float %12 233 OpReturn 234 OpFunctionEnd 235 )"; 236 auto result = SinglePassRunAndDisassemble<StrengthReductionPass>( 237 text, /* skip_nop = */ true, /* do_validation = */ false); 238 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 239 } 240 241 TEST_F(PrivateToLocalTest, CreatePointerToAmbiguousStruct1) { 242 // Test that the correct pointer type is picked up. 243 const std::string text = R"( 244 ; CHECK: [[struct1:%[a-zA-Z_\d]+]] = OpTypeStruct 245 ; CHECK: [[struct2:%[a-zA-Z_\d]+]] = OpTypeStruct 246 ; CHECK: [[priv_ptr:%[\w]+]] = OpTypePointer Private [[struct1]] 247 ; CHECK: [[fuct_ptr2:%[\w]+]] = OpTypePointer Function [[struct2]] 248 ; CHECK: [[fuct_ptr1:%[\w]+]] = OpTypePointer Function [[struct1]] 249 ; CHECK: OpFunction 250 ; CHECK: OpLabel 251 ; CHECK-NEXT: [[newvar:%[a-zA-Z_\d]+]] = OpVariable [[fuct_ptr1]] Function 252 ; CHECK: OpLoad [[struct1]] [[newvar]] 253 OpCapability Shader 254 %1 = OpExtInstImport "GLSL.std.450" 255 OpMemoryModel Logical GLSL450 256 OpEntryPoint Fragment %2 "main" 257 OpExecutionMode %2 OriginUpperLeft 258 OpSource GLSL 430 259 %3 = OpTypeVoid 260 %4 = OpTypeFunction %3 261 %5 = OpTypeFloat 32 262 %struct1 = OpTypeStruct %5 263 %struct2 = OpTypeStruct %5 264 %6 = OpTypePointer Private %struct1 265 %func_ptr2 = OpTypePointer Function %struct2 266 %8 = OpVariable %6 Private 267 %2 = OpFunction %3 None %4 268 %7 = OpLabel 269 %9 = OpLoad %struct1 %8 270 OpReturn 271 OpFunctionEnd 272 )"; 273 SinglePassRunAndMatch<PrivateToLocalPass>(text, false); 274 } 275 276 TEST_F(PrivateToLocalTest, CreatePointerToAmbiguousStruct2) { 277 // Test that the correct pointer type is picked up. 278 const std::string text = R"( 279 ; CHECK: [[struct1:%[a-zA-Z_\d]+]] = OpTypeStruct 280 ; CHECK: [[struct2:%[a-zA-Z_\d]+]] = OpTypeStruct 281 ; CHECK: [[priv_ptr:%[\w]+]] = OpTypePointer Private [[struct2]] 282 ; CHECK: [[fuct_ptr1:%[\w]+]] = OpTypePointer Function [[struct1]] 283 ; CHECK: [[fuct_ptr2:%[\w]+]] = OpTypePointer Function [[struct2]] 284 ; CHECK: OpFunction 285 ; CHECK: OpLabel 286 ; CHECK-NEXT: [[newvar:%[a-zA-Z_\d]+]] = OpVariable [[fuct_ptr2]] Function 287 ; CHECK: OpLoad [[struct2]] [[newvar]] 288 OpCapability Shader 289 %1 = OpExtInstImport "GLSL.std.450" 290 OpMemoryModel Logical GLSL450 291 OpEntryPoint Fragment %2 "main" 292 OpExecutionMode %2 OriginUpperLeft 293 OpSource GLSL 430 294 %3 = OpTypeVoid 295 %4 = OpTypeFunction %3 296 %5 = OpTypeFloat 32 297 %struct1 = OpTypeStruct %5 298 %struct2 = OpTypeStruct %5 299 %6 = OpTypePointer Private %struct2 300 %func_ptr2 = OpTypePointer Function %struct1 301 %8 = OpVariable %6 Private 302 %2 = OpFunction %3 None %4 303 %7 = OpLabel 304 %9 = OpLoad %struct2 %8 305 OpReturn 306 OpFunctionEnd 307 )"; 308 SinglePassRunAndMatch<PrivateToLocalPass>(text, false); 309 } 310 311 } // namespace 312 } // namespace opt 313 } // namespace spvtools 314