Skip to content

Commit 02cacc0

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

File tree

1 file changed

+56
-6
lines changed

1 file changed

+56
-6
lines changed

src/spv/lift.rs

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -863,22 +863,72 @@ 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+
// FIXME(eddyb) what does it mean for this to not be true?
907+
// (can it even happen?)
908+
if target_of_target == merge_point {
909+
blocks[block_idx].terminator.targets[target_idx] = target_of_target;
910+
*use_counts.get_mut(&target).unwrap() -= 1;
911+
*use_counts.get_mut(&target_of_target).unwrap() += 1;
912+
}
913+
}
914+
}
915+
}
867916

917+
let block = &blocks[block_idx];
868918
let is_trivial_branch = {
869919
let Terminator { attrs, kind, inputs, targets, target_phi_values, merge } =
870-
original_terminator;
920+
&block.terminator;
871921

872-
*attrs == AttrSet::default()
922+
(*attrs == AttrSet::default()
873923
&& matches!(**kind, cfg::ControlInstKind::Branch)
874924
&& inputs.is_empty()
875925
&& targets.len() == 1
876926
&& target_phi_values.is_empty()
877-
&& merge.is_none()
927+
&& merge.is_none())
928+
.then(|| targets[0])
878929
};
879930

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

884934
if *target_use_count == 1 {

0 commit comments

Comments
 (0)