From dd8e7df8ba5712c31ab257be538ff974d84913cc Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Mon, 19 Sep 2016 11:11:30 -0700 Subject: [PATCH] Add an internal MutableSourceMap trait. Use the SourceMap for mapping during parsing too. --- src/libreader/parser.rs | 125 ++++++++--------------------------- src/libreader/sourcemap.rs | 130 +++++++++++++++++++++++++++++++------ 2 files changed, 138 insertions(+), 117 deletions(-) diff --git a/src/libreader/parser.rs b/src/libreader/parser.rs index 68a5e72a4f..b2c9f40d6f 100644 --- a/src/libreader/parser.rs +++ b/src/libreader/parser.rs @@ -5,12 +5,11 @@ // // ====--------------------------------------------------------------------------------------====// -use std::collections::HashMap; use std::str::FromStr; use std::u32; use std::mem; -use cretonne::ir::{Function, Ebb, Inst, Opcode, Value, Type, FunctionName, StackSlot, - StackSlotData, JumpTable, JumpTableData}; +use cretonne::ir::{Function, Ebb, Inst, Opcode, Value, Type, FunctionName, StackSlotData, + JumpTable, JumpTableData}; use cretonne::ir::types::{VOID, Signature, ArgumentType, ArgumentExtension}; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE}; @@ -20,7 +19,7 @@ use testfile::{TestFile, Details, Comment}; use error::{Location, Error, Result}; use lexer::{self, Lexer, Token}; use testcommand::TestCommand; -use sourcemap; +use sourcemap::{SourceMap, MutableSourceMap}; /// Parse the entire `text` into a list of functions. /// @@ -65,10 +64,7 @@ pub struct Parser<'a> { // file by number. We need to map these numbers to real references. struct Context { function: Function, - stack_slots: HashMap, // ssNN - jump_tables: HashMap, // jtNN - ebbs: HashMap, // ebbNN - values: HashMap, // vNN, vxNN + map: SourceMap, // Remember the location of every instruction. inst_locs: Vec<(Inst, Location)>, @@ -78,36 +74,25 @@ impl Context { fn new(f: Function) -> Context { Context { function: f, - stack_slots: HashMap::new(), - jump_tables: HashMap::new(), - ebbs: HashMap::new(), - values: HashMap::new(), + map: SourceMap::new(), inst_locs: Vec::new(), } } // Allocate a new stack slot and add a mapping number -> StackSlot. fn add_ss(&mut self, number: u32, data: StackSlotData, loc: &Location) -> Result<()> { - if self.stack_slots.insert(number, self.function.stack_slots.push(data)).is_some() { - err!(loc, "duplicate stack slot: ss{}", number) - } else { - Ok(()) - } + self.map.def_ss(number, self.function.stack_slots.push(data), loc) } // Allocate a new jump table and add a mapping number -> JumpTable. fn add_jt(&mut self, number: u32, data: JumpTableData, loc: &Location) -> Result<()> { - if self.jump_tables.insert(number, self.function.jump_tables.push(data)).is_some() { - err!(loc, "duplicate jump table: jt{}", number) - } else { - Ok(()) - } + self.map.def_jt(number, self.function.jump_tables.push(data), loc) } // Resolve a reference to a jump table. fn get_jt(&self, number: u32, loc: &Location) -> Result { - match self.jump_tables.get(&number) { - Some(&jt) => Ok(jt), + match self.map.get_jt(number) { + Some(jt) => Ok(jt), None => err!(loc, "undefined jump table jt{}", number), } } @@ -116,20 +101,7 @@ impl Context { fn add_ebb(&mut self, src_ebb: Ebb, loc: &Location) -> Result { let ebb = self.function.dfg.make_ebb(); self.function.layout.append_ebb(ebb); - if self.ebbs.insert(src_ebb, ebb).is_some() { - err!(loc, "duplicate EBB: {}", src_ebb) - } else { - Ok(ebb) - } - } - - // Add a value mapping src_val -> data. - fn add_value(&mut self, src_val: Value, data: Value, loc: &Location) -> Result<()> { - if self.values.insert(src_val, data).is_some() { - err!(loc, "duplicate value: {}", src_val) - } else { - Ok(()) - } + self.map.def_ebb(src_ebb, ebb, loc).and(Ok(ebb)) } // Record the location of an instuction. @@ -140,41 +112,6 @@ impl Context { // The parser creates all instructions with Ebb and Value references using the source file // numbering. These references need to be rewritten after parsing is complete since forward // references are allowed. - - // Rewrite an Ebb reference. - fn rewrite_ebb(map: &HashMap, ebb: &mut Ebb, loc: &Location) -> Result<()> { - match map.get(ebb) { - Some(&new) => { - *ebb = new; - Ok(()) - } - None => err!(loc, "undefined reference: {}", ebb), - } - } - - // Rewrite a value reference. - fn rewrite_value(map: &HashMap, val: &mut Value, loc: &Location) -> Result<()> { - match map.get(val) { - Some(&new) => { - *val = new; - Ok(()) - } - None => err!(loc, "undefined reference: {}", val), - } - } - - // Rewrite a slice of value references. - fn rewrite_values(map: &HashMap, - vals: &mut [Value], - loc: &Location) - -> Result<()> { - for val in vals { - try!(Self::rewrite_value(map, val, loc)); - } - Ok(()) - } - - // Rewrite all EBB and value references in the function. fn rewrite_references(&mut self) -> Result<()> { for &(inst, loc) in &self.inst_locs { match self.function.dfg[inst] { @@ -189,7 +126,7 @@ impl Context { InstructionData::BinaryImmRev { ref mut arg, .. } | InstructionData::ExtractLane { ref mut arg, .. } | InstructionData::BranchTable { ref mut arg, .. } => { - try!(Self::rewrite_value(&self.values, arg, &loc)); + try!(self.map.rewrite_value(arg, &loc)); } InstructionData::Binary { ref mut args, .. } | @@ -197,30 +134,30 @@ impl Context { InstructionData::InsertLane { ref mut args, .. } | InstructionData::IntCompare { ref mut args, .. } | InstructionData::FloatCompare { ref mut args, .. } => { - try!(Self::rewrite_values(&self.values, args, &loc)); + try!(self.map.rewrite_values(args, &loc)); } InstructionData::Ternary { ref mut args, .. } => { - try!(Self::rewrite_values(&self.values, args, &loc)); + try!(self.map.rewrite_values(args, &loc)); } InstructionData::Jump { ref mut data, .. } => { - try!(Self::rewrite_ebb(&self.ebbs, &mut data.destination, &loc)); - try!(Self::rewrite_values(&self.values, &mut data.arguments, &loc)); + try!(self.map.rewrite_ebb(&mut data.destination, &loc)); + try!(self.map.rewrite_values(&mut data.arguments, &loc)); } InstructionData::Branch { ref mut data, .. } => { - try!(Self::rewrite_value(&self.values, &mut data.arg, &loc)); - try!(Self::rewrite_ebb(&self.ebbs, &mut data.destination, &loc)); - try!(Self::rewrite_values(&self.values, &mut data.arguments, &loc)); + try!(self.map.rewrite_value(&mut data.arg, &loc)); + try!(self.map.rewrite_ebb(&mut data.destination, &loc)); + try!(self.map.rewrite_values(&mut data.arguments, &loc)); } InstructionData::Call { ref mut data, .. } => { - try!(Self::rewrite_values(&self.values, &mut data.args, &loc)); + try!(self.map.rewrite_values(&mut data.args, &loc)); } InstructionData::Return { ref mut data, .. } => { - try!(Self::rewrite_values(&self.values, &mut data.args, &loc)); + try!(self.map.rewrite_values(&mut data.args, &loc)); } } } @@ -230,7 +167,7 @@ impl Context { for jt in self.function.jump_tables.keys() { for ebb in self.function.jump_tables[jt].as_mut_slice() { if *ebb != NO_EBB { - try!(Self::rewrite_ebb(&self.ebbs, ebb, &loc)); + try!(self.map.rewrite_ebb(ebb, &loc)); } } } @@ -512,7 +449,7 @@ impl<'a> Parser<'a> { let details = Details { location: location, comments: mem::replace(&mut self.comments, Vec::new()), - map: sourcemap::new(ctx.values, ctx.ebbs, ctx.stack_slots, ctx.jump_tables), + map: ctx.map, }; Ok((ctx.function, details)) @@ -777,7 +714,7 @@ impl<'a> Parser<'a> { let t = try!(self.match_type("expected EBB argument type")); // Allocate the EBB argument and add the mapping. let value = ctx.function.dfg.append_ebb_arg(ebb, t); - ctx.add_value(vx, value, &vx_location) + ctx.map.def_value(vx, value, &vx_location) } // Parse an instruction, append it to `ebb`. @@ -856,7 +793,7 @@ impl<'a> Parser<'a> { // Now map the source result values to the just created instruction results. // Pass a reference to `ctx.values` instead of `ctx` itself since the `Values` iterator // holds a reference to `ctx.function`. - self.add_values(&mut ctx.values, + self.add_values(&mut ctx.map, results.into_iter(), ctx.function.dfg.inst_results(inst)) } @@ -888,8 +825,8 @@ impl<'a> Parser<'a> { // layout of the blocks. let ctrl_src_value = inst_data.typevar_operand() .expect("Constraints <-> Format inconsistency"); - ctx.function.dfg.value_type(match ctx.values.get(&ctrl_src_value) { - Some(&v) => v, + ctx.function.dfg.value_type(match ctx.map.get_value(ctrl_src_value) { + Some(v) => v, None => { return err!(self.loc, "cannot determine type of operand {}", @@ -932,18 +869,12 @@ impl<'a> Parser<'a> { } // Add mappings for a list of source values to their corresponding new values. - fn add_values(&self, - values: &mut HashMap, - results: S, - new_results: V) - -> Result<()> + fn add_values(&self, map: &mut SourceMap, results: S, new_results: V) -> Result<()> where S: Iterator, V: Iterator { for (src, val) in results.zip(new_results) { - if values.insert(src, val).is_some() { - return err!(self.loc, "duplicate result value: {}", src); - } + try!(map.def_value(src, val, &self.loc)); } Ok(()) } diff --git a/src/libreader/sourcemap.rs b/src/libreader/sourcemap.rs index 9a601a3e39..090e438d54 100644 --- a/src/libreader/sourcemap.rs +++ b/src/libreader/sourcemap.rs @@ -10,6 +10,7 @@ use std::collections::HashMap; use cretonne::ir::{StackSlot, JumpTable, Ebb, Value}; use cretonne::ir::entities::AnyEntity; +use error::{Result, Location}; /// Mapping from source entity names to entity references that are valid in the parsed function. #[derive(Debug)] @@ -22,6 +23,26 @@ pub struct SourceMap { /// Read-only interface which is exposed outside the parser crate. impl SourceMap { + /// Look up a value entity by its source number. + pub fn get_value(&self, src: Value) -> Option { + self.values.get(&src).cloned() + } + + /// Look up a EBB entity by its source number. + pub fn get_ebb(&self, src: Ebb) -> Option { + self.ebbs.get(&src).cloned() + } + + /// Look up a stack slot entity by its source number. + pub fn get_ss(&self, src_num: u32) -> Option { + self.stack_slots.get(&src_num).cloned() + } + + /// Look up a jump table entity by its source number. + pub fn get_jt(&self, src_num: u32) -> Option { + self.jump_tables.get(&src_num).cloned() + } + /// Look up an entity by source name. /// Returns the entity reference corresponding to `name`, if it exists. pub fn lookup_str(&self, name: &str) -> Option { @@ -29,25 +50,51 @@ impl SourceMap { match ent { "v" => { Value::direct_with_number(num) - .and_then(|v| self.values.get(&v).cloned()) + .and_then(|v| self.get_value(v)) .map(AnyEntity::Value) } "vx" => { Value::table_with_number(num) - .and_then(|v| self.values.get(&v).cloned()) + .and_then(|v| self.get_value(v)) .map(AnyEntity::Value) } - "ebb" => { - Ebb::with_number(num) - .and_then(|e| self.ebbs.get(&e).cloned()) - .map(AnyEntity::Ebb) - } - "ss" => self.stack_slots.get(&num).cloned().map(AnyEntity::StackSlot), - "jt" => self.jump_tables.get(&num).cloned().map(AnyEntity::JumpTable), + "ebb" => Ebb::with_number(num).and_then(|e| self.get_ebb(e)).map(AnyEntity::Ebb), + "ss" => self.get_ss(num).map(AnyEntity::StackSlot), + "jt" => self.get_jt(num).map(AnyEntity::JumpTable), _ => None, } }) } + + /// Rewrite an Ebb reference. + pub fn rewrite_ebb(&self, ebb: &mut Ebb, loc: &Location) -> Result<()> { + match self.get_ebb(*ebb) { + Some(new) => { + *ebb = new; + Ok(()) + } + None => err!(loc, "undefined reference: {}", ebb), + } + } + + /// Rewrite a value reference. + pub fn rewrite_value(&self, val: &mut Value, loc: &Location) -> Result<()> { + match self.get_value(*val) { + Some(new) => { + *val = new; + Ok(()) + } + None => err!(loc, "undefined reference: {}", val), + } + } + + /// Rewrite a slice of value references. + pub fn rewrite_values(&self, vals: &mut [Value], loc: &Location) -> Result<()> { + for val in vals { + try!(self.rewrite_value(val, loc)); + } + Ok(()) + } } /// Get the number of decimal digits at the end of `s`. @@ -67,17 +114,60 @@ fn split_entity_name(name: &str) -> Option<(&str, u32)> { } } -/// Create a new SourceMap from all the individual mappings. -pub fn new(values: HashMap, - ebbs: HashMap, - stack_slots: HashMap, - jump_tables: HashMap) - -> SourceMap { - SourceMap { - values: values, - ebbs: ebbs, - stack_slots: stack_slots, - jump_tables: jump_tables, + +/// Interface for mutating a source map. +/// +/// This interface is provided for the parser itself, it is not made available outside the crate. +pub trait MutableSourceMap { + fn new() -> Self; + + /// Define a value mapping from the source name `src` to the final `entity`. + fn def_value(&mut self, src: Value, entity: Value, loc: &Location) -> Result<()>; + fn def_ebb(&mut self, src: Ebb, entity: Ebb, loc: &Location) -> Result<()>; + fn def_ss(&mut self, src_num: u32, entity: StackSlot, loc: &Location) -> Result<()>; + fn def_jt(&mut self, src_num: u32, entity: JumpTable, loc: &Location) -> Result<()>; +} + +impl MutableSourceMap for SourceMap { + fn new() -> SourceMap { + SourceMap { + values: HashMap::new(), + ebbs: HashMap::new(), + stack_slots: HashMap::new(), + jump_tables: HashMap::new(), + } + } + + fn def_value(&mut self, src: Value, entity: Value, loc: &Location) -> Result<()> { + if self.values.insert(src, entity).is_some() { + err!(loc, "duplicate value: {}", src) + } else { + Ok(()) + } + } + + fn def_ebb(&mut self, src: Ebb, entity: Ebb, loc: &Location) -> Result<()> { + if self.ebbs.insert(src, entity).is_some() { + err!(loc, "duplicate EBB: {}", src) + } else { + Ok(()) + } + } + + fn def_ss(&mut self, src_num: u32, entity: StackSlot, loc: &Location) -> Result<()> { + if self.stack_slots.insert(src_num, entity).is_some() { + err!(loc, "duplicate stack slot: ss{}", src_num) + } else { + Ok(()) + } + } + + fn def_jt(&mut self, src_num: u32, entity: JumpTable, loc: &Location) -> Result<()> { + if self.jump_tables.insert(src_num, entity).is_some() { + err!(loc, "duplicate jump table: jt{}", src_num) + } else { + Ok(()) + } } }