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, Heap, JumpTable, SigRef, StackSlot, 14 Table, 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 heap entity. 53 pub fn contains_heap(&self, heap: Heap) -> bool { 54 self.locations.contains_key(&heap.into()) 55 } 56 57 /// Look up a table entity. 58 pub fn contains_table(&self, table: Table) -> bool { 59 self.locations.contains_key(&table.into()) 60 } 61 62 /// Look up a signature entity. 63 pub fn contains_sig(&self, sig: SigRef) -> bool { 64 self.locations.contains_key(&sig.into()) 65 } 66 67 /// Look up a function entity. 68 pub fn contains_fn(&self, fn_: FuncRef) -> bool { 69 self.locations.contains_key(&fn_.into()) 70 } 71 72 /// Look up a jump table entity. 73 pub fn contains_jt(&self, jt: JumpTable) -> bool { 74 self.locations.contains_key(&jt.into()) 75 } 76 77 /// Look up a constant entity. 78 pub fn contains_constant(&self, c: Constant) -> bool { 79 self.locations.contains_key(&c.into()) 80 } 81 82 /// Look up an entity by source name. 83 /// Returns the entity reference corresponding to `name`, if it exists. 84 pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> { 85 split_entity_name(name).and_then(|(ent, num)| match ent { 86 "v" => Value::with_number(num).and_then(|v| { 87 if !self.contains_value(v) { 88 None 89 } else { 90 Some(v.into()) 91 } 92 }), 93 "block" => Block::with_number(num).and_then(|block| { 94 if !self.contains_block(block) { 95 None 96 } else { 97 Some(block.into()) 98 } 99 }), 100 "ss" => StackSlot::with_number(num).and_then(|ss| { 101 if !self.contains_ss(ss) { 102 None 103 } else { 104 Some(ss.into()) 105 } 106 }), 107 "gv" => GlobalValue::with_number(num).and_then(|gv| { 108 if !self.contains_gv(gv) { 109 None 110 } else { 111 Some(gv.into()) 112 } 113 }), 114 "heap" => Heap::with_number(num).and_then(|heap| { 115 if !self.contains_heap(heap) { 116 None 117 } else { 118 Some(heap.into()) 119 } 120 }), 121 "table" => Table::with_number(num).and_then(|table| { 122 if !self.contains_table(table) { 123 None 124 } else { 125 Some(table.into()) 126 } 127 }), 128 "sig" => SigRef::with_number(num).and_then(|sig| { 129 if !self.contains_sig(sig) { 130 None 131 } else { 132 Some(sig.into()) 133 } 134 }), 135 "fn" => FuncRef::with_number(num).and_then(|fn_| { 136 if !self.contains_fn(fn_) { 137 None 138 } else { 139 Some(fn_.into()) 140 } 141 }), 142 "jt" => JumpTable::with_number(num).and_then(|jt| { 143 if !self.contains_jt(jt) { 144 None 145 } else { 146 Some(jt.into()) 147 } 148 }), 149 _ => None, 150 }) 151 } 152 153 /// Get the source location where an entity was defined. 154 pub fn location(&self, entity: AnyEntity) -> Option<Location> { 155 self.locations.get(&entity).cloned() 156 } 157 } 158 159 impl SourceMap { 160 /// Create a new empty `SourceMap`. 161 pub fn new() -> Self { 162 Self { 163 locations: HashMap::new(), 164 } 165 } 166 167 /// Define the value `entity`. 168 pub fn def_value(&mut self, entity: Value, loc: Location) -> ParseResult<()> { 169 self.def_entity(entity.into(), loc) 170 } 171 172 /// Define the block `entity`. 173 pub fn def_block(&mut self, entity: Block, loc: Location) -> ParseResult<()> { 174 self.def_entity(entity.into(), loc) 175 } 176 177 /// Define the stack slot `entity`. 178 pub fn def_ss(&mut self, entity: StackSlot, loc: Location) -> ParseResult<()> { 179 self.def_entity(entity.into(), loc) 180 } 181 182 /// Define the dynamic stack slot `entity`. 183 pub fn def_dss(&mut self, entity: DynamicStackSlot, loc: Location) -> ParseResult<()> { 184 self.def_entity(entity.into(), loc) 185 } 186 187 /// Define the dynamic type `entity`. 188 pub fn def_dt(&mut self, entity: DynamicType, loc: Location) -> ParseResult<()> { 189 self.def_entity(entity.into(), loc) 190 } 191 192 /// Define the global value `entity`. 193 pub fn def_gv(&mut self, entity: GlobalValue, loc: Location) -> ParseResult<()> { 194 self.def_entity(entity.into(), loc) 195 } 196 197 /// Define the heap `entity`. 198 pub fn def_heap(&mut self, entity: Heap, loc: Location) -> ParseResult<()> { 199 self.def_entity(entity.into(), loc) 200 } 201 202 /// Define the table `entity`. 203 pub fn def_table(&mut self, entity: Table, loc: Location) -> ParseResult<()> { 204 self.def_entity(entity.into(), loc) 205 } 206 207 /// Define the signature `entity`. 208 pub fn def_sig(&mut self, entity: SigRef, loc: Location) -> ParseResult<()> { 209 self.def_entity(entity.into(), loc) 210 } 211 212 /// Define the external function `entity`. 213 pub fn def_fn(&mut self, entity: FuncRef, loc: Location) -> ParseResult<()> { 214 self.def_entity(entity.into(), loc) 215 } 216 217 /// Define the jump table `entity`. 218 pub fn def_jt(&mut self, entity: JumpTable, loc: Location) -> ParseResult<()> { 219 self.def_entity(entity.into(), loc) 220 } 221 222 /// Define the jump table `entity`. 223 pub fn def_constant(&mut self, entity: Constant, loc: Location) -> ParseResult<()> { 224 self.def_entity(entity.into(), loc) 225 } 226 227 /// Define an entity. This can be used for instructions whose numbers never 228 /// appear in source, or implicitly defined signatures. 229 pub fn def_entity(&mut self, entity: AnyEntity, loc: Location) -> ParseResult<()> { 230 if self.locations.insert(entity, loc).is_some() { 231 err!(loc, "duplicate entity: {}", entity) 232 } else { 233 Ok(()) 234 } 235 } 236 } 237 238 #[cfg(test)] 239 mod tests { 240 use crate::{parse_test, ParseOptions}; 241 242 #[test] 243 fn details() { 244 let tf = parse_test( 245 "function %detail() { 246 ss10 = explicit_slot 13 247 jt10 = jump_table [block0] 248 block0(v4: i32, v7: i32): 249 v10 = iadd v4, v7 250 }", 251 ParseOptions::default(), 252 ) 253 .unwrap(); 254 let map = &tf.functions[0].1.map; 255 256 assert_eq!(map.lookup_str("v0"), None); 257 assert_eq!(map.lookup_str("ss1"), None); 258 assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss10"); 259 assert_eq!(map.lookup_str("jt10").unwrap().to_string(), "jt10"); 260 assert_eq!(map.lookup_str("block0").unwrap().to_string(), "block0"); 261 assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v4"); 262 assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v7"); 263 assert_eq!(map.lookup_str("v10").unwrap().to_string(), "v10"); 264 } 265 } 266