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