CFG: Handle implied access to opaque loaded values.

Similar concern as access chains. Objects that we cannot lower to
temporaries must implicitly access all expression dependencies when they
are themselves accessed.
This commit is contained in:
Hans-Kristian Arntzen 2022-12-13 16:31:17 +01:00
parent c77b09b57c
commit 68a012a4f2
4 changed files with 203 additions and 5 deletions

View File

@ -0,0 +1,71 @@
#version 450
#if defined(GL_EXT_control_flow_attributes)
#extension GL_EXT_control_flow_attributes : require
#define SPIRV_CROSS_FLATTEN [[flatten]]
#define SPIRV_CROSS_BRANCH [[dont_flatten]]
#define SPIRV_CROSS_UNROLL [[unroll]]
#define SPIRV_CROSS_LOOP [[dont_unroll]]
#else
#define SPIRV_CROSS_FLATTEN
#define SPIRV_CROSS_BRANCH
#define SPIRV_CROSS_UNROLL
#define SPIRV_CROSS_LOOP
#endif
struct MyConsts
{
uint opt;
};
uvec4 _37;
layout(binding = 3, std140) uniform type_scene
{
MyConsts myConsts;
} scene;
uniform sampler2D SPIRV_Cross_CombinedtexTablemySampler[1];
layout(location = 1) out uint out_var_SV_TARGET1;
void main()
{
uint _42;
bool _47;
float _55;
do
{
_42 = _37.y & 16777215u;
_47 = scene.myConsts.opt != 0u;
SPIRV_CROSS_BRANCH
if (_47)
{
_55 = 1.0;
break;
}
else
{
_55 = textureLod(SPIRV_Cross_CombinedtexTablemySampler[_42], vec2(0.0), 0.0).x;
break;
}
break; // unreachable workaround
} while(false);
float _66;
do
{
SPIRV_CROSS_BRANCH
if (_47)
{
_66 = 1.0;
break;
}
else
{
_66 = textureLod(SPIRV_Cross_CombinedtexTablemySampler[_42], vec2(0.0), 0.0).x;
break;
}
break; // unreachable workaround
} while(false);
out_var_SV_TARGET1 = uint(cross(vec3(-1.0, -1.0, _55), vec3(1.0, 1.0, _66)).x);
}

View File

