Skip to content

Commit f8b164c

Browse files
committed
MachInst backend: pass through SourceLoc information.
This change adds SourceLoc information per instruction in a `VCode<Inst>` container, and keeps this information up-to-date across register allocation and branch reordering. The information is initially collected during instruction lowering, eventually collected on the MachSection, and finally provided to the environment that wraps the codegen crate for wasmtime. This PR is based on top of bytecodealliance#1570 and bytecodealliance#1571 (part of a series fixing tests). This PR depends on wasmtime/regalloc.rs#50, a change to the register allocator to provide instruction-granularity info on the rewritten instruction stream (rather than block-granularity). With the prior PRs applied as well, quite a few more unit tests pass; the exclusion list in bytecodealliance#1526 should be updated if this PR lands first.
1 parent ce9b49e commit f8b164c

File tree

5 files changed

+136
-16
lines changed

5 files changed

+136
-16
lines changed

cranelift/codegen/src/machinst/lower.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
360360
"lower_branch_group: targets = {:?} branches = {:?}",
361361
targets, branches
362362
);
363+
self.vcode.set_srcloc(Some(self.srcloc(branches[0])));
363364
backend.lower_branch_group(
364365
&mut self,
365366
&branches[..],
@@ -376,6 +377,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
376377
let num_uses = self.num_uses[inst];
377378
let side_effect = has_side_effect(self.f, inst);
378379
if side_effect || num_uses > 0 {
380+
self.vcode.set_srcloc(Some(self.srcloc(inst)));
379381
backend.lower(&mut self, inst);
380382
self.vcode.end_ir_inst();
381383
} else {
@@ -404,6 +406,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
404406
"lower_branch_group: targets = {:?} branches = {:?}",
405407
targets, branches
406408
);
409+
self.vcode.set_srcloc(Some(self.srcloc(branches[0])));
407410
backend.lower_branch_group(&mut self, &branches[..], &targets[..], fallthrough);
408411
self.vcode.end_ir_inst();
409412
branches.clear();

cranelift/codegen/src/machinst/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@
9797
//! ```
9898
9999
use crate::binemit::{CodeInfo, CodeOffset};
100-
use crate::entity::SecondaryMap;
101100
use crate::ir::condcodes::IntCC;
102101
use crate::ir::{Function, Type};
103102
use crate::result::CodegenResult;

cranelift/codegen/src/machinst/sections.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ impl MachSections {
7474
sink.end_codegen();
7575
}
7676

77+
/// Get a list of source location mapping tuples.
78+
pub fn get_srclocs(&self) -> Vec<MachSrcLoc> {
79+
let mut ret = vec![];
80+
for section in &self.sections {
81+
ret.extend(section.srclocs.clone().into_iter());
82+
}
83+
ret
84+
}
85+
7786
/// Get the total required size for these sections.
7887
pub fn total_size(&self) -> CodeOffset {
7988
if self.sections.len() == 0 {
@@ -143,6 +152,12 @@ pub trait MachSectionOutput {
143152
/// Add a call return address record at the current offset.
144153
fn add_call_site(&mut self, loc: SourceLoc, opcode: Opcode);
145154

155+
/// Start the output for the given source-location at the current offset.
156+
fn start_srcloc(&mut self, loc: SourceLoc);
157+
158+
/// End the output for the previously-given source-location at the current offset.
159+
fn end_srcloc(&mut self);
160+
146161
/// Align up to the given alignment.
147162
fn align_to(&mut self, align_to: CodeOffset) {
148163
assert!(align_to.is_power_of_two());
@@ -168,8 +183,13 @@ pub struct MachSection {
168183
pub relocs: Vec<MachReloc>,
169184
/// Any trap records referring to this section.
170185
pub traps: Vec<MachTrap>,
171-
/// Any call site record referring to this section.
186+
/// Any call site records referring to this section.
172187
pub call_sites: Vec<MachCallSite>,
188+
/// Any source location mappings referring to this section.
189+
pub srclocs: Vec<MachSrcLoc>,
190+
/// The curren source location in progress (after `start_srcloc()` and before `end_srcloc()`).
191+
/// This is a (start_offset, src_loc) tuple.
192+
pub cur_srcloc: Option<(CodeOffset, SourceLoc)>,
173193
}
174194

175195
impl MachSection {
@@ -182,6 +202,8 @@ impl MachSection {
182202
relocs: vec![],
183203
traps: vec![],
184204
call_sites: vec![],
205+
srclocs: vec![],
206+
cur_srcloc: None,
185207
}
186208
}
187209

@@ -266,6 +288,22 @@ impl MachSectionOutput for MachSection {
266288
opcode,
267289
});
268290
}
291+
292+
fn start_srcloc(&mut self, loc: SourceLoc) {
293+
self.cur_srcloc = Some((self.cur_offset_from_start(), loc));
294+
}
295+
296+
fn end_srcloc(&mut self) {
297+
if let Some((start, loc)) = self.cur_srcloc.take() {
298+
let end = self.cur_offset_from_start();
299+
// Skip zero-length extends.
300+
if end > start {
301+
self.srclocs.push(MachSrcLoc { start, end, loc });
302+
}
303+
} else {
304+
panic!("end_srcloc() called without start_srcloc()");
305+
}
306+
}
269307
}
270308

271309
/// A MachSectionOutput implementation that records only size.
@@ -315,6 +353,10 @@ impl MachSectionOutput for MachSectionSize {
315353
fn add_trap(&mut self, _: SourceLoc, _: TrapCode) {}
316354

317355
fn add_call_site(&mut self, _: SourceLoc, _: Opcode) {}
356+
357+
fn start_srcloc(&mut self, _: SourceLoc) {}
358+
359+
fn end_srcloc(&mut self) {}
318360
}
319361

320362
/// A relocation resulting from a compilation.
@@ -352,3 +394,16 @@ pub struct MachCallSite {
352394
/// The call's opcode.
353395
pub opcode: Opcode,
354396
}
397+
398+
/// A source-location mapping resulting from a compilation.
399+
#[derive(Clone, Debug)]
400+
pub struct MachSrcLoc {
401+
/// The start of the region of code corresponding to a source location.
402+
/// This is absolute, not relative to the start of the section.
403+
pub start: CodeOffset,
404+
/// The end of the region of code corresponding to a source location.
405+
/// This is absolute, not relative to the start of the section.
406+
pub end: CodeOffset,
407+
/// The source location.
408+
pub loc: SourceLoc,
409+
}

cranelift/codegen/src/machinst/vcode.rs

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
//! See the main module comment in `mod.rs` for more details on the VCode-based
1818
//! backend pipeline.
1919
20+
use crate::entity::SecondaryMap;
2021
use crate::ir;
22+
use crate::ir::SourceLoc;
2123
use crate::machinst::*;
2224
use crate::settings;
2325

@@ -59,6 +61,10 @@ pub struct VCode<I: VCodeInst> {
5961
/// Lowered machine instructions in order corresponding to the original IR.
6062
insts: Vec<I>,
6163

64+
/// Source locations for each instruction. (`SourceLoc` is a `u32`, so it is
65+
/// reasonable to keep one of these per instruction.)
66+
srclocs: Vec<Option<SourceLoc>>,
67+
6268
/// Entry block.
6369
entry: BlockIndex,
6470

@@ -115,13 +121,16 @@ pub struct VCodeBuilder<I: VCodeInst> {
115121

116122
/// Current basic block instructions, in reverse order (because blocks are
117123
/// built bottom-to-top).
118-
bb_insns: SmallVec<[I; 32]>,
124+
bb_insns: SmallVec<[(I, Option<SourceLoc>); 32]>,
119125

120126
/// Current IR-inst instructions, in forward order.
121-
ir_inst_insns: SmallVec<[I; 4]>,
127+
ir_inst_insns: SmallVec<[(I, Option<SourceLoc>); 4]>,
122128

123129
/// Start of succs for the current block in the concatenated succs list.
124130
succ_start: usize,
131+
132+
/// Current source location.
133+
cur_srcloc: Option<SourceLoc>,
125134
}
126135

127136
impl<I: VCodeInst> VCodeBuilder<I> {
@@ -133,6 +142,7 @@ impl<I: VCodeInst> VCodeBuilder<I> {
133142
bb_insns: SmallVec::new(),
134143
ir_inst_insns: SmallVec::new(),
135144
succ_start: 0,
145+
cur_srcloc: None,
136146
}
137147
}
138148

@@ -179,8 +189,8 @@ impl<I: VCodeInst> VCodeBuilder<I> {
179189
/// End the current IR instruction. Must be called after pushing any
180190
/// instructions and prior to ending the basic block.
181191
pub fn end_ir_inst(&mut self) {
182-
while let Some(i) = self.ir_inst_insns.pop() {
183-
self.bb_insns.push(i);
192+
while let Some(pair) = self.ir_inst_insns.pop() {
193+
self.bb_insns.push(pair);
184194
}
185195
}
186196

@@ -191,8 +201,9 @@ impl<I: VCodeInst> VCodeBuilder<I> {
191201
let block_num = self.vcode.block_ranges.len() as BlockIndex;
192202
// Push the instructions.
193203
let start_idx = self.vcode.insts.len() as InsnIndex;
194-
while let Some(i) = self.bb_insns.pop() {
204+
while let Some((i, loc)) = self.bb_insns.pop() {
195205
self.vcode.insts.push(i);
206+
self.vcode.srclocs.push(loc);
196207
}
197208
let end_idx = self.vcode.insts.len() as InsnIndex;
198209
// Add the instruction index range to the list of blocks.
@@ -224,7 +235,12 @@ impl<I: VCodeInst> VCodeBuilder<I> {
224235
}
225236
}
226237
}
227-
self.ir_inst_insns.push(insn);
238+
self.ir_inst_insns.push((insn, self.cur_srcloc));
239+
}
240+
241+
/// Set the current source location.
242+
pub fn set_srcloc(&mut self, srcloc: Option<SourceLoc>) {
243+
self.cur_srcloc = srcloc;
228244
}
229245

230246
/// Build the final VCode.
@@ -286,6 +302,7 @@ impl<I: VCodeInst> VCode<I> {
286302
liveouts: abi.liveouts(),
287303
vreg_types: vec![],
288304
insts: vec![],
305+
srclocs: vec![],
289306
entry: 0,
290307
block_ranges: vec![],
291308
block_succ_range: vec![],
@@ -349,14 +366,18 @@ impl<I: VCodeInst> VCode<I> {
349366
block_ranges(result.target_map.elems(), result.insns.len());
350367
let mut final_insns = vec![];
351368
let mut final_block_ranges = vec![(0, 0); self.num_blocks()];
369+
let mut final_srclocs = vec![];
352370

353371
for block in &self.final_block_order {
354372
let (start, end) = block_ranges[*block as usize];
355373
let final_start = final_insns.len() as InsnIndex;
356374

357375
if *block == self.entry {
358376
// Start with the prologue.
359-
final_insns.extend(self.abi.gen_prologue().into_iter());
377+
let prologue = self.abi.gen_prologue();
378+
let len = prologue.len();
379+
final_insns.extend(prologue.into_iter());
380+
final_srclocs.extend(iter::repeat(None).take(len));
360381
}
361382

362383
for i in start..end {
@@ -368,21 +389,34 @@ impl<I: VCodeInst> VCode<I> {
368389
continue;
369390
}
370391

392+
// Is there a srcloc associated with this insn? Look it up based on original
393+
// instruction index (if new insn corresponds to some original insn, i.e., is not
394+
// an inserted load/spill/move).
395+
let srcloc: Option<SourceLoc> = result.orig_insn_map[InstIx::new(i as u32)]
396+
.and_then(|orig_idx| self.srclocs[orig_idx.get() as usize]);
397+
371398
// Whenever encountering a return instruction, replace it
372399
// with the epilogue.
373400
let is_ret = insn.is_term() == MachTerminator::Ret;
374401
if is_ret {
375-
final_insns.extend(self.abi.gen_epilogue().into_iter());
402+
let epilogue = self.abi.gen_epilogue();
403+
let len = epilogue.len();
404+
final_insns.extend(epilogue.into_iter());
405+
final_srclocs.extend(iter::repeat(srcloc).take(len));
376406
} else {
377407
final_insns.push(insn.clone());
408+
final_srclocs.push(srcloc);
378409
}
379410
}
380411

381412
let final_end = final_insns.len() as InsnIndex;
382413
final_block_ranges[*block as usize] = (final_start, final_end);
383414
}
384415

416+
debug_assert!(final_insns.len() == final_srclocs.len());
417+
385418
self.insts = final_insns;
419+
self.srclocs = final_srclocs;
386420
self.block_ranges = final_block_ranges;
387421
}
388422

@@ -512,6 +546,7 @@ impl<I: VCodeInst> VCode<I> {
512546
let code_section = sections.get_section(code_idx);
513547

514548
let flags = self.abi.flags();
549+
let mut cur_srcloc: Option<SourceLoc> = None;
515550
for &block in &self.final_block_order {
516551
let new_offset = I::align_basic_block(code_section.cur_offset_from_start());
517552
while new_offset > code_section.cur_offset_from_start() {
@@ -523,8 +558,24 @@ impl<I: VCodeInst> VCode<I> {
523558

524559
let (start, end) = self.block_ranges[block as usize];
525560
for iix in start..end {
561+
let srcloc = self.srclocs[iix as usize];
562+
if srcloc != cur_srcloc {
563+
if cur_srcloc.is_some() {
564+
code_section.end_srcloc();
565+
}
566+
if srcloc.is_some() {
567+
code_section.start_srcloc(srcloc.unwrap());
568+
}
569+
cur_srcloc = srcloc;
570+
}
571+
526572
self.insts[iix as usize].emit(code_section, flags);
527573
}
574+
575+
if cur_srcloc.is_some() {
576+
code_section.end_srcloc();
577+
cur_srcloc = None;
578+
}
528579
}
529580

530581
sections

crates/environ/src/cranelift.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ use crate::compilation::{
9393
use crate::func_environ::{get_func_name, FuncEnvironment};
9494
use crate::{CacheConfig, FunctionBodyData, ModuleLocal, ModuleTranslation, Tunables};
9595
use cranelift_codegen::ir::{self, ExternalName};
96+
use cranelift_codegen::machinst::sections::MachSrcLoc;
9697
use cranelift_codegen::print_errors::pretty_error;
9798
use cranelift_codegen::{binemit, isa, Context};
9899
use cranelift_entity::PrimaryMap;
@@ -207,13 +208,24 @@ fn get_function_address_map<'data>(
207208
) -> FunctionAddressMap {
208209
let mut instructions = Vec::new();
209210

210-
let func = &context.func;
211-
let mut blocks = func.layout.blocks().collect::<Vec<_>>();
212-
blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase
211+
if let Some(ref mcr) = &context.mach_compile_result {
212+
// New-style backend: we have a `MachCompileResult` that will give us `MachSrcLoc` mapping
213+
// tuples.
214+
let mut srclocs = mcr.sections.get_srclocs();
215+
srclocs.sort_by_key(|mach_src_loc| mach_src_loc.start);
216+
for MachSrcLoc { start, end, loc } in srclocs.into_iter() {
217+
instructions.push(InstructionAddressMap {
218+
srcloc: loc,
219+
code_offset: start as usize,
220+
code_len: (end - start) as usize,
221+
});
222+
}
223+
} else {
224+
// Old-style backend: we need to traverse the instruction/encoding info in the function.
225+
let func = &context.func;
226+
let mut blocks = func.layout.blocks().collect::<Vec<_>>();
227+
blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase
213228

214-
// FIXME(#1523): New backend does not support debug info or instruction-address mapping
215-
// yet.
216-
if !isa.get_mach_backend().is_some() {
217229
let encinfo = isa.encoding_info();
218230
for block in blocks {
219231
for (offset, inst, size) in func.inst_offsets(block, &encinfo) {

0 commit comments

Comments
 (0)