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