From 0e5fd810958305226ae98e5debb94b2140cc38d5 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Sat, 14 Mar 2026 20:10:01 +1000 Subject: [PATCH] Only emit value label aliases for lowered instructions If we emit a value label alias for an instruction that isn't lowered, then that signals that the value has been optimised out. However, since it is an alias we know that the value also exists in an earlier vreg, so we should skip the alias and use that instead. This situation occurs often for memory indexes on AArch64. We translate memory stores into instructions such as: v8 = iconst.i32 42 v9 = uextend.i64 v6 v10 = load.i64 notrap aligned readonly can_move checked v0+56 v11 = iadd v10, v9 v12 = iconst.i64 20 v13 = iadd v11, v12 ; v12 = 20 store little heap v8, v13 ; v8 = 42 Here, v6 is a memory index (which has a label) and v9 is an extension of the memory index (which has a label alias, added by cast_index_to_pointer_ty()). This is lowered to: 40c: 52800540 mov w0, #0x2a // #42 410: f9401c41 ldr x1, [x2, #56] 414: 91005021 add x1, x1, #0x14 418: b8384820 str w0, [x1, w24, uxtw] The uextend has been folded into the str, so v9 has been optimised out. But v6 is still present in w24, so the debuginfo should use that instead. This fixes the following tests for AArch64: native_debug::lldb::dwarf_cold_block native_debug::lldb::dwarf_fib_wasm native_debug::lldb::dwarf_fib_wasm_dwarf5 native_debug::lldb::dwarf_fib_wasm_split4 native_debug::lldb::dwarf_fission native_debug::lldb::dwarf_fraction_norm native_debug::lldb::dwarf_imported_memory native_debug::lldb::dwarf_shared_memory native_debug::lldb::dwarf_simple native_debug::lldb::dwarf_spilled_frame_base --- cranelift/codegen/src/machinst/lower.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cranelift/codegen/src/machinst/lower.rs b/cranelift/codegen/src/machinst/lower.rs index c3ce9fa9c96c..dc09f10c4d9c 100644 --- a/cranelift/codegen/src/machinst/lower.rs +++ b/cranelift/codegen/src/machinst/lower.rs @@ -802,7 +802,9 @@ impl<'func, I: VCodeInst> Lower<'func, I> { // Value defined by "inst" becomes live after it in normal // order, and therefore **before** in reversed order. - self.emit_value_label_live_range_start_for_inst(inst); + // Only emit value label aliases if the instruction will be lowered + // (otherwise we want to keep using the earlier label instead). + self.emit_value_label_live_range_start_for_inst(inst, has_side_effect || value_needed); // Normal instruction: codegen if the instruction is side-effecting // or any of its outputs is used. @@ -949,14 +951,14 @@ impl<'func, I: VCodeInst> Lower<'func, I> { } } - fn emit_value_label_marks_for_value(&mut self, val: Value) { + fn emit_value_label_marks_for_value(&mut self, val: Value, allow_alias: bool) { let regs = self.value_regs[val]; if regs.len() > 1 { return; } let reg = regs.only_reg().unwrap(); - if let Some(label_starts) = self.get_value_labels(val, 0) { + if let Some(label_starts) = self.get_value_labels(val, if allow_alias { 0 } else { !0 }) { let labels = label_starts .iter() .map(|&ValueLabelStart { label, .. }| label) @@ -971,7 +973,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> { } } - fn emit_value_label_live_range_start_for_inst(&mut self, inst: Inst) { + fn emit_value_label_live_range_start_for_inst(&mut self, inst: Inst, allow_alias: bool) { if self.f.dfg.values_labels.is_none() { return; } @@ -982,7 +984,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> { inst ); for &val in self.f.dfg.inst_results(inst) { - self.emit_value_label_marks_for_value(val); + self.emit_value_label_marks_for_value(val, allow_alias); } } @@ -993,7 +995,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> { trace!("value labeling: block {}", block); for &arg in self.f.dfg.block_params(block) { - self.emit_value_label_marks_for_value(arg); + self.emit_value_label_marks_for_value(arg, true); } self.finish_ir_inst(Default::default()); }