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 25namespace spvtools { 26namespace opt { 27namespace { 28 29static const std::string kFuncName = "inst_buff_addr_search_and_test"; 30static const std::string kImportDeco = R"( 31;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" + 32 kFuncName + R"(" Import 33)"; 34static const std::string kImportStub = R"( 35;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}} 36;CHECK: OpFunctionEnd 37)"; 38// clang-format on 39 40using InstBuffAddrTest = PassTest<::testing::Test>; 41 42TEST_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"( 63OpCapability Shader 64OpCapability PhysicalStorageBufferAddresses 65;CHECK: OpCapability Int64 66OpExtension "SPV_EXT_physical_storage_buffer" 67;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" 68%1 = OpExtInstImport "GLSL.std.450" 69OpMemoryModel PhysicalStorageBuffer64 GLSL450 70OpEntryPoint GLCompute %main "main" 71;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID 72OpExecutionMode %main LocalSize 1 1 1 73OpSource GLSL 450 74OpSourceExtension "GL_EXT_buffer_reference" 75OpName %main "main" 76OpName %ufoo "ufoo" 77OpMemberName %ufoo 0 "data" 78OpMemberName %ufoo 1 "offset" 79OpName %bufStruct "bufStruct" 80OpMemberName %bufStruct 0 "a" 81OpMemberName %bufStruct 1 "b" 82OpName %u_info "u_info" 83)"; 84 85 // clang-format off 86 const std::string decorates = R"( 87OpMemberDecorate %ufoo 0 Offset 0 88OpMemberDecorate %ufoo 1 Offset 8 89OpDecorate %ufoo Block 90OpDecorate %_arr_int_uint_2 ArrayStride 16 91OpMemberDecorate %bufStruct 0 Offset 0 92OpMemberDecorate %bufStruct 1 Offset 32 93OpDecorate %bufStruct Block 94OpDecorate %u_info DescriptorSet 0 95OpDecorate %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 103OpTypeForwardPointer %_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 148OpStore %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 154OpReturn 155OpFunctionEnd 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 163TEST_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"( 188OpCapability Shader 189OpCapability PhysicalStorageBufferAddresses 190;CHECK: OpCapability Int64 191OpExtension "SPV_EXT_physical_storage_buffer" 192OpExtension "SPV_KHR_storage_buffer_storage_class" 193%1 = OpExtInstImport "GLSL.std.450" 194OpMemoryModel PhysicalStorageBuffer64 GLSL450 195OpEntryPoint GLCompute %main "main" 196OpExecutionMode %main LocalSize 1 1 1 197OpSource GLSL 450 198OpSourceExtension "GL_EXT_buffer_reference" 199OpName %main "main" 200;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID 201OpName %blockType "blockType" 202OpMemberName %blockType 0 "x" 203OpMemberName %blockType 1 "next" 204OpName %rootBlock "rootBlock" 205OpMemberName %rootBlock 0 "root" 206OpName %r "r" 207)"; 208 209// clang-format off 210 const std::string decorates = R"( 211OpMemberDecorate %blockType 0 Offset 0 212OpMemberDecorate %blockType 1 Offset 8 213OpDecorate %blockType Block 214OpMemberDecorate %rootBlock 0 Offset 0 215OpDecorate %rootBlock Block 216OpDecorate %r DescriptorSet 0 217OpDecorate %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 225OpTypeForwardPointer %_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 248OpStore %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 284OpReturn 285OpFunctionEnd 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 294TEST_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"( 315OpCapability Shader 316OpCapability Int64 317OpCapability PhysicalStorageBufferAddresses 318;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" 319%1 = OpExtInstImport "GLSL.std.450" 320OpMemoryModel PhysicalStorageBuffer64 GLSL450 321OpEntryPoint Fragment %main "main" 322;CHECK: OpEntryPoint Fragment %main "main" %gl_FragCoord 323OpExecutionMode %main OriginUpperLeft 324OpSource GLSL 450 325OpSourceExtension "GL_ARB_gpu_shader_int64" 326OpSourceExtension "GL_EXT_buffer_reference" 327OpName %main "main" 328OpName %Test "Test" 329OpMemberName %Test 0 "a" 330OpName %Test_0 "Test" 331OpMemberName %Test_0 0 "a" 332OpName %TestBuffer "TestBuffer" 333OpMemberName %TestBuffer 0 "test" 334)"; 335 336 // clang-format off 337 const std::string decorates = R"( 338OpMemberDecorate %Test_0 0 Offset 0 339OpMemberDecorate %TestBuffer 0 Offset 0 340OpDecorate %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 351OpTypeForwardPointer %_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]] 388OpReturn 389OpFunctionEnd 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 399TEST_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"( 422OpCapability Shader 423OpCapability Float64 424OpCapability Int64 425OpCapability PhysicalStorageBufferAddresses 426%1 = OpExtInstImport "GLSL.std.450" 427OpMemoryModel PhysicalStorageBuffer64 GLSL450 428OpEntryPoint Vertex %main "main" 429OpSource GLSL 450 430OpSourceExtension "GL_ARB_gpu_shader_int64" 431OpSourceExtension "GL_EXT_buffer_reference" 432OpName %main "main" 433OpName %Test "Test" 434OpMemberName %Test 0 "pad_1" 435OpMemberName %Test 1 "pad_2" 436OpMemberName %Test 2 "a" 437OpName %GetTest_u641_ "GetTest(u641;" 438OpName %ptr "ptr" 439OpName %Test_0 "Test" 440OpMemberName %Test_0 0 "pad_1" 441OpMemberName %Test_0 1 "pad_2" 442OpMemberName %Test_0 2 "a" 443OpName %TestBuffer "TestBuffer" 444OpMemberName %TestBuffer 0 "test" 445OpName %param "param" 446)"; 447 448 // clang-format off 449 const std::string decorates = R"( 450OpDecorate %TestBuffer Block 451OpMemberDecorate %Test_0 0 Offset 0 452OpMemberDecorate %Test_0 1 Offset 16 453OpMemberDecorate %Test_0 2 Offset 24 454OpMemberDecorate %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 471OpTypeForwardPointer %_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 487OpStore %param %ulong_18446744073172680704 488%35 = OpFunctionCall %Test %GetTest_u641_ %param 489OpReturn 490OpFunctionEnd 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]] 518OpStore %28 %29 519%30 = OpLoad %Test %28 520OpReturnValue %30 521OpFunctionEnd 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 531TEST_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"( 550OpCapability Shader 551OpCapability PhysicalStorageBufferAddresses 552%1 = OpExtInstImport "GLSL.std.450" 553OpMemoryModel PhysicalStorageBuffer64 GLSL450 554OpEntryPoint Vertex %main "main" %u_info 555;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex 556OpSource GLSL 450 557OpSourceExtension "GL_EXT_buffer_reference" 558OpName %main "main" 559OpName %i "i" 560OpName %ufoo "ufoo" 561OpMemberName %ufoo 0 "data" 562OpMemberName %ufoo 1 "nWrites" 563OpName %bufStruct "bufStruct" 564OpMemberName %bufStruct 0 "a" 565OpName %u_info "u_info" 566OpMemberDecorate %ufoo 0 Offset 0 567OpMemberDecorate %ufoo 1 Offset 8 568OpDecorate %ufoo Block 569OpDecorate %_arr_int_uint_4 ArrayStride 16 570OpMemberDecorate %bufStruct 0 Offset 0 571OpDecorate %bufStruct Block 572OpDecorate %u_info DescriptorSet 0 573OpDecorate %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 580OpTypeForwardPointer %_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 599OpStore %i %int_0 600OpBranch %10 601%10 = OpLabel 602OpLoopMerge %12 %13 None 603OpBranch %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 609OpBranchConditional %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 615OpStore %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 629OpBranch %13 630%13 = OpLabel 631%37 = OpLoad %int %i 632%38 = OpIAdd %int %37 %int_1 633OpStore %i %38 634OpBranch %10 635%12 = OpLabel 636OpReturn 637OpFunctionEnd)"; 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 645TEST_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"( 665OpCapability Shader 666OpCapability PhysicalStorageBufferAddresses 667%1 = OpExtInstImport "GLSL.std.450" 668OpMemoryModel PhysicalStorageBuffer64 GLSL450 669OpEntryPoint Vertex %main "main" %u_info 670OpSource GLSL 450 671OpSourceExtension "GL_EXT_buffer_reference" 672OpSourceExtension "GL_EXT_scalar_block_layout" 673OpName %main "main" 674OpName %i "i" 675OpName %ufoo "ufoo" 676OpMemberName %ufoo 0 "data" 677OpMemberName %ufoo 1 "nReads" 678OpName %IndexBuffer "IndexBuffer" 679OpMemberName %IndexBuffer 0 "indices" 680OpName %u_info "u_info" 681OpName %readvec "readvec" 682OpMemberDecorate %ufoo 0 Offset 0 683OpMemberDecorate %ufoo 1 Offset 8 684OpDecorate %ufoo Block 685OpDecorate %_runtimearr_v3uint ArrayStride 12 686OpMemberDecorate %IndexBuffer 0 NonWritable 687OpMemberDecorate %IndexBuffer 0 Offset 0 688OpDecorate %IndexBuffer Block 689OpDecorate %u_info DescriptorSet 0 690OpDecorate %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 697OpTypeForwardPointer %_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 717OpStore %i %int_0 718OpBranch %10 719%10 = OpLabel 720OpLoopMerge %12 %13 None 721OpBranch %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 727OpBranchConditional %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 734OpStore %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]] 752OpBranch %13 753%13 = OpLabel 754%39 = OpLoad %int %i 755%40 = OpIAdd %int %39 %int_1 756OpStore %i %40 757OpBranch %10 758%12 = OpLabel 759OpReturn 760OpFunctionEnd 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