1 // Copyright (c) 2019-2022 Valve Corporation 2 // Copyright (c) 2019-2022 LunarG Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 // Bindless Check Instrumentation Tests. 17 // Tests ending with V2 use version 2 record format. 18 19 #include <string> 20 #include <vector> 21 22 #include "test/opt/pass_fixture.h" 23 #include "test/opt/pass_utils.h" 24 25 namespace spvtools { 26 namespace opt { 27 namespace { 28 29 static const std::string kFuncName = "inst_buff_addr_search_and_test"; 30 static const std::string kImportDeco = R"( 31 ;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" + 32 kFuncName + R"(" Import 33 )"; 34 static const std::string kImportStub = R"( 35 ;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}} 36 ;CHECK: OpFunctionEnd 37 )"; 38 // clang-format on 39 40 using InstBuffAddrTest = PassTest<::testing::Test>; 41 42 TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferStore) { 43 // #version 450 44 // #extension GL_EXT_buffer_reference : enable 45 // 46 // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; 47 // 48 // layout(set = 0, binding = 0) uniform ufoo { 49 // bufStruct data; 50 // uint offset; 51 // } u_info; 52 // 53 // layout(buffer_reference, std140) buffer bufStruct { 54 // layout(offset = 0) int a[2]; 55 // layout(offset = 32) int b; 56 // }; 57 // 58 // void main() { 59 // u_info.data.b = 0xca7; 60 // } 61 62 const std::string defs = R"( 63 OpCapability Shader 64 OpCapability PhysicalStorageBufferAddresses 65 ;CHECK: OpCapability Int64 66 OpExtension "SPV_EXT_physical_storage_buffer" 67 ;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" 68 %1 = OpExtInstImport "GLSL.std.450" 69 OpMemoryModel PhysicalStorageBuffer64 GLSL450 70 OpEntryPoint GLCompute %main "main" 71 ;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID 72 OpExecutionMode %main LocalSize 1 1 1 73 OpSource GLSL 450 74 OpSourceExtension "GL_EXT_buffer_reference" 75 OpName %main "main" 76 OpName %ufoo "ufoo" 77 OpMemberName %ufoo 0 "data" 78 OpMemberName %ufoo 1 "offset" 79 OpName %bufStruct "bufStruct" 80 OpMemberName %bufStruct 0 "a" 81 OpMemberName %bufStruct 1 "b" 82 OpName %u_info "u_info" 83 )"; 84 85 // clang-format off 86 const std::string decorates = R"( 87 OpMemberDecorate %ufoo 0 Offset 0 88 OpMemberDecorate %ufoo 1 Offset 8 89 OpDecorate %ufoo Block 90 OpDecorate %_arr_int_uint_2 ArrayStride 16 91 OpMemberDecorate %bufStruct 0 Offset 0 92 OpMemberDecorate %bufStruct 1 Offset 32 93 OpDecorate %bufStruct Block 94 OpDecorate %u_info DescriptorSet 0 95 OpDecorate %u_info Binding 0 96 )" + kImportDeco + R"( 97 ;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId 98 )"; 99 100 const std::string globals = R"( 101 %void = OpTypeVoid 102 %3 = OpTypeFunction %void 103 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer 104 %uint = OpTypeInt 32 0 105 %ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint 106 %int = OpTypeInt 32 1 107 %uint_2 = OpConstant %uint 2 108 %_arr_int_uint_2 = OpTypeArray %int %uint_2 109 %bufStruct = OpTypeStruct %_arr_int_uint_2 %int 110 %_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct 111 %_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo 112 %u_info = OpVariable %_ptr_Uniform_ufoo Uniform 113 %int_0 = OpConstant %int 0 114 %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct 115 %int_1 = OpConstant %int 1 116 %int_3239 = OpConstant %int 3239 117 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int 118 ;CHECK: %ulong = OpTypeInt 64 0 119 ;CHECK: %bool = OpTypeBool 120 ;CHECK: %v3uint = OpTypeVector %uint 3 121 ;CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint 122 ;CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input 123 )"; 124 // clang-format off 125 126 const std::string main_func = R"( 127 %main = OpFunction %void None %3 128 %5 = OpLabel 129 %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 130 %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 131 %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 132 ;CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 133 ;CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 134 ;CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 135 ;CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 136 ;CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20 137 ;CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1 138 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %22 139 ;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID 140 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 141 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 142 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 143 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} 144 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} {{%\w+}} %uint_4 145 ;CHECK: OpSelectionMerge {{%\w+}} None 146 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} 147 ;CHECK: {{%\w+}} = OpLabel 148 OpStore %22 %int_3239 Aligned 16 149 ;CHECK: OpStore %22 %int_3239 Aligned 16 150 ;CHECK: OpBranch {{%\w+}} 151 ;CHECK: {{%\w+}} = OpLabel 152 ;CHECK: OpBranch {{%\w+}} 153 ;CHECK: {{%\w+}} = OpLabel 154 OpReturn 155 OpFunctionEnd 156 )"; 157 158 // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 159 SinglePassRunAndMatch<InstBuffAddrCheckPass>( 160 defs + decorates + globals + kImportStub + main_func, true, 23u); 161 } 162 163 TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) { 164 // #version 450 165 // #extension GL_EXT_buffer_reference : enable 166 167 // // forward reference 168 // layout(buffer_reference) buffer blockType; 169 170 // layout(buffer_reference, std430, buffer_reference_align = 16) buffer 171 // blockType { 172 // int x; 173 // blockType next; 174 // }; 175 176 // layout(std430) buffer rootBlock { 177 // blockType root; 178 // } r; 179 180 // void main() 181 // { 182 // blockType b = r.root; 183 // b = b.next; 184 // b.x = 531; 185 // } 186 187 const std::string defs = R"( 188 OpCapability Shader 189 OpCapability PhysicalStorageBufferAddresses 190 ;CHECK: OpCapability Int64 191 OpExtension "SPV_EXT_physical_storage_buffer" 192 OpExtension "SPV_KHR_storage_buffer_storage_class" 193 %1 = OpExtInstImport "GLSL.std.450" 194 OpMemoryModel PhysicalStorageBuffer64 GLSL450 195 OpEntryPoint GLCompute %main "main" 196 OpExecutionMode %main LocalSize 1 1 1 197 OpSource GLSL 450 198 OpSourceExtension "GL_EXT_buffer_reference" 199 OpName %main "main" 200 ;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID 201 OpName %blockType "blockType" 202 OpMemberName %blockType 0 "x" 203 OpMemberName %blockType 1 "next" 204 OpName %rootBlock "rootBlock" 205 OpMemberName %rootBlock 0 "root" 206 OpName %r "r" 207 )"; 208 209 // clang-format off 210 const std::string decorates = R"( 211 OpMemberDecorate %blockType 0 Offset 0 212 OpMemberDecorate %blockType 1 Offset 8 213 OpDecorate %blockType Block 214 OpMemberDecorate %rootBlock 0 Offset 0 215 OpDecorate %rootBlock Block 216 OpDecorate %r DescriptorSet 0 217 OpDecorate %r Binding 0 218 )" + kImportDeco + R"( 219 ;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId 220 )"; 221 222 const std::string globals = R"( 223 %void = OpTypeVoid 224 %3 = OpTypeFunction %void 225 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer 226 %int = OpTypeInt 32 1 227 %blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType 228 %_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType 229 %rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType 230 %_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock 231 %r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer 232 %int_0 = OpConstant %int 0 233 %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType 234 %int_1 = OpConstant %int 1 235 %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType 236 %int_531 = OpConstant %int 531 237 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int 238 )"; 239 240 const std::string main_func = R"( 241 %main = OpFunction %void None %3 242 %5 = OpLabel 243 %16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0 244 %17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16 245 %21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1 246 %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 247 %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0 248 OpStore %26 %int_531 Aligned 16 249 ;CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 250 ;CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0 251 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %21 252 ;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID 253 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 254 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 255 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 256 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} 257 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_45 {{%\w+}} {{%\w+}} %uint_8 258 ;CHECK: OpSelectionMerge {{%\w+}} None 259 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} 260 ;CHECK: {{%\w+}} = OpLabel 261 ;CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 262 ;CHECK: OpBranch {{%\w+}} 263 ;CHECK: {{%\w+}} = OpLabel 264 ;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %52 265 ;CHECK: OpBranch {{%\w+}} 266 ;CHECK: {{%\w+}} = OpLabel 267 ;CHECK: {{%\w+}} = OpPhi %_ptr_PhysicalStorageBuffer_blockType {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} 268 ;CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int {{%\w+}} %int_0 269 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %26 270 ;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID 271 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 272 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 273 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 274 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} 275 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_47 {{%\w+}} {{%\w+}} %uint_4 276 ;CHECK: OpSelectionMerge {{%\w+}} None 277 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} 278 ;CHECK: {{%\w+}} = OpLabel 279 ;CHECK: OpStore %26 %int_531 Aligned 16 280 ;CHECK: OpBranch {{%\w+}} 281 ;CHECK: {{%\w+}} = OpLabel 282 ;CHECK: OpBranch {{%\w+}} 283 ;CHECK: {{%\w+}} = OpLabel 284 OpReturn 285 OpFunctionEnd 286 )"; 287 // clang-format on 288 289 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 290 SinglePassRunAndMatch<InstBuffAddrCheckPass>( 291 defs + decorates + globals + kImportStub + main_func, true, 23u); 292 } 293 294 TEST_F(InstBuffAddrTest, StructLoad) { 295 // #version 450 296 // #extension GL_EXT_buffer_reference : enable 297 // #extension GL_ARB_gpu_shader_int64 : enable 298 // struct Test { 299 // float a; 300 // }; 301 // 302 // layout(buffer_reference, std430, buffer_reference_align = 16) buffer 303 // TestBuffer { Test test; }; 304 // 305 // Test GetTest(uint64_t ptr) { 306 // return TestBuffer(ptr).test; 307 // } 308 // 309 // void main() { 310 // GetTest(0xe0000000); 311 // } 312 313 const std::string defs = 314 R"( 315 OpCapability Shader 316 OpCapability Int64 317 OpCapability PhysicalStorageBufferAddresses 318 ;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" 319 %1 = OpExtInstImport "GLSL.std.450" 320 OpMemoryModel PhysicalStorageBuffer64 GLSL450 321 OpEntryPoint Fragment %main "main" 322 ;CHECK: OpEntryPoint Fragment %main "main" %gl_FragCoord 323 OpExecutionMode %main OriginUpperLeft 324 OpSource GLSL 450 325 OpSourceExtension "GL_ARB_gpu_shader_int64" 326 OpSourceExtension "GL_EXT_buffer_reference" 327 OpName %main "main" 328 OpName %Test "Test" 329 OpMemberName %Test 0 "a" 330 OpName %Test_0 "Test" 331 OpMemberName %Test_0 0 "a" 332 OpName %TestBuffer "TestBuffer" 333 OpMemberName %TestBuffer 0 "test" 334 )"; 335 336 // clang-format off 337 const std::string decorates = R"( 338 OpMemberDecorate %Test_0 0 Offset 0 339 OpMemberDecorate %TestBuffer 0 Offset 0 340 OpDecorate %TestBuffer Block 341 )" + kImportDeco + R"( 342 ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord 343 )"; 344 345 const std::string globals = R"( 346 %void = OpTypeVoid 347 %3 = OpTypeFunction %void 348 %ulong = OpTypeInt 64 0 349 %float = OpTypeFloat 32 350 %Test = OpTypeStruct %float 351 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer 352 %Test_0 = OpTypeStruct %float 353 %TestBuffer = OpTypeStruct %Test_0 354 %_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer 355 %int = OpTypeInt 32 1 356 %int_0 = OpConstant %int 0 357 %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 358 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 359 ;CHECK: {{%\w+}} = OpConstantNull %Test_0 360 )"; 361 362 const std::string main_func = R"( 363 %main = OpFunction %void None %3 364 %5 = OpLabel 365 %37 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %ulong_18446744073172680704 366 %38 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %37 %int_0 367 %39 = OpLoad %Test_0 %38 Aligned 16 368 ;CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16 369 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %38 370 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord 371 ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} 372 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 373 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 374 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 375 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_38 {{%\w+}} {{%\w+}} %uint_4 376 ;CHECK: OpSelectionMerge {{%\w+}} None 377 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} 378 ;CHECK: {{%\w+}} = OpLabel 379 ;CHECK: {{%\w+}} = OpLoad %Test_0 %38 Aligned 16 380 ;CHECK: OpBranch {{%\w+}} 381 ;CHECK: {{%\w+}} = OpLabel 382 ;CHECK: OpBranch {{%\w+}} 383 ;CHECK: {{%\w+}} = OpLabel 384 ;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} 385 %40 = OpCopyLogical %Test %39 386 ;CHECK-NOT: %40 = OpCopyLogical %Test %39 387 ;CHECK: %40 = OpCopyLogical %Test [[phi_result]] 388 OpReturn 389 OpFunctionEnd 390 )"; 391 // clang-format on 392 393 SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); 394 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 395 SinglePassRunAndMatch<InstBuffAddrCheckPass>( 396 defs + decorates + globals + kImportStub + main_func, true); 397 } 398 399 TEST_F(InstBuffAddrTest, PaddedStructLoad) { 400 // #version 450 401 // #extension GL_EXT_buffer_reference : enable 402 // #extension GL_ARB_gpu_shader_int64 : enable 403 // struct Test { 404 // uvec3 pad_1; // Offset 0 Size 12 405 // double pad_2; // Offset 16 Size 8 (alignment requirement) 406 // float a; // Offset 24 Size 4 407 // }; // Total Size 28 408 // 409 // layout(buffer_reference, std430, buffer_reference_align = 16) buffer 410 // TestBuffer { Test test; }; 411 // 412 // Test GetTest(uint64_t ptr) { 413 // return TestBuffer(ptr).test; 414 // } 415 // 416 // void main() { 417 // GetTest(0xe0000000); 418 // } 419 420 const std::string defs = 421 R"( 422 OpCapability Shader 423 OpCapability Float64 424 OpCapability Int64 425 OpCapability PhysicalStorageBufferAddresses 426 %1 = OpExtInstImport "GLSL.std.450" 427 OpMemoryModel PhysicalStorageBuffer64 GLSL450 428 OpEntryPoint Vertex %main "main" 429 OpSource GLSL 450 430 OpSourceExtension "GL_ARB_gpu_shader_int64" 431 OpSourceExtension "GL_EXT_buffer_reference" 432 OpName %main "main" 433 OpName %Test "Test" 434 OpMemberName %Test 0 "pad_1" 435 OpMemberName %Test 1 "pad_2" 436 OpMemberName %Test 2 "a" 437 OpName %GetTest_u641_ "GetTest(u641;" 438 OpName %ptr "ptr" 439 OpName %Test_0 "Test" 440 OpMemberName %Test_0 0 "pad_1" 441 OpMemberName %Test_0 1 "pad_2" 442 OpMemberName %Test_0 2 "a" 443 OpName %TestBuffer "TestBuffer" 444 OpMemberName %TestBuffer 0 "test" 445 OpName %param "param" 446 )"; 447 448 // clang-format off 449 const std::string decorates = R"( 450 OpDecorate %TestBuffer Block 451 OpMemberDecorate %Test_0 0 Offset 0 452 OpMemberDecorate %Test_0 1 Offset 16 453 OpMemberDecorate %Test_0 2 Offset 24 454 OpMemberDecorate %TestBuffer 0 Offset 0 455 )" + kImportDeco + R"( 456 ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex 457 ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex 458 )"; 459 460 const std::string globals = R"( 461 %void = OpTypeVoid 462 %3 = OpTypeFunction %void 463 %ulong = OpTypeInt 64 0 464 %_ptr_Function_ulong = OpTypePointer Function %ulong 465 %uint = OpTypeInt 32 0 466 %v3uint = OpTypeVector %uint 3 467 %double = OpTypeFloat 64 468 %float = OpTypeFloat 32 469 %Test = OpTypeStruct %v3uint %double %float 470 %13 = OpTypeFunction %Test %_ptr_Function_ulong 471 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer 472 %Test_0 = OpTypeStruct %v3uint %double %float 473 %TestBuffer = OpTypeStruct %Test_0 474 %_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer 475 %int = OpTypeInt 32 1 476 %int_0 = OpConstant %int 0 477 %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 478 %_ptr_Function_Test = OpTypePointer Function %Test 479 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 480 ;CHECK: {{%\w+}} = OpConstantNull %Test_0 481 )"; 482 483 const std::string main_func = R"( 484 %main = OpFunction %void None %3 485 %5 = OpLabel 486 %param = OpVariable %_ptr_Function_ulong Function 487 OpStore %param %ulong_18446744073172680704 488 %35 = OpFunctionCall %Test %GetTest_u641_ %param 489 OpReturn 490 OpFunctionEnd 491 %GetTest_u641_ = OpFunction %Test None %13 492 %ptr = OpFunctionParameter %_ptr_Function_ulong 493 %16 = OpLabel 494 %28 = OpVariable %_ptr_Function_Test Function 495 %17 = OpLoad %ulong %ptr 496 %21 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %17 497 %25 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %21 %int_0 498 %26 = OpLoad %Test_0 %25 Aligned 16 499 %29 = OpCopyLogical %Test %26 500 ;CHECK-NOT: %30 = OpLoad %Test %28 501 ;CHECK-NOT: %26 = OpLoad %Test_0 %25 Aligned 16 502 ;CHECK-NOT: %29 = OpCopyLogical %Test %26 503 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %25 504 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex 505 ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex 506 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 507 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_28 508 ;CHECK: OpSelectionMerge {{%\w+}} None 509 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} 510 ;CHECK: {{%\w+}} = OpLabel 511 ;CHECK: {{%\w+}} = OpLoad %Test_0 %25 Aligned 16 512 ;CHECK: OpBranch {{%\w+}} 513 ;CHECK: {{%\w+}} = OpLabel 514 ;CHECK: OpBranch {{%\w+}} 515 ;CHECK: {{%\w+}} = OpLabel 516 ;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} 517 ;CHECK: %29 = OpCopyLogical %Test [[phi_result]] 518 OpStore %28 %29 519 %30 = OpLoad %Test %28 520 OpReturnValue %30 521 OpFunctionEnd 522 )"; 523 // clang-format on 524 525 SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); 526 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 527 SinglePassRunAndMatch<InstBuffAddrCheckPass>( 528 defs + decorates + globals + kImportStub + main_func, true); 529 } 530 531 TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) { 532 // #version 450 533 // #extension GL_EXT_buffer_reference : enable 534 // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; 535 // layout(set = 0, binding = 0) uniform ufoo { 536 // bufStruct data; 537 // int nWrites; 538 // } u_info; 539 // layout(buffer_reference, std140) buffer bufStruct { 540 // int a[4]; 541 // }; 542 // void main() { 543 // for (int i=0; i < u_info.nWrites; ++i) { 544 // u_info.data.a[i] = 0xdeadca71; 545 // } 546 // } 547 548 // clang-format off 549 const std::string text = R"( 550 OpCapability Shader 551 OpCapability PhysicalStorageBufferAddresses 552 %1 = OpExtInstImport "GLSL.std.450" 553 OpMemoryModel PhysicalStorageBuffer64 GLSL450 554 OpEntryPoint Vertex %main "main" %u_info 555 ;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex 556 OpSource GLSL 450 557 OpSourceExtension "GL_EXT_buffer_reference" 558 OpName %main "main" 559 OpName %i "i" 560 OpName %ufoo "ufoo" 561 OpMemberName %ufoo 0 "data" 562 OpMemberName %ufoo 1 "nWrites" 563 OpName %bufStruct "bufStruct" 564 OpMemberName %bufStruct 0 "a" 565 OpName %u_info "u_info" 566 OpMemberDecorate %ufoo 0 Offset 0 567 OpMemberDecorate %ufoo 1 Offset 8 568 OpDecorate %ufoo Block 569 OpDecorate %_arr_int_uint_4 ArrayStride 16 570 OpMemberDecorate %bufStruct 0 Offset 0 571 OpDecorate %bufStruct Block 572 OpDecorate %u_info DescriptorSet 0 573 OpDecorate %u_info Binding 0 574 )" + kImportDeco + R"( 575 %void = OpTypeVoid 576 %3 = OpTypeFunction %void 577 %int = OpTypeInt 32 1 578 %_ptr_Function_int = OpTypePointer Function %int 579 %int_0 = OpConstant %int 0 580 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer 581 %ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int 582 %uint = OpTypeInt 32 0 583 %uint_4 = OpConstant %uint 4 584 %_arr_int_uint_4 = OpTypeArray %int %uint_4 585 %bufStruct = OpTypeStruct %_arr_int_uint_4 586 %_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct 587 %_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo 588 %u_info = OpVariable %_ptr_Uniform_ufoo Uniform 589 %int_1 = OpConstant %int 1 590 %_ptr_Uniform_int = OpTypePointer Uniform %int 591 %bool = OpTypeBool 592 %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct 593 %int_n559035791 = OpConstant %int -559035791 594 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int 595 )" + kImportStub + R"( 596 %main = OpFunction %void None %3 597 %5 = OpLabel 598 %i = OpVariable %_ptr_Function_int Function 599 OpStore %i %int_0 600 OpBranch %10 601 %10 = OpLabel 602 OpLoopMerge %12 %13 None 603 OpBranch %14 604 %14 = OpLabel 605 %15 = OpLoad %int %i 606 %26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 607 %27 = OpLoad %int %26 608 %29 = OpSLessThan %bool %15 %27 609 OpBranchConditional %29 %11 %12 610 %11 = OpLabel 611 %31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 612 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 613 %33 = OpLoad %int %i 614 %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 615 OpStore %36 %int_n559035791 Aligned 16 616 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %36 617 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex 618 ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex 619 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 620 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_4 621 ;CHECK: OpSelectionMerge {{%\w+}} None 622 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} 623 ;CHECK: {{%\w+}} = OpLabel 624 ;CHECK: OpStore %36 %int_n559035791 Aligned 16 625 ;CHECK: OpBranch {{%\w+}} 626 ;CHECK: {{%\w+}} = OpLabel 627 ;CHECK: OpBranch {{%\w+}} 628 ;CHECK: {{%\w+}} = OpLabel 629 OpBranch %13 630 %13 = OpLabel 631 %37 = OpLoad %int %i 632 %38 = OpIAdd %int %37 %int_1 633 OpStore %i %38 634 OpBranch %10 635 %12 = OpLabel 636 OpReturn 637 OpFunctionEnd)"; 638 // clang-format on 639 640 SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); 641 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 642 SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 23); 643 } 644 645 TEST_F(InstBuffAddrTest, UVec3ScalarAddressOOB) { 646 // clang-format off 647 // #version 450 648 // #extension GL_EXT_buffer_reference : enable 649 // #extension GL_EXT_scalar_block_layout : enable 650 // layout(buffer_reference, std430, scalar) readonly buffer IndexBuffer 651 // { 652 // uvec3 indices[]; 653 // }; 654 // layout(set = 0, binding = 0) uniform ufoo { 655 // IndexBuffer data; 656 // int nReads; 657 // } u_info; 658 // void main() { 659 // uvec3 readvec; 660 // for (int i=0; i < u_info.nReads; ++i) { 661 // readvec = u_info.data.indices[i]; 662 // } 663 // } 664 const std::string text = R"( 665 OpCapability Shader 666 OpCapability PhysicalStorageBufferAddresses 667 %1 = OpExtInstImport "GLSL.std.450" 668 OpMemoryModel PhysicalStorageBuffer64 GLSL450 669 OpEntryPoint Vertex %main "main" %u_info 670 OpSource GLSL 450 671 OpSourceExtension "GL_EXT_buffer_reference" 672 OpSourceExtension "GL_EXT_scalar_block_layout" 673 OpName %main "main" 674 OpName %i "i" 675 OpName %ufoo "ufoo" 676 OpMemberName %ufoo 0 "data" 677 OpMemberName %ufoo 1 "nReads" 678 OpName %IndexBuffer "IndexBuffer" 679 OpMemberName %IndexBuffer 0 "indices" 680 OpName %u_info "u_info" 681 OpName %readvec "readvec" 682 OpMemberDecorate %ufoo 0 Offset 0 683 OpMemberDecorate %ufoo 1 Offset 8 684 OpDecorate %ufoo Block 685 OpDecorate %_runtimearr_v3uint ArrayStride 12 686 OpMemberDecorate %IndexBuffer 0 NonWritable 687 OpMemberDecorate %IndexBuffer 0 Offset 0 688 OpDecorate %IndexBuffer Block 689 OpDecorate %u_info DescriptorSet 0 690 OpDecorate %u_info Binding 0 691 )" + kImportDeco + R"( 692 %void = OpTypeVoid 693 %3 = OpTypeFunction %void 694 %int = OpTypeInt 32 1 695 %_ptr_Function_int = OpTypePointer Function %int 696 %int_0 = OpConstant %int 0 697 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_IndexBuffer PhysicalStorageBuffer 698 %ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_IndexBuffer %int 699 %uint = OpTypeInt 32 0 700 %v3uint = OpTypeVector %uint 3 701 %_runtimearr_v3uint = OpTypeRuntimeArray %v3uint 702 %IndexBuffer = OpTypeStruct %_runtimearr_v3uint 703 %_ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer PhysicalStorageBuffer %IndexBuffer 704 %_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo 705 %u_info = OpVariable %_ptr_Uniform_ufoo Uniform 706 %int_1 = OpConstant %int 1 707 %_ptr_Uniform_int = OpTypePointer Uniform %int 708 %bool = OpTypeBool 709 )" + kImportStub + R"( 710 %_ptr_Function_v3uint = OpTypePointer Function %v3uint 711 %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_IndexBuffer 712 %_ptr_PhysicalStorageBuffer_v3uint = OpTypePointer PhysicalStorageBuffer %v3uint 713 %main = OpFunction %void None %3 714 %5 = OpLabel 715 %i = OpVariable %_ptr_Function_int Function 716 %readvec = OpVariable %_ptr_Function_v3uint Function 717 OpStore %i %int_0 718 OpBranch %10 719 %10 = OpLabel 720 OpLoopMerge %12 %13 None 721 OpBranch %14 722 %14 = OpLabel 723 %15 = OpLoad %int %i 724 %26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 725 %27 = OpLoad %int %26 726 %29 = OpSLessThan %bool %15 %27 727 OpBranchConditional %29 %11 %12 728 %11 = OpLabel 729 %33 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer %u_info %int_0 730 %34 = OpLoad %_ptr_PhysicalStorageBuffer_IndexBuffer %33 731 %35 = OpLoad %int %i 732 %37 = OpAccessChain %_ptr_PhysicalStorageBuffer_v3uint %34 %int_0 %35 733 %38 = OpLoad %v3uint %37 Aligned 4 734 OpStore %readvec %38 735 ;CHECK-NOT: %38 = OpLoad %v3uint %37 Aligned 4 736 ;CHECK-NOT: OpStore %readvec %38 737 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %37 738 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex 739 ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex 740 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 741 ;CHECK: [[test_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_67 {{%\w+}} {{%\w+}} %uint_12 742 ;CHECK: OpSelectionMerge {{%\w+}} None 743 ;CHECK: OpBranchConditional [[test_result]] {{%\w+}} {{%\w+}} 744 ;CHECK: {{%\w+}} = OpLabel 745 ;CHECK: {{%\w+}} = OpLoad %v3uint %37 Aligned 4 746 ;CHECK: OpBranch {{%\w+}} 747 ;CHECK: {{%\w+}} = OpLabel 748 ;CHECK: OpBranch {{%\w+}} 749 ;CHECK: {{%\w+}} = OpLabel 750 ;CHECK: [[phi_result:%\w+]] = OpPhi %v3uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} 751 ;CHECK: OpStore %readvec [[phi_result]] 752 OpBranch %13 753 %13 = OpLabel 754 %39 = OpLoad %int %i 755 %40 = OpIAdd %int %39 %int_1 756 OpStore %i %40 757 OpBranch %10 758 %12 = OpLabel 759 OpReturn 760 OpFunctionEnd 761 )"; 762 // clang-format on 763 764 SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); 765 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 766 ValidatorOptions()->scalar_block_layout = true; 767 SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 23); 768 } 769 770 } // namespace 771 } // namespace opt 772 } // namespace spvtools 773