Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasBanana committed Jan 28, 2020
2 parents 8c13316 + 97f1d48 commit 261244f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 13 deletions.
20 changes: 13 additions & 7 deletions source/opt/dead_branch_elim_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ bool DeadBranchElimPass::MarkLiveBlocks(
}

if (simplify) {
modified = true;
conditions_to_simplify.push_back({block, live_lab_id});
stack.push_back(GetParentBlock(live_lab_id));
} else {
Expand All @@ -179,24 +178,29 @@ bool DeadBranchElimPass::MarkLiveBlocks(
}
}

// Traverse |conditions_to_simplify in reverse order. This is done so that we
// simplify nested constructs before simplifying the constructs that contain
// them.
// Traverse |conditions_to_simplify| in reverse order. This is done so that
// we simplify nested constructs before simplifying the constructs that
// contain them.
for (auto b = conditions_to_simplify.rbegin();
b != conditions_to_simplify.rend(); ++b) {
SimplifyBranch(b->first, b->second);
modified |= SimplifyBranch(b->first, b->second);
}

return modified;
}

void DeadBranchElimPass::SimplifyBranch(BasicBlock* block,
bool DeadBranchElimPass::SimplifyBranch(BasicBlock* block,
uint32_t live_lab_id) {
Instruction* merge_inst = block->GetMergeInst();
Instruction* terminator = block->terminator();
if (merge_inst && merge_inst->opcode() == SpvOpSelectionMerge) {
if (merge_inst->NextNode()->opcode() == SpvOpSwitch &&
SwitchHasNestedBreak(block->id())) {
if (terminator->NumInOperands() == 2) {
// We cannot remove the branch, and it already has a single case, so no
// work to do.
return false;
}
// We have to keep the switch because it has a nest break, so we
// remove all cases except for the live one.
Instruction::OperandList new_operands;
Expand Down Expand Up @@ -231,6 +235,7 @@ void DeadBranchElimPass::SimplifyBranch(BasicBlock* block,
AddBranch(live_lab_id, block);
context()->KillInst(terminator);
}
return true;
}

void DeadBranchElimPass::MarkUnreachableStructuredTargets(
Expand Down Expand Up @@ -643,7 +648,8 @@ bool DeadBranchElimPass::SwitchHasNestedBreak(uint32_t switch_header_id) {
if (bb->id() == switch_header_id) {
return true;
}
return (cfg_analysis->ContainingConstruct(inst) == switch_header_id);
return (cfg_analysis->ContainingConstruct(inst) == switch_header_id &&
bb->GetMergeInst() == nullptr);
});
}

Expand Down
13 changes: 7 additions & 6 deletions source/opt/dead_branch_elim_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,15 @@ class DeadBranchElimPass : public MemPass {
std::unordered_set<BasicBlock*>* blocks_with_back_edges);

// Returns true if there is a brach to the merge node of the selection
// construct |switch_header_id| that is inside a nested selection construct.
// construct |switch_header_id| that is inside a nested selection construct or
// in the header of the nested selection construct.
bool SwitchHasNestedBreak(uint32_t switch_header_id);

// Replaces the terminator of |block| with a branch to |live_lab_id|. The
// merge instruction is deleted or moved as needed to maintain structured
// control flow. Assumes that the StructuredCFGAnalysis is valid for the
// constructs containing |block|.
void SimplifyBranch(BasicBlock* block, uint32_t live_lab_id);
// Return true of the terminator of |block| is successfully replaced with a
// branch to |live_lab_id|. The merge instruction is deleted or moved as
// needed to maintain structured control flow. Assumes that the
// StructuredCFGAnalysis is valid for the constructs containing |block|.
bool SimplifyBranch(BasicBlock* block, uint32_t live_lab_id);
};

} // namespace opt
Expand Down
68 changes: 68 additions & 0 deletions test/opt/dead_branch_elim_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,7 @@ OpFunctionEnd

SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
}

TEST_F(DeadBranchElimTest, LeaveContinueBackedgeExtraBlock) {
const std::string text = R"(
; CHECK: OpBranch [[header:%\w+]]
Expand Down Expand Up @@ -3161,6 +3162,73 @@ OpFunctionEnd
SinglePassRunAndCheck<DeadBranchElimPass>(before, after, true, true);
}

TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithSingleCase) {
const std::string text = R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%4 = OpTypeFunction %void
%bool = OpTypeBool
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%8 = OpUndef %bool
%main = OpFunction %void None %4
%9 = OpLabel
OpSelectionMerge %10 None
OpSwitch %uint_0 %11
%11 = OpLabel
OpSelectionMerge %12 None
OpBranchConditional %8 %10 %12
%12 = OpLabel
OpBranch %10
%10 = OpLabel
OpReturn
OpFunctionEnd
)";

SinglePassRunAndCheck<DeadBranchElimPass>(text, text, true, true);
}

TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithTwoCases) {
const std::string text = R"(
; CHECK: OpSelectionMerge [[merge:%\w+]] None
; CHECK-NEXT: OpSwitch %uint_0 [[bb:%\w+\n]]
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%4 = OpTypeFunction %void
%bool = OpTypeBool
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%8 = OpUndef %bool
%main = OpFunction %void None %4
%9 = OpLabel
OpSelectionMerge %10 None
OpSwitch %uint_0 %11 1 %12
%11 = OpLabel
OpSelectionMerge %13 None
OpBranchConditional %8 %10 %13
%13 = OpLabel
OpBranch %10
%12 = OpLabel
OpBranch %10
%10 = OpLabel
OpReturn
OpFunctionEnd
)";

SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
}

// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// More complex control flow
Expand Down

0 comments on commit 261244f

Please sign in to comment.