Skip to content

Commit

Permalink
MachInst backend: pass through SourceLoc information.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
cfallin committed Apr 24, 2020
1 parent 74eda80 commit b691770
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 19 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cranelift/codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ gimli = { version = "0.20.0", default-features = false, features = ["write"], op
smallvec = { version = "1.0.0" }
thiserror = "1.0.4"
byteorder = { version = "1.3.2", default-features = false }
regalloc = "0.0.17"
regalloc = "0.0.18"
# It is a goal of the cranelift-codegen crate to have minimal external dependencies.
# Please don't add any unless they are essential to the task of creating binary
# machine code. Integration tests that need external dependencies can be
Expand Down
3 changes: 3 additions & 0 deletions cranelift/codegen/src/machinst/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
"lower_branch_group: targets = {:?} branches = {:?}",
targets, branches
);
self.vcode.set_srcloc(self.srcloc(branches[0]));
backend.lower_branch_group(
&mut self,
&branches[..],
Expand All @@ -361,6 +362,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
let num_uses = self.num_uses[inst];
let side_effect = has_side_effect(self.f, inst);
if side_effect || num_uses > 0 {
self.vcode.set_srcloc(self.srcloc(inst));
backend.lower(&mut self, inst);
self.vcode.end_ir_inst();
} else {
Expand Down Expand Up @@ -389,6 +391,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
"lower_branch_group: targets = {:?} branches = {:?}",
targets, branches
);
self.vcode.set_srcloc(self.srcloc(branches[0]));
backend.lower_branch_group(&mut self, &branches[..], &targets[..], fallthrough);
self.vcode.end_ir_inst();
branches.clear();
Expand Down
1 change: 0 additions & 1 deletion cranelift/codegen/src/machinst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@
//! ```

use crate::binemit::{CodeInfo, CodeOffset};
use crate::entity::SecondaryMap;
use crate::ir::condcodes::IntCC;
use crate::ir::{Function, Type};
use crate::result::CodegenResult;
Expand Down
108 changes: 107 additions & 1 deletion cranelift/codegen/src/machinst/sections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ impl MachSections {
sink.end_codegen();
}

/// Get a list of source location mapping tuples in sorted-by-start-offset order.
pub fn get_srclocs_sorted<'a>(&'a self) -> MachSectionsSrcLocs<'a> {
MachSectionsSrcLocs::new(&self.sections)
}

/// Get the total required size for these sections.
pub fn total_size(&self) -> CodeOffset {
if self.sections.len() == 0 {
Expand All @@ -90,6 +95,58 @@ impl MachSections {
}
}

/// An iterator over the srclocs in each section.
/// Returns MachSrcLocs in an order sorted by start location.
pub struct MachSectionsSrcLocs<'a> {
sections: &'a [MachSection],
cur_section: usize,
cur_srcloc: usize,
// For validation:
last_offset: CodeOffset,
}

impl<'a> MachSectionsSrcLocs<'a> {
fn new(sections: &'a [MachSection]) -> MachSectionsSrcLocs<'a> {
MachSectionsSrcLocs {
sections,
cur_section: 0,
cur_srcloc: 0,
last_offset: 0,
}
}
}

impl<'a> Iterator for MachSectionsSrcLocs<'a> {
type Item = &'a MachSrcLoc;

fn next(&mut self) -> Option<&'a MachSrcLoc> {
// We simply iterate through sections and srcloc records in order. This produces a
// sorted order naturally because sections are in starting-offset-order, and srclocs
// are produced as a section is emitted into, so are in order as well.

// If we're out of sections, we're done.
if self.cur_section >= self.sections.len() {
return None;
}

// Otherwise, make sure we have a srcloc in the current section left to return, and
// advance to the next section if not. Done if we run out of sections.
while self.cur_srcloc >= self.sections[self.cur_section].srclocs.len() {
self.cur_srcloc = 0;
self.cur_section += 1;
if self.cur_section >= self.sections.len() {
return None;
}
}

let loc = &self.sections[self.cur_section].srclocs[self.cur_srcloc];
self.cur_srcloc += 1;
debug_assert!(loc.start >= self.last_offset);
self.last_offset = loc.start;
Some(loc)
}
}

/// An abstraction over MachSection and MachSectionSize: some
/// receiver of section data.
pub trait MachSectionOutput {
Expand Down Expand Up @@ -143,6 +200,12 @@ pub trait MachSectionOutput {
/// Add a call return address record at the current offset.
fn add_call_site(&mut self, loc: SourceLoc, opcode: Opcode);

/// Start the output for the given source-location at the current offset.
fn start_srcloc(&mut self, loc: SourceLoc);

/// End the output for the previously-given source-location at the current offset.
fn end_srcloc(&mut self);

/// Align up to the given alignment.
fn align_to(&mut self, align_to: CodeOffset) {
assert!(align_to.is_power_of_two());
Expand All @@ -168,8 +231,13 @@ pub struct MachSection {
pub relocs: Vec<MachReloc>,
/// Any trap records referring to this section.
pub traps: Vec<MachTrap>,
/// Any call site record referring to this section.
/// Any call site records referring to this section.
pub call_sites: Vec<MachCallSite>,
/// Any source location mappings referring to this section.
pub srclocs: Vec<MachSrcLoc>,
/// The current source location in progress (after `start_srcloc()` and before `end_srcloc()`).
/// This is a (start_offset, src_loc) tuple.
pub cur_srcloc: Option<(CodeOffset, SourceLoc)>,
}

impl MachSection {
Expand All @@ -182,6 +250,8 @@ impl MachSection {
relocs: vec![],
traps: vec![],
call_sites: vec![],
srclocs: vec![],
cur_srcloc: None,
}
}

Expand Down Expand Up @@ -266,6 +336,23 @@ impl MachSectionOutput for MachSection {
opcode,
});
}

fn start_srcloc(&mut self, loc: SourceLoc) {
self.cur_srcloc = Some((self.cur_offset_from_start(), loc));
}

fn end_srcloc(&mut self) {
let (start, loc) = self
.cur_srcloc
.take()
.expect("end_srcloc() called without start_srcloc()");
let end = self.cur_offset_from_start();
// Skip zero-length extends.
debug_assert!(end >= start);
if end > start {
self.srclocs.push(MachSrcLoc { start, end, loc });
}
}
}

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

fn add_call_site(&mut self, _: SourceLoc, _: Opcode) {}

fn start_srcloc(&mut self, _: SourceLoc) {}

fn end_srcloc(&mut self) {}
}

/// A relocation resulting from a compilation.
Expand Down Expand Up @@ -352,3 +443,18 @@ pub struct MachCallSite {
/// The call's opcode.
pub opcode: Opcode,
}

/// A source-location mapping resulting from a compilation.
#[derive(Clone, Debug)]
pub struct MachSrcLoc {
/// The start of the region of code corresponding to a source location.
/// This is relative to the start of the function, not to the start of the
/// section.
pub start: CodeOffset,
/// The end of the region of code corresponding to a source location.
/// This is relative to the start of the section, not to the start of the
/// section.
pub end: CodeOffset,
/// The source location.
pub loc: SourceLoc,
}
Loading

0 comments on commit b691770

Please sign in to comment.