diff --git a/lib/frontend/src/frontend.rs b/lib/frontend/src/frontend.rs index 91c2b4c4e6..376f798dd2 100644 --- a/lib/frontend/src/frontend.rs +++ b/lib/frontend/src/frontend.rs @@ -1,5 +1,6 @@ //! A frontend for building Cretonne IL from other languages. use cretonne::cursor::{Cursor, FuncCursor}; +use cretonne::ir; use cretonne::ir::{Ebb, Type, Value, Function, Inst, JumpTable, StackSlot, JumpTableData, StackSlotData, DataFlowGraph, InstructionData, ExtFuncData, FuncRef, SigRef, Signature, InstBuilderBase, GlobalVarData, GlobalVar, HeapData, Heap}; @@ -30,6 +31,9 @@ where /// This field is public so the function can be re-borrowed. pub func: &'a mut Function, + /// Source location to assign to all new instructions. + srcloc: ir::SourceLoc, + builder: &'a mut ILBuilder, position: Position, 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()); self.builder.func.dfg.make_inst_results(inst, ctrl_typevar); self.builder.func.layout.append_inst(inst, self.ebb); + self.builder.func.srclocs[inst] = self.builder.srcloc; + if data.opcode().is_branch() { match data.branch_destination() { Some(dest_ebb) => { @@ -179,13 +185,13 @@ impl<'short, 'long, Variable> InstBuilderBase<'short> for FuncInstBuilder<'short /// `create_ebb`) whose properties are: /// /// - 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. /// /// 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 /// 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 function. @@ -215,6 +221,7 @@ where builder.clear(); FunctionBuilder { func: func, + srcloc: Default::default(), builder: builder, position: Position { 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. pub fn create_ebb(&mut self) -> Ebb { let ebb = self.func.dfg.make_ebb(); @@ -386,7 +398,9 @@ where /// need to know about `FunctionBuilder` at all. pub fn cursor<'f>(&'f mut self) -> FuncCursor<'f> { 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 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. pub fn ebb_args(&self, ebb: Ebb) -> &[Value] { self.func.dfg.ebb_args(ebb) diff --git a/lib/wasm/src/func_translator.rs b/lib/wasm/src/func_translator.rs index 9a43083461..a5abdf382c 100644 --- a/lib/wasm/src/func_translator.rs +++ b/lib/wasm/src/func_translator.rs @@ -139,6 +139,7 @@ fn parse_local_decls( let mut locals_total = 0; for _ in 0..local_count { + builder.set_srcloc(cur_srcloc(reader)); let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|_| { CtonError::InvalidInput })?; @@ -199,6 +200,7 @@ fn parse_function_body( // Keep going until the final `End` operator which pops the outermost block. while !state.control_stack.is_empty() { + builder.set_srcloc(cur_srcloc(&reader)); let op = reader.read_operator().map_err(|_| CtonError::InvalidInput)?; translate_operator(&op, builder, state, environ); } @@ -218,6 +220,15 @@ fn parse_function_body( 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)] mod tests { use cretonne::{ir, Context};