diff --git a/cranelift/filetests/regalloc/coalesce.cton b/cranelift/filetests/regalloc/coalesce.cton index 7624eaef7c..bdddf26ef4 100644 --- a/cranelift/filetests/regalloc/coalesce.cton +++ b/cranelift/filetests/regalloc/coalesce.cton @@ -110,3 +110,15 @@ ebb1(v10: i32): v11 = iadd_imm v10, 1 return v11 } + +function %gvn_unremovable_phi(i32) native { +ebb0(v0: i32): + v2 = iconst.i32 0 + jump ebb2(v2, v0) + +ebb2(v3: i32, v4: i32): + brnz v3, ebb2(v3, v4) + v5 = iconst.i32 1 + brnz v3, ebb2(v2, v5) + return +} diff --git a/lib/cretonne/src/regalloc/coalescing.rs b/lib/cretonne/src/regalloc/coalescing.rs index 509f5a45e7..34a9b8bde0 100644 --- a/lib/cretonne/src/regalloc/coalescing.rs +++ b/lib/cretonne/src/regalloc/coalescing.rs @@ -450,13 +450,21 @@ impl<'a> Context<'a> { return Some(a); } - // The local conflict could be avoided by splitting at this predecessor, so try - // that. This split is not necessarily required, but it allows us to make progress. + // The local conflict could likely be avoided by splitting at this predecessor, so + // try that. This split is not necessarily required, but it allows us to make + // progress. let new_val = self.split_pred(pred_inst, pred_ebb, argnum, pred_val); - assert!( - self.add_class(new_val).is_ok(), - "Splitting didn't resolve conflict." - ); + + // If this tiny new live range can't be merged, there is something in the already + // merged values that is fundamentally incompatible with `pred_inst`, and we need + // to start over after removing that value. + // TODO: It is unfortunate that we discover this *after* splitting. It would have + // been better if we could detect and isolate `merged` before splitting. + if let Err((merged, _)) = self.add_class(new_val) { + dbg!("Splitting didn't help: {} interferes", merged); + // We need to start over, isolating the bad value. + return Some(merged); + } } }