Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Cross.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Kristian Arntzen <post@arntzen-software.no>2019-08-26 10:56:00 +0300
committerHans-Kristian Arntzen <post@arntzen-software.no>2019-08-26 11:05:43 +0300
commite3d4dddfec57f4a76fb52308f8277360638d06c7 (patch)
tree06660bdfb1188cddf20f81fdfe1f45d9cabc69ec /spirv_cfg.cpp
parent4ce04480ec5469fe7ebbdd66c3016090a704d81b (diff)
Fix variable scope when switch block exits multiple times.
Inner scope can still dominate here, so we need to be conservative when we observe switch blocks specifically. Normal selection merges cannot merge from multiple paths.
Diffstat (limited to 'spirv_cfg.cpp')
-rw-r--r--spirv_cfg.cpp25
1 files changed, 23 insertions, 2 deletions
diff --git a/spirv_cfg.cpp b/spirv_cfg.cpp
index ed31f236..8f6f024c 100644
--- a/spirv_cfg.cpp
+++ b/spirv_cfg.cpp
@@ -148,14 +148,35 @@ bool CFG::post_order_visit(uint32_t block_id)
// Add a fake branch so any dominator in either the if (), or else () block, or a lone case statement
// will be hoisted out to outside the selection merge.
// If size > 1, the variable will be automatically hoisted, so we should not mess with it.
+ // The exception here is switch blocks, where we can have multiple edges to merge block,
+ // all coming from same scope, so be more conservative in this case.
// Adding fake branches unconditionally breaks parameter preservation analysis,
// which looks at how variables are accessed through the CFG.
auto pred_itr = preceding_edges.find(block.next_block);
if (pred_itr != end(preceding_edges))
{
auto &pred = pred_itr->second;
- if (pred.size() == 1 && *pred.begin() != block_id)
- add_branch(block_id, block.next_block);
+ auto succ_itr = succeeding_edges.find(block_id);
+ uint32_t num_succeeding_edges = 0;
+ if (succ_itr != end(succeeding_edges))
+ num_succeeding_edges = succ_itr->second.size();
+
+ if (block.terminator == SPIRBlock::MultiSelect && num_succeeding_edges == 1)
+ {
+ // Multiple branches can come from the same scope due to "break;", so we need to assume that all branches
+ // come from same case scope in worst case, even if there are multiple preceding edges.
+ // If we have more than one succeeding edge from the block header, it should be impossible
+ // to have a dominator be inside the block.
+ // Only case this can go wrong is if we have 2 or more edges from block header and
+ // 2 or more edges to merge block, and still have dominator be inside a case label.
+ if (!pred.empty())
+ add_branch(block_id, block.next_block);
+ }
+ else
+ {
+ if (pred.size() == 1 && *pred.begin() != block_id)
+ add_branch(block_id, block.next_block);
+ }
}
else
{