Assign source locations when translating WebAssembly to Cretonne.

The source locations are byte code offsets relative to the beginning of
the function.
This commit is contained in:
Jakob Stoklund Olesen
2017-09-21 08:12:53 -07:00
parent 4d4da2dc60
commit 85e4e9f511
2 changed files with 29 additions and 4 deletions

View File

@@ -1,5 +1,6 @@
//! A frontend for building Cretonne IL from other languages. //! A frontend for building Cretonne IL from other languages.
use cretonne::cursor::{Cursor, FuncCursor}; use cretonne::cursor::{Cursor, FuncCursor};
use cretonne::ir;
use cretonne::ir::{Ebb, Type, Value, Function, Inst, JumpTable, StackSlot, JumpTableData, use cretonne::ir::{Ebb, Type, Value, Function, Inst, JumpTable, StackSlot, JumpTableData,
StackSlotData, DataFlowGraph, InstructionData, ExtFuncData, FuncRef, SigRef, StackSlotData, DataFlowGraph, InstructionData, ExtFuncData, FuncRef, SigRef,
Signature, InstBuilderBase, GlobalVarData, GlobalVar, HeapData, Heap}; Signature, InstBuilderBase, GlobalVarData, GlobalVar, HeapData, Heap};
@@ -30,6 +31,9 @@ where
/// This field is public so the function can be re-borrowed. /// This field is public so the function can be re-borrowed.
pub func: &'a mut Function, pub func: &'a mut Function,
/// Source location to assign to all new instructions.
srcloc: ir::SourceLoc,
builder: &'a mut ILBuilder<Variable>, builder: &'a mut ILBuilder<Variable>,
position: Position, position: Position,
pristine: bool, pristine: bool,
@@ -117,6 +121,8 @@ impl<'short, 'long, Variable> InstBuilderBase<'short> for FuncInstBuilder<'short
let inst = self.builder.func.dfg.make_inst(data.clone()); let inst = self.builder.func.dfg.make_inst(data.clone());
self.builder.func.dfg.make_inst_results(inst, ctrl_typevar); self.builder.func.dfg.make_inst_results(inst, ctrl_typevar);
self.builder.func.layout.append_inst(inst, self.ebb); self.builder.func.layout.append_inst(inst, self.ebb);
self.builder.func.srclocs[inst] = self.builder.srcloc;
if data.opcode().is_branch() { if data.opcode().is_branch() {
match data.branch_destination() { match data.branch_destination() {
Some(dest_ebb) => { Some(dest_ebb) => {
@@ -179,13 +185,13 @@ impl<'short, 'long, Variable> InstBuilderBase<'short> for FuncInstBuilder<'short
/// `create_ebb`) whose properties are: /// `create_ebb`) whose properties are:
/// ///
/// - branch and jump instructions can only point at the top of extended blocks; /// - branch and jump instructions can only point at the top of extended blocks;
/// - the last instruction of each block is a terminator instruction which has no natural sucessor, /// - the last instruction of each block is a terminator instruction which has no natural successor,
/// and those instructions can only appear at the end of extended blocks. /// and those instructions can only appear at the end of extended blocks.
/// ///
/// The parameters of Cretonne IL instructions are Cretonne IL values, which can only be created /// The parameters of Cretonne IL instructions are Cretonne IL values, which can only be created
/// as results of other Cretonne IL instructions. To be able to create variables redefined multiple /// as results of other Cretonne IL instructions. To be able to create variables redefined multiple
/// times in your program, use the `def_var` and `use_var` command, that will maintain the /// times in your program, use the `def_var` and `use_var` command, that will maintain the
/// correspondance between your variables and Cretonne IL SSA values. /// correspondence between your variables and Cretonne IL SSA values.
/// ///
/// The first block for which you call `switch_to_block` will be assumed to be the beginning of /// The first block for which you call `switch_to_block` will be assumed to be the beginning of
/// the function. /// the function.
@@ -215,6 +221,7 @@ where
builder.clear(); builder.clear();
FunctionBuilder { FunctionBuilder {
func: func, func: func,
srcloc: Default::default(),
builder: builder, builder: builder,
position: Position { position: Position {
ebb: Ebb::new(0), ebb: Ebb::new(0),
@@ -224,6 +231,11 @@ where
} }
} }
/// Set the source location that should be assigned to all new instructions.
pub fn set_srcloc(&mut self, srcloc: ir::SourceLoc) {
self.srcloc = srcloc;
}
/// Creates a new `Ebb` for the function and returns its reference. /// Creates a new `Ebb` for the function and returns its reference.
pub fn create_ebb(&mut self) -> Ebb { pub fn create_ebb(&mut self) -> Ebb {
let ebb = self.func.dfg.make_ebb(); let ebb = self.func.dfg.make_ebb();
@@ -386,7 +398,9 @@ where
/// need to know about `FunctionBuilder` at all. /// need to know about `FunctionBuilder` at all.
pub fn cursor<'f>(&'f mut self) -> FuncCursor<'f> { pub fn cursor<'f>(&'f mut self) -> FuncCursor<'f> {
self.ensure_inserted_ebb(); self.ensure_inserted_ebb();
FuncCursor::new(self.func).at_bottom(self.position.ebb) FuncCursor::new(self.func)
.with_srcloc(self.srcloc)
.at_bottom(self.position.ebb)
} }
} }
@@ -399,7 +413,7 @@ impl<'a, Variable> FunctionBuilder<'a, Variable>
where where
Variable: EntityRef + Default, Variable: EntityRef + Default,
{ {
/// Retrieves all the arguments for an `Ebb` currently infered from the jump instructions /// Retrieves all the arguments for an `Ebb` currently inferred from the jump instructions
/// inserted that target it and the SSA construction. /// inserted that target it and the SSA construction.
pub fn ebb_args(&self, ebb: Ebb) -> &[Value] { pub fn ebb_args(&self, ebb: Ebb) -> &[Value] {
self.func.dfg.ebb_args(ebb) self.func.dfg.ebb_args(ebb)

View File

@@ -139,6 +139,7 @@ fn parse_local_decls(
let mut locals_total = 0; let mut locals_total = 0;
for _ in 0..local_count { for _ in 0..local_count {
builder.set_srcloc(cur_srcloc(reader));
let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|_| { let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|_| {
CtonError::InvalidInput CtonError::InvalidInput
})?; })?;
@@ -199,6 +200,7 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
// Keep going until the final `End` operator which pops the outermost block. // Keep going until the final `End` operator which pops the outermost block.
while !state.control_stack.is_empty() { while !state.control_stack.is_empty() {
builder.set_srcloc(cur_srcloc(&reader));
let op = reader.read_operator().map_err(|_| CtonError::InvalidInput)?; let op = reader.read_operator().map_err(|_| CtonError::InvalidInput)?;
translate_operator(&op, builder, state, environ); translate_operator(&op, builder, state, environ);
} }
@@ -218,6 +220,15 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
Ok(()) Ok(())
} }
/// Get the current source location from a reader.
fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
// We record source locations as byte code offsets relative to the beginning of the function.
// This will wrap around of a single function's byte code is larger than 4 GB, but a) the
// WebAssembly format doesn't allow for that, and b) that would hit other Cretonne
// implementation limits anyway.
ir::SourceLoc::new(reader.current_position() as u32)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use cretonne::{ir, Context}; use cretonne::{ir, Context};