Skip to content

Commit 8bedb88

Browse files
committed
spv/lift: elide empty targets of an if-else/switch, as allowed by SPIR-V.
1 parent e8757ad commit 8bedb88

1 file changed

Lines changed: 54 additions & 6 deletions

File tree

src/spv/lift.rs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -863,22 +863,70 @@ impl<'a> FuncLifting<'a> {
863863
// HACK(eddyb) this takes advantage of `blocks` being an `IndexMap`,
864864
// to iterate at the same time as mutating other entries.
865865
for block_idx in (0..blocks.len()).rev() {
866-
let BlockLifting { terminator: original_terminator, .. } = &blocks[block_idx];
866+
// HACK(eddyb) elide empty cases of an `if`-`else`/`switch`, as
867+
// SPIR-V allows their targets to just be the whole merge block
868+
// (the same one that `OpSelectionMerge` describes).
869+
let block = &blocks[block_idx];
870+
if let (cfg::ControlInstKind::SelectBranch(_), Some(Merge::Selection(merge_point))) =
871+
(&*block.terminator.kind, block.terminator.merge)
872+
{
873+
for target_idx in 0..block.terminator.targets.len() {
874+
let block = &blocks[block_idx];
875+
let target = block.terminator.targets[target_idx];
876+
if !block
877+
.terminator
878+
.target_phi_values
879+
.get(&target)
880+
.copied()
881+
.unwrap_or_default()
882+
.is_empty()
883+
{
884+
continue;
885+
}
886+
887+
let target_is_trivial_branch = {
888+
let BlockLifting {
889+
phis,
890+
insts,
891+
terminator:
892+
Terminator { attrs, kind, inputs, targets, target_phi_values, merge },
893+
} = &blocks[&target];
894+
895+
(phis.is_empty()
896+
&& insts.iter().all(|insts| insts.is_empty())
897+
&& *attrs == AttrSet::default()
898+
&& matches!(**kind, cfg::ControlInstKind::Branch)
899+
&& inputs.is_empty()
900+
&& targets.len() == 1
901+
&& target_phi_values.is_empty()
902+
&& merge.is_none())
903+
.then(|| targets[0])
904+
};
905+
if let Some(target_of_target) = target_is_trivial_branch
906+
&& target_of_target == merge_point
907+
{
908+
blocks[block_idx].terminator.targets[target_idx] = target_of_target;
909+
*use_counts.get_mut(&target).unwrap() -= 1;
910+
*use_counts.get_mut(&target_of_target).unwrap() += 1;
911+
}
912+
}
913+
}
867914

915+
let block = &blocks[block_idx];
868916
let is_trivial_branch = {
869917
let Terminator { attrs, kind, inputs, targets, target_phi_values, merge } =
870-
original_terminator;
918+
&block.terminator;
871919

872-
*attrs == AttrSet::default()
920+
(*attrs == AttrSet::default()
873921
&& matches!(**kind, cfg::ControlInstKind::Branch)
874922
&& inputs.is_empty()
875923
&& targets.len() == 1
876924
&& target_phi_values.is_empty()
877-
&& merge.is_none()
925+
&& merge.is_none())
926+
.then(|| targets[0])
878927
};
879928

880-
if is_trivial_branch {
881-
let target = original_terminator.targets[0];
929+
if let Some(target) = is_trivial_branch {
882930
let target_use_count = use_counts.get_mut(&target).unwrap();
883931

884932
if *target_use_count == 1 {

0 commit comments

Comments
 (0)