@ -0,0 +1,120 @@
; SPIR-V
; Version: 1.0
; Generator: Google spiregg; 0
; Bound: 71
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %ps_main "main" %out_var_SV_TARGET1
OpExecutionMode %ps_main OriginUpperLeft
OpSource HLSL 600
OpName %type_scene "type.scene"
OpMemberName %type_scene 0 "myConsts"
OpName %MyConsts "MyConsts"
OpMemberName %MyConsts 0 "opt"
OpName %scene "scene"
OpName %type_sampler "type.sampler"
OpName %mySampler "mySampler"
OpName %type_2d_image "type.2d.image"
OpName %texTable "texTable"
OpName %out_var_SV_TARGET1 "out.var.SV_TARGET1"
OpName %ps_main "ps_main"
OpName %type_sampled_image "type.sampled.image"
OpDecorate %out_var_SV_TARGET1 Location 1
OpDecorate %scene DescriptorSet 0
OpDecorate %scene Binding 3
OpDecorate %mySampler DescriptorSet 0
OpDecorate %mySampler Binding 2
OpDecorate %texTable DescriptorSet 0
OpDecorate %texTable Binding 0
OpMemberDecorate %MyConsts 0 Offset 0
OpMemberDecorate %type_scene 0 Offset 0
OpDecorate %type_scene Block
%float = OpTypeFloat 32
%float_1 = OpConstant %float 1
%v2float = OpTypeVector %float 2
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%uint = OpTypeInt 32 0
%uint_16777215 = OpConstant %uint 16777215
%uint_0 = OpConstant %uint 0
%float_0 = OpConstant %float 0
%21 = OpConstantComposite %v2float %float_0 %float_0
%MyConsts = OpTypeStruct %uint
%type_scene = OpTypeStruct %MyConsts
%_ptr_Uniform_type_scene = OpTypePointer Uniform %type_scene
%type_sampler = OpTypeSampler
%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
%uint_1 = OpConstant %uint 1
%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
%_arr_type_2d_image_uint_1 = OpTypeArray %type_2d_image %uint_1
%_ptr_UniformConstant__arr_type_2d_image_uint_1 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_1
%_ptr_Output_uint = OpTypePointer Output %uint
%void = OpTypeVoid
%29 = OpTypeFunction %void
%v4uint = OpTypeVector %uint 4
%v3float = OpTypeVector %float 3
%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%bool = OpTypeBool
%type_sampled_image = OpTypeSampledImage %type_2d_image
%v4float = OpTypeVector %float 4
%scene = OpVariable %_ptr_Uniform_type_scene Uniform
%mySampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
%texTable = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_1 UniformConstant
%out_var_SV_TARGET1 = OpVariable %_ptr_Output_uint Output
%float_n1 = OpConstant %float -1
%37 = OpUndef %v4uint
%ps_main = OpFunction %void None %29
%38 = OpLabel
OpSelectionMerge %39 None
OpSwitch %uint_0 %40
%40 = OpLabel
%41 = OpCompositeExtract %uint %37 1
%42 = OpBitwiseAnd %uint %41 %uint_16777215
%43 = OpAccessChain %_ptr_UniformConstant_type_2d_image %texTable %42
%44 = OpLoad %type_2d_image %43
%45 = OpAccessChain %_ptr_Uniform_uint %scene %int_0 %int_0
%46 = OpLoad %uint %45
%47 = OpINotEqual %bool %46 %uint_0
OpSelectionMerge %48 DontFlatten
OpBranchConditional %47 %49 %50
%50 = OpLabel
%51 = OpLoad %type_sampler %mySampler
%52 = OpSampledImage %type_sampled_image %44 %51
%53 = OpImageSampleExplicitLod %v4float %52 %21 Lod %float_0
%54 = OpCompositeExtract %float %53 0
OpBranch %39
%49 = OpLabel
OpBranch %39
%48 = OpLabel
OpUnreachable
%39 = OpLabel
%55 = OpPhi %float %54 %50 %float_1 %49
%56 = OpCompositeConstruct %v3float %float_n1 %float_n1 %55
OpSelectionMerge %57 None
OpSwitch %uint_0 %58
%58 = OpLabel
OpSelectionMerge %59 DontFlatten
OpBranchConditional %47 %60 %61
%61 = OpLabel
%62 = OpLoad %type_sampler %mySampler
%63 = OpSampledImage %type_sampled_image %44 %62
%64 = OpImageSampleExplicitLod %v4float %63 %21 Lod %float_0
%65 = OpCompositeExtract %float %64 0
OpBranch %57
%60 = OpLabel
OpBranch %57
%59 = OpLabel
OpUnreachable
%57 = OpLabel
%66 = OpPhi %float %65 %61 %float_1 %60
%67 = OpCompositeConstruct %v3float %float_1 %float_1 %66
%68 = OpExtInst %v3float %1 Cross %56 %67
%69 = OpCompositeExtract %float %68 0
%70 = OpConvertFToU %uint %69
OpStore %out_var_SV_TARGET1 %70
OpReturn
OpFunctionEnd

View File

@ -3213,8 +3213,8 @@ void Compiler::AnalyzeVariableScopeAccessHandler::notify_variable_access(uint32_
return;
// Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers.
auto itr = access_chain_children.find(id);
if (itr != end(access_chain_children))
auto itr = rvalue_forward_children.find(id);
if (itr != end(rvalue_forward_children))
for (auto child_id : itr->second)
notify_variable_access(child_id, block);
@ -3322,14 +3322,14 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3
if (var)
{
accessed_variables_to_block[var->self].insert(current_block->self);
access_chain_children[args[1]].insert(var->self);
rvalue_forward_children[args[1]].insert(var->self);
}
// args[2] might be another access chain we have to track use of.
for (uint32_t i = 2; i < length; i++)
{
notify_variable_access(args[i], current_block->self);
access_chain_children[args[1]].insert(args[i]);
rvalue_forward_children[args[1]].insert(args[i]);
}
// Also keep track of the access chain pointer itself.
@ -3411,6 +3411,12 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3
// Might be an access chain we have to track use of.
notify_variable_access(args[2], current_block->self);
// If we're loading an opaque type we cannot lower it to a temporary,
// we must defer access of args[2] until it's used.
auto &type = compiler.get<SPIRType>(args[0]);
if (compiler.type_is_opaque_value(type))
rvalue_forward_children[args[1]].insert(args[2]);
break;
}

View File

@ -1015,7 +1015,8 @@ protected:
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> partial_write_variables_to_block;
std::unordered_set<uint32_t> access_chain_expressions;
// Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers.
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> access_chain_children;
// This is also relevant when forwarding opaque objects since we cannot lower these to temporaries.
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> rvalue_forward_children;
const SPIRBlock *current_block = nullptr;
};