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:
@@ -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)
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
Reference in New Issue
Block a user