Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 56 additions & 6 deletions src/spv/lift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,22 +863,72 @@ impl<'a> FuncLifting<'a> {
// HACK(eddyb) this takes advantage of `blocks` being an `IndexMap`,
// to iterate at the same time as mutating other entries.
for block_idx in (0..blocks.len()).rev() {
let BlockLifting { terminator: original_terminator, .. } = &blocks[block_idx];
// HACK(eddyb) elide empty cases of an `if`-`else`/`switch`, as
// SPIR-V allows their targets to just be the whole merge block
// (the same one that `OpSelectionMerge` describes).
let block = &blocks[block_idx];
if let (cfg::ControlInstKind::SelectBranch(_), Some(Merge::Selection(merge_point))) =
(&*block.terminator.kind, block.terminator.merge)
{
for target_idx in 0..block.terminator.targets.len() {
let block = &blocks[block_idx];
let target = block.terminator.targets[target_idx];
if !block
.terminator
.target_phi_values
.get(&target)
.copied()
.unwrap_or_default()
.is_empty()
{
continue;
}

let target_is_trivial_branch = {
let BlockLifting {
phis,
insts,
terminator:
Terminator { attrs, kind, inputs, targets, target_phi_values, merge },
} = &blocks[&target];

(phis.is_empty()
&& insts.iter().all(|insts| insts.is_empty())
&& *attrs == AttrSet::default()
&& matches!(**kind, cfg::ControlInstKind::Branch)
&& inputs.is_empty()
&& targets.len() == 1
&& target_phi_values.is_empty()
&& merge.is_none())
.then(|| targets[0])
};
if let Some(target_of_target) = target_is_trivial_branch {
// FIXME(eddyb) what does it mean for this to not be true?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put an error or panic in here so if we hit it we are aware.

// (can it even happen?)
if target_of_target == merge_point {
blocks[block_idx].terminator.targets[target_idx] = target_of_target;
*use_counts.get_mut(&target).unwrap() -= 1;
*use_counts.get_mut(&target_of_target).unwrap() += 1;
}
}
}
}

let block = &blocks[block_idx];
let is_trivial_branch = {
let Terminator { attrs, kind, inputs, targets, target_phi_values, merge } =
original_terminator;
&block.terminator;

*attrs == AttrSet::default()
(*attrs == AttrSet::default()
&& matches!(**kind, cfg::ControlInstKind::Branch)
&& inputs.is_empty()
&& targets.len() == 1
&& target_phi_values.is_empty()
&& merge.is_none()
&& merge.is_none())
.then(|| targets[0])
};

if is_trivial_branch {
let target = original_terminator.targets[0];
if let Some(target) = is_trivial_branch {
let target_use_count = use_counts.get_mut(&target).unwrap();

if *target_use_count == 1 {
Expand Down
Loading