mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-19 19:40:13 +00:00
ba4c9fe534
Avoid using OpConstantNull with types that do not allow it. Update existing tests for slight changes in code generation. Add new tests based on the Vulkan Validation layer test case that exposed this problem.
686 lines
26 KiB
C++
686 lines
26 KiB
C++
// Copyright (c) 2019-2022 Valve Corporation
|
|
// Copyright (c) 2019-2022 LunarG Inc.
|
|
//
|
|
// 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.
|
|
|
|
// Bindless Check Instrumentation Tests.
|
|
// Tests ending with V2 use version 2 record format.
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "test/opt/assembly_builder.h"
|
|
#include "test/opt/pass_fixture.h"
|
|
#include "test/opt/pass_utils.h"
|
|
|
|
namespace spvtools {
|
|
namespace opt {
|
|
namespace {
|
|
|
|
static const std::string kOutputDecorations = R"(
|
|
; CHECK: OpDecorate [[output_buffer_type:%inst_buff_addr_OutputBuffer]] Block
|
|
; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0
|
|
; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4
|
|
; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7
|
|
; CHECK: OpDecorate [[output_buffer_var]] Binding 0
|
|
)";
|
|
|
|
static const std::string kOutputGlobals = R"(
|
|
; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint
|
|
; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]]
|
|
; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer
|
|
)";
|
|
|
|
static const std::string kStreamWrite4Begin = R"(
|
|
; CHECK: {{%\w+}} = OpFunction %void None {{%\w+}}
|
|
; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
|
|
; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
|
|
; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
|
|
; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
|
|
; CHECK: {{%\w+}} = OpLabel
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1
|
|
; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_10
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
|
|
; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2
|
|
; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
|
|
; CHECK: OpSelectionMerge {{%\w+}} None
|
|
; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLabel
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} %uint_10
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} %uint_23
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} [[param_1]]
|
|
)";
|
|
|
|
static const std::string kStreamWrite4End = R"(
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} [[param_2]]
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} [[param_3]]
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} [[param_4]]
|
|
; CHECK: OpBranch {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLabel
|
|
; CHECK: OpReturn
|
|
; CHECK: OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format off
|
|
static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"(
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} %uint_4
|
|
; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
|
|
; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} {{%\w+}}
|
|
)" + kStreamWrite4End;
|
|
|
|
static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"(
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} %uint_5
|
|
; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
|
|
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
|
|
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
|
|
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} {{%\w+}}
|
|
)" + kStreamWrite4End;
|
|
// clang-format on
|
|
|
|
// clang-format off
|
|
static const std::string kStreamWrite4Vert = kStreamWrite4Begin + R"(
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} %uint_0
|
|
; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
|
|
; CHECK: OpStore {{%\w+}} {{%\w+}}
|
|
)" + kStreamWrite4End;
|
|
// clang-format on
|
|
|
|
static const std::string kInputDecorations = R"(
|
|
; CHECK: OpDecorate [[input_buffer_type:%inst_buff_addr_InputBuffer]] Block
|
|
; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0
|
|
; CHECK: OpDecorate [[input_buffer_var:%\w+]] DescriptorSet 7
|
|
; CHECK: OpDecorate [[input_buffer_var]] Binding 2
|
|
)";
|
|
|
|
static const std::string kInputGlobals = R"(
|
|
; CHECK: [[input_buffer_type]] = OpTypeStruct %_runtimearr_ulong
|
|
; CHECK: [[input_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[input_buffer_type]]
|
|
; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer
|
|
)";
|
|
|
|
static const std::string kSearchAndTest = R"(
|
|
; CHECK: {{%\w+}} = OpFunction %bool None {{%\w+}}
|
|
; CHECK: [[param_1:%\w+]] = OpFunctionParameter %ulong
|
|
; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
|
|
; CHECK: {{%\w+}} = OpLabel
|
|
; CHECK: OpBranch {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLabel
|
|
; CHECK: {{%\w+}} = OpPhi %uint %uint_1 {{%\w+}} {{%\w+}} {{%\w+}}
|
|
; CHECK: OpLoopMerge {{%\w+}} {{%\w+}} None
|
|
; CHECK: OpBranch {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLabel
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpUGreaterThan %bool {{%\w+}} [[param_1]]
|
|
; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLabel
|
|
; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpISub %ulong [[param_1]] {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpUConvert %ulong [[param_2]]
|
|
; CHECK: {{%\w+}} = OpIAdd %ulong {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 %uint_0
|
|
; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1
|
|
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
|
|
; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
|
|
; CHECK: OpReturnValue {{%\w+}}
|
|
; CHECK: OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
|
|
using InstBuffAddrTest = PassTest<::testing::Test>;
|
|
|
|
TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferStore) {
|
|
// #version 450
|
|
// #extension GL_EXT_buffer_reference : enable
|
|
//
|
|
// layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
|
|
//
|
|
// layout(set = 0, binding = 0) uniform ufoo {
|
|
// bufStruct data;
|
|
// uint offset;
|
|
// } u_info;
|
|
//
|
|
// layout(buffer_reference, std140) buffer bufStruct {
|
|
// layout(offset = 0) int a[2];
|
|
// layout(offset = 32) int b;
|
|
// };
|
|
//
|
|
// void main() {
|
|
// u_info.data.b = 0xca7;
|
|
// }
|
|
|
|
const std::string defs = R"(
|
|
OpCapability Shader
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
; CHECK: OpCapability Int64
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpSource GLSL 450
|
|
OpSourceExtension "GL_EXT_buffer_reference"
|
|
OpName %main "main"
|
|
OpName %ufoo "ufoo"
|
|
OpMemberName %ufoo 0 "data"
|
|
OpMemberName %ufoo 1 "offset"
|
|
OpName %bufStruct "bufStruct"
|
|
OpMemberName %bufStruct 0 "a"
|
|
OpMemberName %bufStruct 1 "b"
|
|
OpName %u_info "u_info"
|
|
)";
|
|
|
|
// clang-format off
|
|
const std::string decorates = R"(
|
|
OpMemberDecorate %ufoo 0 Offset 0
|
|
OpMemberDecorate %ufoo 1 Offset 8
|
|
OpDecorate %ufoo Block
|
|
OpDecorate %_arr_int_uint_2 ArrayStride 16
|
|
OpMemberDecorate %bufStruct 0 Offset 0
|
|
OpMemberDecorate %bufStruct 1 Offset 32
|
|
OpDecorate %bufStruct Block
|
|
OpDecorate %u_info DescriptorSet 0
|
|
OpDecorate %u_info Binding 0
|
|
; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
|
|
)" + kInputDecorations + R"(
|
|
; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
|
|
)" + kOutputDecorations + R"(
|
|
; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
|
|
)";
|
|
|
|
const std::string globals = R"(
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
|
|
%uint = OpTypeInt 32 0
|
|
%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint
|
|
%int = OpTypeInt 32 1
|
|
%uint_2 = OpConstant %uint 2
|
|
%_arr_int_uint_2 = OpTypeArray %int %uint_2
|
|
%bufStruct = OpTypeStruct %_arr_int_uint_2 %int
|
|
%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
|
|
%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
|
|
%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
|
|
%int_0 = OpConstant %int 0
|
|
%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
|
|
%int_1 = OpConstant %int 1
|
|
%int_3239 = OpConstant %int 3239
|
|
%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
|
|
; CHECK: %ulong = OpTypeInt 64 0
|
|
; CHECK: %bool = OpTypeBool
|
|
; CHECK: %28 = OpTypeFunction %bool %ulong %uint
|
|
; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong
|
|
)" + kInputGlobals + R"(
|
|
; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong
|
|
; CHECK: %70 = OpTypeFunction %void %uint %uint %uint %uint
|
|
; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
|
|
)" + kOutputGlobals + R"(
|
|
; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
|
|
; CHECK: %v3uint = OpTypeVector %uint 3
|
|
; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
|
|
; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
|
|
)";
|
|
// clang-format off
|
|
|
|
const std::string main_func = R"(
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
|
|
%18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
|
|
%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
|
|
; CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
|
|
; CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
|
|
; CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
|
|
; CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
|
|
; CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20
|
|
; CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1
|
|
; CHECK: %24 = OpConvertPtrToU %ulong %22
|
|
; CHECK: %61 = OpFunctionCall %bool %inst_buff_addr_search_and_test %24 %uint_4
|
|
; CHECK: OpSelectionMerge %62 None
|
|
; CHECK: OpBranchConditional %61 %63 %64
|
|
; CHECK: %63 = OpLabel
|
|
OpStore %22 %int_3239 Aligned 16
|
|
; CHECK: OpStore %22 %int_3239 Aligned 16
|
|
; CHECK: OpBranch %62
|
|
; CHECK: %64 = OpLabel
|
|
; CHECK: %65 = OpUConvert %uint %24
|
|
; CHECK: %67 = OpShiftRightLogical %ulong %24 %uint_32
|
|
; CHECK: %68 = OpUConvert %uint %67
|
|
; CHECK: %124 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_48 %uint_2 %65 %68
|
|
; CHECK: OpBranch %62
|
|
; CHECK: %62 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute;
|
|
|
|
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndMatch<InstBuffAddrCheckPass>(
|
|
defs + decorates + globals + main_func + output_funcs, true, 7u, 23u);
|
|
}
|
|
|
|
TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) {
|
|
// #version 450
|
|
// #extension GL_EXT_buffer_reference : enable
|
|
|
|
// // forward reference
|
|
// layout(buffer_reference) buffer blockType;
|
|
|
|
// layout(buffer_reference, std430, buffer_reference_align = 16) buffer
|
|
// blockType {
|
|
// int x;
|
|
// blockType next;
|
|
// };
|
|
|
|
// layout(std430) buffer rootBlock {
|
|
// blockType root;
|
|
// } r;
|
|
|
|
// void main()
|
|
// {
|
|
// blockType b = r.root;
|
|
// b = b.next;
|
|
// b.x = 531;
|
|
// }
|
|
|
|
const std::string defs = R"(
|
|
OpCapability Shader
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
; CHECK: OpCapability Int64
|
|
OpExtension "SPV_EXT_physical_storage_buffer"
|
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
OpSource GLSL 450
|
|
OpSourceExtension "GL_EXT_buffer_reference"
|
|
OpName %main "main"
|
|
; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
|
|
OpName %blockType "blockType"
|
|
OpMemberName %blockType 0 "x"
|
|
OpMemberName %blockType 1 "next"
|
|
OpName %rootBlock "rootBlock"
|
|
OpMemberName %rootBlock 0 "root"
|
|
OpName %r "r"
|
|
)";
|
|
|
|
// clang-format off
|
|
const std::string decorates = R"(
|
|
OpMemberDecorate %blockType 0 Offset 0
|
|
OpMemberDecorate %blockType 1 Offset 8
|
|
OpDecorate %blockType Block
|
|
OpMemberDecorate %rootBlock 0 Offset 0
|
|
OpDecorate %rootBlock Block
|
|
OpDecorate %r DescriptorSet 0
|
|
OpDecorate %r Binding 0
|
|
; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
|
|
)" + kInputDecorations + R"(
|
|
; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
|
|
)" + kOutputDecorations + R"(
|
|
; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
|
|
)";
|
|
// clang-format on
|
|
|
|
const std::string globals = R"(
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
|
|
%int = OpTypeInt 32 1
|
|
%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
|
|
%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
|
|
%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
|
|
%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
|
|
%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
|
|
%int_0 = OpConstant %int 0
|
|
%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
|
|
%int_1 = OpConstant %int 1
|
|
%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
|
|
%int_531 = OpConstant %int 531
|
|
%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
|
|
)" + kInputGlobals + kOutputGlobals;
|
|
|
|
const std::string main_func = R"(
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
|
|
%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16
|
|
%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1
|
|
%22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
|
|
%26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
|
|
OpStore %26 %int_531 Aligned 16
|
|
; CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
|
|
; CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
|
|
; CHECK: %30 = OpConvertPtrToU %ulong %21
|
|
; CHECK: %67 = OpFunctionCall %bool %inst_buff_addr_search_and_test %30 %uint_8
|
|
; CHECK: OpSelectionMerge %68 None
|
|
; CHECK: OpBranchConditional %67 %69 %70
|
|
; CHECK: %69 = OpLabel
|
|
; CHECK: %71 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
|
|
; CHECK: OpBranch %68
|
|
; CHECK: %70 = OpLabel
|
|
; CHECK: %72 = OpUConvert %uint %30
|
|
; CHECK: %74 = OpShiftRightLogical %ulong %30 %uint_32
|
|
; CHECK: %75 = OpUConvert %uint %74
|
|
; CHECK: %131 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_44 %uint_2 %72 %75
|
|
; CHECK: %133 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %132
|
|
; CHECK: OpBranch %68
|
|
; CHECK: %68 = OpLabel
|
|
; CHECK: %134 = OpPhi %_ptr_PhysicalStorageBuffer_blockType %71 %69 %133 %70
|
|
; CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %134 %int_0
|
|
; CHECK: %135 = OpConvertPtrToU %ulong %26
|
|
; CHECK: %136 = OpFunctionCall %bool %inst_buff_addr_search_and_test %135 %uint_4
|
|
; CHECK: OpSelectionMerge %137 None
|
|
; CHECK: OpBranchConditional %136 %138 %139
|
|
; CHECK: %138 = OpLabel
|
|
; CHECK: OpStore %26 %int_531 Aligned 16
|
|
; CHECK: OpBranch %137
|
|
; CHECK: %139 = OpLabel
|
|
; CHECK: %140 = OpUConvert %uint %135
|
|
; CHECK: %141 = OpShiftRightLogical %ulong %135 %uint_32
|
|
; CHECK: %142 = OpUConvert %uint %141
|
|
; CHECK: %144 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_46 %uint_2 %140 %142
|
|
; CHECK: OpBranch %137
|
|
; CHECK: %137 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute;
|
|
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndMatch<InstBuffAddrCheckPass>(
|
|
defs + decorates + globals + main_func + output_funcs, true, 7u, 23u);
|
|
}
|
|
|
|
TEST_F(InstBuffAddrTest, StructLoad) {
|
|
// #version 450
|
|
// #extension GL_EXT_buffer_reference : enable
|
|
// #extension GL_ARB_gpu_shader_int64 : enable
|
|
// struct Test {
|
|
// float a;
|
|
// };
|
|
//
|
|
// layout(buffer_reference, std430, buffer_reference_align = 16) buffer
|
|
// TestBuffer { Test test; };
|
|
//
|
|
// Test GetTest(uint64_t ptr) {
|
|
// return TestBuffer(ptr).test;
|
|
// }
|
|
//
|
|
// void main() {
|
|
// GetTest(0xe0000000);
|
|
// }
|
|
|
|
const std::string defs =
|
|
R"(
|
|
OpCapability Shader
|
|
OpCapability Int64
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
; CHECK: OpEntryPoint Fragment %main "main" %inst_buff_addr_input_buffer %inst_buff_addr_output_buffer %gl_FragCoord
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpSourceExtension "GL_ARB_gpu_shader_int64"
|
|
OpSourceExtension "GL_EXT_buffer_reference"
|
|
OpName %main "main"
|
|
OpName %Test "Test"
|
|
OpMemberName %Test 0 "a"
|
|
OpName %Test_0 "Test"
|
|
OpMemberName %Test_0 0 "a"
|
|
OpName %TestBuffer "TestBuffer"
|
|
OpMemberName %TestBuffer 0 "test"
|
|
)";
|
|
|
|
// clang-format off
|
|
const std::string decorates = R"(
|
|
OpMemberDecorate %Test_0 0 Offset 0
|
|
OpMemberDecorate %TestBuffer 0 Offset 0
|
|
OpDecorate %TestBuffer Block
|
|
; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
|
|
)" + kInputDecorations + R"(
|
|
; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
|
|
)" + kOutputDecorations + R"(
|
|
; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
|
|
)";
|
|
|
|
const std::string globals = R"(
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%ulong = OpTypeInt 64 0
|
|
%float = OpTypeFloat 32
|
|
%Test = OpTypeStruct %float
|
|
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer
|
|
%Test_0 = OpTypeStruct %float
|
|
%TestBuffer = OpTypeStruct %Test_0
|
|
%_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0
|
|
%ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704
|
|
; CHECK: %47 = OpTypeFunction %bool %ulong %uint
|
|
)" + kInputGlobals + R"(
|
|
; CHECK: %90 = OpTypeFunction %void %uint %uint %uint %uint
|
|
)" + kOutputGlobals + R"(
|
|
; CHECK: %143 = OpConstantNull %Test_0
|
|
)";
|
|
// clang-format on
|
|
|
|
const std::string main_func =
|
|
R"(
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%37 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %ulong_18446744073172680704
|
|
%38 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %37 %int_0
|
|
%39 = OpLoad %Test_0 %38 Aligned 16
|
|
; CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16
|
|
; CHECK: %43 = OpConvertPtrToU %ulong %38
|
|
; CHECK: %80 = OpFunctionCall %bool %inst_buff_addr_search_and_test %43 %uint_4
|
|
; CHECK: OpSelectionMerge %81 None
|
|
; CHECK: OpBranchConditional %80 %82 %83
|
|
; CHECK: %82 = OpLabel
|
|
; CHECK: %84 = OpLoad %Test_0 %38 Aligned 16
|
|
; CHECK: OpBranch %81
|
|
; CHECK: %83 = OpLabel
|
|
; CHECK: %85 = OpUConvert %uint %43
|
|
; CHECK: %87 = OpShiftRightLogical %ulong %43 %uint_32
|
|
; CHECK: %88 = OpUConvert %uint %87
|
|
; CHECK: %142 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_37 %uint_2 %85 %88
|
|
; CHECK: OpBranch %81
|
|
; CHECK: %81 = OpLabel
|
|
; CHECK: %144 = OpPhi %Test_0 %84 %82 %143 %83
|
|
%40 = OpCopyLogical %Test %39
|
|
; CHECK-NOT: %40 = OpCopyLogical %Test %39
|
|
; CHECK: %40 = OpCopyLogical %Test %144
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string output_funcs = kSearchAndTest + kStreamWrite4Frag;
|
|
|
|
SetTargetEnv(SPV_ENV_VULKAN_1_2);
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndMatch<InstBuffAddrCheckPass>(
|
|
defs + decorates + globals + main_func + output_funcs, true);
|
|
}
|
|
|
|
TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) {
|
|
// #version 450
|
|
// #extension GL_EXT_buffer_reference : enable
|
|
// layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
|
|
// layout(set = 0, binding = 0) uniform ufoo {
|
|
// bufStruct data;
|
|
// int nWrites;
|
|
// } u_info;
|
|
// layout(buffer_reference, std140) buffer bufStruct {
|
|
// int a[4];
|
|
// };
|
|
// void main() {
|
|
// for (int i=0; i < u_info.nWrites; ++i) {
|
|
// u_info.data.a[i] = 0xdeadca71;
|
|
// }
|
|
// }
|
|
|
|
// clang-format off
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
OpCapability PhysicalStorageBufferAddresses
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
|
OpEntryPoint Vertex %main "main" %u_info
|
|
;CHECK: OpEntryPoint Vertex %main "main" %u_info %inst_buff_addr_input_buffer %inst_buff_addr_output_buffer %gl_VertexIndex %gl_InstanceIndex
|
|
OpSource GLSL 450
|
|
OpSourceExtension "GL_EXT_buffer_reference"
|
|
OpName %main "main"
|
|
OpName %i "i"
|
|
OpName %ufoo "ufoo"
|
|
OpMemberName %ufoo 0 "data"
|
|
OpMemberName %ufoo 1 "nWrites"
|
|
OpName %bufStruct "bufStruct"
|
|
OpMemberName %bufStruct 0 "a"
|
|
OpName %u_info "u_info"
|
|
OpMemberDecorate %ufoo 0 Offset 0
|
|
OpMemberDecorate %ufoo 1 Offset 8
|
|
OpDecorate %ufoo Block
|
|
OpDecorate %_arr_int_uint_4 ArrayStride 16
|
|
OpMemberDecorate %bufStruct 0 Offset 0
|
|
OpDecorate %bufStruct Block
|
|
OpDecorate %u_info DescriptorSet 0
|
|
OpDecorate %u_info Binding 0)" + kInputDecorations + kOutputDecorations + R"(
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_0 = OpConstant %int 0
|
|
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
|
|
%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int
|
|
%uint = OpTypeInt 32 0
|
|
%uint_4 = OpConstant %uint 4
|
|
%_arr_int_uint_4 = OpTypeArray %int %uint_4
|
|
%bufStruct = OpTypeStruct %_arr_int_uint_4
|
|
%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
|
|
%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
|
|
%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
|
|
%int_1 = OpConstant %int 1
|
|
%_ptr_Uniform_int = OpTypePointer Uniform %int
|
|
%bool = OpTypeBool
|
|
%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
|
|
%int_n559035791 = OpConstant %int -559035791
|
|
%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int)" + kInputGlobals + kOutputGlobals + R"(
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%i = OpVariable %_ptr_Function_int Function
|
|
OpStore %i %int_0
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%15 = OpLoad %int %i
|
|
%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1
|
|
%27 = OpLoad %int %26
|
|
%29 = OpSLessThan %bool %15 %27
|
|
OpBranchConditional %29 %11 %12
|
|
%11 = OpLabel
|
|
%31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
|
|
%32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
|
|
%33 = OpLoad %int %i
|
|
%36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33
|
|
;CHECK: %41 = OpConvertPtrToU %ulong %36
|
|
;CHECK: %76 = OpFunctionCall %bool %inst_buff_addr_search_and_test %41 %uint_4
|
|
;CHECK: OpSelectionMerge %77 None
|
|
;CHECK: OpBranchConditional %76 %78 %79
|
|
;CHECK: %78 = OpLabel
|
|
OpStore %36 %int_n559035791 Aligned 16
|
|
;CHECK: OpBranch %77
|
|
;CHECK: 79 = OpLabel
|
|
;CHECK: 80 = OpUConvert %uint %41
|
|
;CHECK: 82 = OpShiftRightLogical %ulong %41 %uint_32
|
|
;CHECK: 83 = OpUConvert %uint %82
|
|
;CHECK: 134 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_62 %uint_2 %80 %83
|
|
;CHECK: OpBranch %77
|
|
;CHECK: 77 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%37 = OpLoad %int %i
|
|
%38 = OpIAdd %int %37 %int_1
|
|
OpStore %i %38
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd)" + kSearchAndTest + kStreamWrite4Vert;
|
|
// clang-format on
|
|
|
|
SetTargetEnv(SPV_ENV_VULKAN_1_2);
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 7, 23);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace opt
|
|
} // namespace spvtools
|