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