Handle dead infinite loops in DCE (#2471)

Fixes #2456

* When eliminating a structured construct that has an unreachable merge,
replace that unreachable terminator with an appropriate return
* New tests
This commit is contained in:
alan-baker 2019-04-03 10:30:12 -04:00 committed by GitHub
parent 8129cf2f99
commit 4bd106b089
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 148 additions and 0 deletions

View File

@ -513,6 +513,26 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) {
AddBranch(mergeBlockId, *bi);
for (++bi; (*bi)->id() != mergeBlockId; ++bi) {
}
auto merge_terminator = (*bi)->terminator();
if (merge_terminator->opcode() == SpvOpUnreachable) {
// The merge was unreachable. This is undefined behaviour so just
// return (or return an undef). Then mark the new return as live.
auto func_ret_type_inst = get_def_use_mgr()->GetDef(func->type_id());
if (func_ret_type_inst->opcode() == SpvOpTypeVoid) {
merge_terminator->SetOpcode(SpvOpReturn);
} else {
// Find an undef for the return value and make sure it gets kept by
// the pass.
auto undef_id = Type2Undef(func->type_id());
auto undef = get_def_use_mgr()->GetDef(undef_id);
live_insts_.Set(undef->unique_id());
merge_terminator->SetOpcode(SpvOpReturnValue);
merge_terminator->SetInOperands({{SPV_OPERAND_TYPE_ID, {undef_id}}});
get_def_use_mgr()->AnalyzeInstUse(merge_terminator);
}
live_insts_.Set(merge_terminator->unique_id());
}
} else {
++bi;
}

View File

@ -6210,6 +6210,134 @@ TEST_F(AggressiveDCETest, Dead) {
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<AggressiveDCEPass>(test, true);
}
TEST_F(AggressiveDCETest, DeadInfiniteLoop) {
const std::string test = R"(
; CHECK: OpSwitch {{%\w+}} {{%\w+}} {{\w+}} {{%\w+}} {{\w+}} [[block:%\w+]]
; CHECK: [[block]] = OpLabel
; CHECK-NEXT: OpBranch [[block:%\w+]]
; CHECK: [[block]] = OpLabel
; CHECK-NEXT: OpBranch [[block:%\w+]]
; CHECK: [[block]] = OpLabel
; CHECK-NEXT: OpReturn
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "main"
OpExecutionMode %2 OriginUpperLeft
%6 = OpTypeVoid
%7 = OpTypeFunction %6
%8 = OpTypeFloat 32
%9 = OpTypeVector %8 3
%10 = OpTypeFunction %9
%11 = OpConstant %8 1
%12 = OpConstantComposite %9 %11 %11 %11
%13 = OpTypeInt 32 1
%32 = OpUndef %13
%2 = OpFunction %6 None %7
%33 = OpLabel
OpBranch %34
%34 = OpLabel
OpLoopMerge %35 %36 None
OpBranch %37
%37 = OpLabel
%38 = OpFunctionCall %9 %39
OpSelectionMerge %40 None
OpSwitch %32 %40 14 %41 58 %42
%42 = OpLabel
OpBranch %43
%43 = OpLabel
OpLoopMerge %44 %45 None
OpBranch %45
%45 = OpLabel
OpBranch %43
%44 = OpLabel
OpUnreachable
%41 = OpLabel
OpBranch %36
%40 = OpLabel
OpBranch %36
%36 = OpLabel
OpBranch %34
%35 = OpLabel
OpReturn
OpFunctionEnd
%39 = OpFunction %9 None %10
%46 = OpLabel
OpReturnValue %12
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<AggressiveDCEPass>(test, true);
}
TEST_F(AggressiveDCETest, DeadInfiniteLoopReturnValue) {
const std::string test = R"(
; CHECK: [[vec3:%\w+]] = OpTypeVector
; CHECK: [[undef:%\w+]] = OpUndef [[vec3]]
; CHECK: OpSwitch {{%\w+}} {{%\w+}} {{\w+}} {{%\w+}} {{\w+}} [[block:%\w+]]
; CHECK: [[block]] = OpLabel
; CHECK-NEXT: OpBranch [[block:%\w+]]
; CHECK: [[block]] = OpLabel
; CHECK-NEXT: OpBranch [[block:%\w+]]
; CHECK: [[block]] = OpLabel
; CHECK-NEXT: OpReturnValue [[undef]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "main"
OpExecutionMode %2 OriginUpperLeft
%6 = OpTypeVoid
%7 = OpTypeFunction %6
%8 = OpTypeFloat 32
%9 = OpTypeVector %8 3
%10 = OpTypeFunction %9
%11 = OpConstant %8 1
%12 = OpConstantComposite %9 %11 %11 %11
%13 = OpTypeInt 32 1
%32 = OpUndef %13
%2 = OpFunction %6 None %7
%entry = OpLabel
%call = OpFunctionCall %9 %func
OpReturn
OpFunctionEnd
%func = OpFunction %9 None %10
%33 = OpLabel
OpBranch %34
%34 = OpLabel
OpLoopMerge %35 %36 None
OpBranch %37
%37 = OpLabel
%38 = OpFunctionCall %9 %39
OpSelectionMerge %40 None
OpSwitch %32 %40 14 %41 58 %42
%42 = OpLabel
OpBranch %43
%43 = OpLabel
OpLoopMerge %44 %45 None
OpBranch %45
%45 = OpLabel
OpBranch %43
%44 = OpLabel
OpUnreachable
%41 = OpLabel
OpBranch %36
%40 = OpLabel
OpBranch %36
%36 = OpLabel
OpBranch %34
%35 = OpLabel
OpReturnValue %12
OpFunctionEnd
%39 = OpFunction %9 None %10
%46 = OpLabel
OpReturnValue %12
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:
//
// Check that logical addressing required