Removing HLSLCounterBuffer decorations when not needed. (#1954)

The HlslCounterBufferGOOGLE that was introduced changed the OpDecorateId
so that is can now reference an id other than the target.  If that other
id is used only in the decoration, then the definition of the id will be
removed because decoration do not count as real uses.

However, if the target of the decoration is still live the decoration
will not be removed.  This leaves a reference to an id that is not
defined.

There are two solutions to consider.  The first is that is the decoration
is kept, then the definition of the id should be kept live.  Implementing
this change would be involved because the way ADCE handles decorations
will have to be reimplemented.

The other solution is to remove the decoration the id is otherwise dead.
This works for this specific case.  Also this is the more desirable
behaviour in this case.  The id will always be the id of a variable that
belongs to a descriptor set.  If that variable is not bound and we do
not remove it, the driver will complain.

I chose to implement the second solution.  The first will be left to when
a case for it comes up.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1885.
This commit is contained in:
Steven Perron 2018-10-05 08:23:09 -04:00 committed by Lei Zhang
parent ebcc58b5f8
commit 497958d899
2 changed files with 72 additions and 1 deletions

View File

@ -627,13 +627,31 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
switch (annotation->opcode()) { switch (annotation->opcode()) {
case SpvOpDecorate: case SpvOpDecorate:
case SpvOpMemberDecorate: case SpvOpMemberDecorate:
case SpvOpDecorateId:
case SpvOpDecorateStringGOOGLE: case SpvOpDecorateStringGOOGLE:
if (IsTargetDead(annotation)) { if (IsTargetDead(annotation)) {
context()->KillInst(annotation); context()->KillInst(annotation);
modified = true; modified = true;
} }
break; break;
case SpvOpDecorateId:
if (IsTargetDead(annotation)) {
context()->KillInst(annotation);
modified = true;
} else {
if (annotation->GetSingleWordInOperand(1) ==
SpvDecorationHlslCounterBufferGOOGLE) {
// HlslCounterBuffer will reference an id other than the target.
// If that id is dead, then the decoration can be removed as well.
uint32_t counter_buffer_id = annotation->GetSingleWordInOperand(2);
Instruction* counter_buffer_inst =
get_def_use_mgr()->GetDef(counter_buffer_id);
if (IsDead(counter_buffer_inst)) {
context()->KillInst(annotation);
modified = true;
}
}
}
break;
case SpvOpGroupDecorate: { case SpvOpGroupDecorate: {
// Go through the targets of this group decorate. Remove each dead // Go through the targets of this group decorate. Remove each dead
// target. If all targets are dead, remove this decoration. // target. If all targets are dead, remove this decoration.

View File

@ -5807,6 +5807,59 @@ OpFunctionEnd
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<AggressiveDCEPass>(test, test, true, true); SinglePassRunAndCheck<AggressiveDCEPass>(test, test, true, true);
} }
TEST_F(AggressiveDCETest, DeadHlslCounterBufferGOOGLE) {
// We are able to remove "local2" because it is not loaded, but have to keep
// the stores to "local1".
const std::string test =
R"(
; CHECK-NOT: OpDecorateId
; CHECK: [[var:%\w+]] = OpVariable
; CHECK-NOT: OpVariable
; CHECK: [[ac:%\w+]] = OpAccessChain {{%\w+}} [[var]]
; CHECK: OpStore [[ac]]
OpCapability Shader
OpExtension "SPV_GOOGLE_hlsl_functionality1"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %1 "main"
OpExecutionMode %1 LocalSize 32 1 1
OpSource HLSL 600
OpDecorate %_runtimearr_v2float ArrayStride 8
OpMemberDecorate %_struct_3 0 Offset 0
OpDecorate %_struct_3 BufferBlock
OpMemberDecorate %_struct_4 0 Offset 0
OpDecorate %_struct_4 BufferBlock
OpDecorateId %5 HlslCounterBufferGOOGLE %6
OpDecorate %5 DescriptorSet 0
OpDecorate %5 Binding 0
OpDecorate %6 DescriptorSet 0
OpDecorate %6 Binding 1
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%_runtimearr_v2float = OpTypeRuntimeArray %v2float
%_struct_3 = OpTypeStruct %_runtimearr_v2float
%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
%int = OpTypeInt 32 1
%_struct_4 = OpTypeStruct %int
%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
%void = OpTypeVoid
%13 = OpTypeFunction %void
%19 = OpConstantNull %v2float
%int_0 = OpConstant %int 0
%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
%5 = OpVariable %_ptr_Uniform__struct_3 Uniform
%6 = OpVariable %_ptr_Uniform__struct_4 Uniform
%1 = OpFunction %void None %13
%22 = OpLabel
%23 = OpAccessChain %_ptr_Uniform_v2float %5 %int_0 %int_0
OpStore %23 %19
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<AggressiveDCEPass>(test, true);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases: // TODO(greg-lunarg): Add tests to verify handling of these cases:
// //
// Check that logical addressing required // Check that logical addressing required