Fix dead branch elim infinite loop. (#1997)

When looking for a break from a selection construct, we do not need to
look inside nested constructs.  However, if a loop header has an
unconditional branch, then we enter the loop.  Entering the loop causes
an infinite loop because we keep going through the loop.

The solution is to look for a merge block, if one exsits, even for block
terminated by an OpBranch.

Fixes #1979.
This commit is contained in:
Steven Perron 2018-10-22 13:59:20 -04:00 committed by GitHub
parent 20bbfb6f4d
commit 0ba35798c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 3 deletions

View File

@ -514,9 +514,17 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge(
}
break;
case SpvOpBranch:
next_block_id = branch->GetSingleWordInOperand(0);
if (next_block_id == loop_merge_id) {
return nullptr;
// Need to check if this is the header of a loop nested in the
// selection construct.
next_block_id = start_block->MergeBlockIdIfAny();
if (next_block_id == 0) {
next_block_id = branch->GetSingleWordInOperand(0);
if (next_block_id == loop_merge_id) {
// We break out of the selection, but to the merge of a loop
// containing the selection. There is no break to the merge of the
// selection construct.
return nullptr;
}
}
break;
default:

View File

@ -2492,6 +2492,73 @@ OpFunctionEnd
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
}
TEST_F(DeadBranchElimTest, SelectionMergeWithNestedLoop) {
const std::string body =
R"(
; CHECK: OpSelectionMerge [[merge1:%\w+]]
; CHECK: [[merge1]] = OpLabel
; CHECK-NEXT: OpBranch [[preheader:%\w+]]
; CHECK: [[preheader]] = OpLabel
; CHECK-NOT: OpLabel
; CHECK: OpBranch [[header:%\w+]]
; CHECK: [[header]] = OpLabel
; CHECK-NOT: OpLabel
; CHECK: OpLoopMerge [[merge2:%\w+]]
; CHECK: [[merge2]] = OpLabel
; CHECK-NEXT: OpUnreachable
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource ESSL 310
OpName %main "main"
OpName %h "h"
OpName %i "i"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%bool = OpTypeBool
%_ptr_Function_bool = OpTypePointer Function %bool
%true = OpConstantTrue %bool
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_1 = OpConstant %int 1
%int_0 = OpConstant %int 0
%27 = OpUndef %bool
%main = OpFunction %void None %3
%5 = OpLabel
%h = OpVariable %_ptr_Function_bool Function
%i = OpVariable %_ptr_Function_int Function
OpSelectionMerge %11 None
OpBranchConditional %27 %10 %11
%10 = OpLabel
OpBranch %11
%11 = OpLabel
OpSelectionMerge %14 None
OpBranchConditional %true %13 %14
%13 = OpLabel
OpStore %i %int_1
OpBranch %19
%19 = OpLabel
OpLoopMerge %21 %22 None
OpBranch %23
%23 = OpLabel
%26 = OpSGreaterThan %bool %int_1 %int_0
OpBranchConditional %true %20 %21
%20 = OpLabel
OpBranch %22
%22 = OpLabel
OpBranch %19
%21 = OpLabel
OpBranch %14
%14 = OpLabel
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<DeadBranchElimPass>(body, true);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// More complex control flow