1 //! Source map associating entities with their source locations. 2 //! 3 //! When the parser reads in a source file, it records the locations of the 4 //! definitions of entities like instructions, blocks, and values. 5 //! 6 //! The `SourceMap` struct defined in this module makes this mapping available 7 //! to parser clients. 8 9 use crate::error::{Location, ParseResult}; 10 use crate::lexer::split_entity_name; 11 use cranelift_codegen::ir::entities::{AnyEntity, DynamicType}; 12 use cranelift_codegen::ir::{ 13 Block, Constant, DynamicStackSlot, FuncRef, GlobalValue, JumpTable, SigRef, StackSlot, Table, 14 Value, 15 }; 16 use std::collections::HashMap; 17 18 /// Mapping from entity names to source locations. 19 #[derive(Debug, Default)] 20 pub struct SourceMap { 21 // Store locations for entities, including instructions. 22 locations: HashMap<AnyEntity, Location>, 23 } 24 25 /// Read-only interface which is exposed outside the parser crate. 26 impl SourceMap { 27 /// Look up a value entity. 28 pub fn contains_value(&self, v: Value) -> bool { 29 self.locations.contains_key(&v.into()) 30 } 31 32 /// Look up a block entity. 33 pub fn contains_block(&self, block: Block) -> bool { 34 self.locations.contains_key(&block.into()) 35 } 36 37 /// Look up a stack slot entity. 38 pub fn contains_ss(&self, ss: StackSlot) -> bool { 39 self.locations.contains_key(&ss.into()) 40 } 41 42 /// Look up a dynamic stack slot entity. 43 pub fn contains_dss(&self, dss: DynamicStackSlot) -> bool { 44 self.locations.contains_key(&dss.into()) 45 } 46 47 /// Look up a global value entity. 48 pub fn contains_gv(&self, gv: GlobalValue) -> bool { 49 self.locations.contains_key(&gv.into()) 50 } 51 52 /// Look up a table entity. 53 pub fn contains_table(&self, table: Table) -> bool { 54 self.locations.contains_key(&table.into()) 55 } 56 57 /// Look up a signature entity. 58 pub fn contains_sig(&self, sig: SigRef) -> bool { 59 self.locations.contains_key(&sig.into()) 60 } 61 62 /// Look up a function entity. 63 pub fn contains_fn(&self, fn_: FuncRef) -> bool { 64 self.locations.contains_key(&fn_.into()) 65 } 66 67 /// Look up a jump table entity. 68 pub fn contains_jt(&self, jt: JumpTable) -> bool { 69 self.locations.contains_key(&jt.into()) 70 } 71 72 /// Look up a constant entity. 73 pub fn contains_constant(&self, c: Constant) -> bool { 74 self.locations.contains_key(&c.into()) 75 } 76 77 /// Look up an entity by source name. 78 /// Returns the entity reference corresponding to `name`, if it exists. 79 pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> { 80 split_entity_name(name).and_then(|(ent, num)| match ent { 81 "v" => Value::with_number(num).and_then(|v| { 82 if !self.contains_value(v) { 83 None 84 } else { 85 Some(v.into()) 86 } 87 }), 88 "block" => Block::with_number(num).and_then(|block| { 89 if !self.contains_block(block) { 90 None 91 } else { 92 Some(block.into()) 93 } 94 }), 95 "ss" => StackSlot::with_number(num).and_then(|ss| { 96 if !self.contains_ss(ss) { 97 None 98 } else { 99 Some(ss.into()) 100 } 101 }), 102 "gv" => GlobalValue::with_number(num).and_then(|gv| { 103 if !self.contains_gv(gv) { 104 None 105 } else { 106 Some(gv.into()) 107 } 108 }), 109 "table" => Table::with_number(num).and_then(|table| { 110 if !self.contains_table(table) { 111 None 112 } else { 113 Some(table.into()) 114 } 115 }), 116 "sig" => SigRef::with_number(num).and_then(|sig| { 117 if !self.contains_sig(sig) { 118 None 119 } else { 120 Some(sig.into()) 121 } 122 }), 123 "fn" => FuncRef::with_number(num).and_then(|fn_| { 124 if !self.contains_fn(fn_) { 125 None 126 } else { 127 Some(fn_.into()) 128 } 129 }), 130 "jt" => JumpTable::with_number(num).and_then(|jt| { 131 if !self.contains_jt(jt) { 132 None 133 } else { 134 Some(jt.into()) 135 } 136 }), 137 _ => None, 138 }) 139 } 140 141 /// Get the source location where an entity was defined. 142 pub fn location(&self, entity: AnyEntity) -> Option<Location> { 143 self.locations.get(&entity).cloned() 144 } 145 } 146 147 impl SourceMap { 148 /// Create a new empty `SourceMap`. 149 pub fn new() -> Self { 150 Self { 151 locations: HashMap::new(), 152 } 153 } 154 155 /// Define the value `entity`. 156 pub fn def_value(&mut self, entity: Value, loc: Location) -> ParseResult<()> { 157 self.def_entity(entity.into(), loc) 158 } 159 160 /// Define the block `entity`. 161 pub fn def_block(&mut self, entity: Block, loc: Location) -> ParseResult<()> { 162 self.def_entity(entity.into(), loc) 163 } 164 165 /// Define the stack slot `entity`. 166 pub fn def_ss(&mut self, entity: StackSlot, loc: Location) -> ParseResult<()> { 167 self.def_entity(entity.into(), loc) 168 } 169 170 /// Define the dynamic stack slot `entity`. 171 pub fn def_dss(&mut self, entity: DynamicStackSlot, loc: Location) -> ParseResult<()> { 172 self.def_entity(entity.into(), loc) 173 } 174 175 /// Define the dynamic type `entity`. 176 pub fn def_dt(&mut self, entity: DynamicType, loc: Location) -> ParseResult<()> { 177 self.def_entity(entity.into(), loc) 178 } 179 180 /// Define the global value `entity`. 181 pub fn def_gv(&mut self, entity: GlobalValue, loc: Location) -> ParseResult<()> { 182 self.def_entity(entity.into(), loc) 183 } 184 185 /// Define the table `entity`. 186 pub fn def_table(&mut self, entity: Table, loc: Location) -> ParseResult<()> { 187 self.def_entity(entity.into(), loc) 188 } 189 190 /// Define the signature `entity`. 191 pub fn def_sig(&mut self, entity: SigRef, loc: Location) -> ParseResult<()> { 192 self.def_entity(entity.into(), loc) 193 } 194 195 /// Define the external function `entity`. 196 pub fn def_fn(&mut self, entity: FuncRef, loc: Location) -> ParseResult<()> { 197 self.def_entity(entity.into(), loc) 198 } 199 200 /// Define the jump table `entity`. 201 pub fn def_jt(&mut self, entity: JumpTable, loc: Location) -> ParseResult<()> { 202 self.def_entity(entity.into(), loc) 203 } 204 205 /// Define the jump table `entity`. 206 pub fn def_constant(&mut self, entity: Constant, loc: Location) -> ParseResult<()> { 207 self.def_entity(entity.into(), loc) 208 } 209 210 /// Define an entity. This can be used for instructions whose numbers never 211 /// appear in source, or implicitly defined signatures. 212 pub fn def_entity(&mut self, entity: AnyEntity, loc: Location) -> ParseResult<()> { 213 if self.locations.insert(entity, loc).is_some() { 214 err!(loc, "duplicate entity: {}", entity) 215 } else { 216 Ok(()) 217 } 218 } 219 } 220 221 #[cfg(test)] 222 mod tests { 223 use crate::{parse_test, ParseOptions}; 224 225 #[test] 226 fn details() { 227 let tf = parse_test( 228 "function %detail() { 229 ss10 = explicit_slot 13 230 block0(v4: i32, v7: i32): 231 v10 = iadd v4, v7 232 }", 233 ParseOptions::default(), 234 ) 235 .unwrap(); 236 let map = &tf.functions[0].1.map; 237 238 assert_eq!(map.lookup_str("v0"), None); 239 assert_eq!(map.lookup_str("ss1"), None); 240 assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss10"); 241 assert_eq!(map.lookup_str("block0").unwrap().to_string(), "block0"); 242 assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v4"); 243 assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v7"); 244 assert_eq!(map.lookup_str("v10").unwrap().to_string(), "v10"); 245 } 246 } 247