Skip to content

Commit 8404c2c

Browse files
committed
Check full block range for loop/continue overlap in RVSDG guards
Selection and switch construct guards now check ALL blocks between header and merge indices, not just named targets (header, then, else, merge). Intermediate blocks in the range may be loop continue targets that must remain reachable.
1 parent 47c50c0 commit 8404c2c

1 file changed

Lines changed: 23 additions & 23 deletions

File tree

  • rust/spirv-tools-opt/src/direct

rust/spirv-tools-opt/src/direct/mod.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -625,20 +625,22 @@ pub fn optimize_module_direct(module: &Module) -> Result<Module, EgglogOptError>
625625
// For each selection construct, convert to RVSDG EffGamma
626626
for (sel_idx, sel) in selection_constructs.iter().enumerate() {
627627
// Skip selections that overlap with loop bodies or continue blocks.
628-
// Check ALL blocks involved (header, then, else, merge) — not just the header —
629-
// because SPIR-V blocks may not be laid out contiguously.
628+
// Check ALL blocks in the construct range [header, merge] — not just the
629+
// named targets — because intermediate blocks (e.g. continue targets) may
630+
// exist between branch targets and the merge block.
630631
{
631632
let label_map = &func_block_labels[sel.func_idx];
632-
let in_loop = loop_block_set.contains(&(sel.func_idx, sel.header_block_idx))
633-
|| continue_block_set.contains(&(sel.func_idx, sel.header_block_idx))
634-
|| [&sel.then_label, &sel.else_label, &sel.merge_label]
635-
.iter()
636-
.any(|label| {
637-
label_map.get(label).map_or(false, |&idx| {
638-
loop_block_set.contains(&(sel.func_idx, idx))
639-
|| continue_block_set.contains(&(sel.func_idx, idx))
640-
})
641-
});
633+
let merge_idx = label_map.get(&sel.merge_label).copied();
634+
let in_loop = if let Some(merge_idx) = merge_idx {
635+
// Check all blocks from header to merge (inclusive)
636+
(sel.header_block_idx..=merge_idx).any(|idx| {
637+
loop_block_set.contains(&(sel.func_idx, idx))
638+
|| continue_block_set.contains(&(sel.func_idx, idx))
639+
})
640+
} else {
641+
// Can't resolve merge — skip to be safe
642+
true
643+
};
642644
if in_loop {
643645
continue;
644646
}
@@ -746,21 +748,19 @@ pub fn optimize_module_direct(module: &Module) -> Result<Module, EgglogOptError>
746748
let mut rvsdg_switches: Vec<RvsdgSwitch> = Vec::new();
747749

748750
for sw in &switch_constructs {
749-
// Skip switches that overlap with loop bodies or continue blocks
751+
// Skip switches that overlap with loop bodies or continue blocks.
752+
// Check ALL blocks in the construct range [header, merge].
750753
{
751754
let label_map = &func_block_labels[sw.func_idx];
752-
let in_loop = loop_block_set.contains(&(sw.func_idx, sw.header_block_idx))
753-
|| continue_block_set.contains(&(sw.func_idx, sw.header_block_idx))
754-
|| sw.case_labels.iter().any(|label| {
755-
label_map.get(label).map_or(false, |&idx| {
756-
loop_block_set.contains(&(sw.func_idx, idx))
757-
|| continue_block_set.contains(&(sw.func_idx, idx))
758-
})
759-
})
760-
|| label_map.get(&sw.merge_label).map_or(false, |&idx| {
755+
let merge_idx = label_map.get(&sw.merge_label).copied();
756+
let in_loop = if let Some(merge_idx) = merge_idx {
757+
(sw.header_block_idx..=merge_idx).any(|idx| {
761758
loop_block_set.contains(&(sw.func_idx, idx))
762759
|| continue_block_set.contains(&(sw.func_idx, idx))
763-
});
760+
})
761+
} else {
762+
true
763+
};
764764
if in_loop {
765765
continue;
766766
}

0 commit comments

Comments
 (0)