1747ad3c4Slazypassion //! Source map associating entities with their source locations.
2747ad3c4Slazypassion //!
3747ad3c4Slazypassion //! When the parser reads in a source file, it records the locations of the
4832666c4SRyan Hunt //! definitions of entities like instructions, blocks, and values.
5747ad3c4Slazypassion //!
6747ad3c4Slazypassion //! The `SourceMap` struct defined in this module makes this mapping available
7747ad3c4Slazypassion //! to parser clients.
8747ad3c4Slazypassion 
9747ad3c4Slazypassion use crate::error::{Location, ParseResult};
10747ad3c4Slazypassion use crate::lexer::split_entity_name;
119c43749dSSam Parker use cranelift_codegen::ir::entities::{AnyEntity, DynamicType};
12747ad3c4Slazypassion use cranelift_codegen::ir::{
13*2f7dbd61SChris Fallin     Block, Constant, DynamicStackSlot, FuncRef, GlobalValue, JumpTable, SigRef, StackSlot, Value,
14747ad3c4Slazypassion };
15747ad3c4Slazypassion use std::collections::HashMap;
16747ad3c4Slazypassion 
17747ad3c4Slazypassion /// Mapping from entity names to source locations.
18747ad3c4Slazypassion #[derive(Debug, Default)]
19747ad3c4Slazypassion pub struct SourceMap {
20747ad3c4Slazypassion     // Store locations for entities, including instructions.
21747ad3c4Slazypassion     locations: HashMap<AnyEntity, Location>,
22747ad3c4Slazypassion }
23747ad3c4Slazypassion 
24747ad3c4Slazypassion /// Read-only interface which is exposed outside the parser crate.
25747ad3c4Slazypassion impl SourceMap {
26747ad3c4Slazypassion     /// Look up a value entity.
contains_value(&self, v: Value) -> bool27747ad3c4Slazypassion     pub fn contains_value(&self, v: Value) -> bool {
28747ad3c4Slazypassion         self.locations.contains_key(&v.into())
29747ad3c4Slazypassion     }
30747ad3c4Slazypassion 
31832666c4SRyan Hunt     /// Look up a block entity.
contains_block(&self, block: Block) -> bool32832666c4SRyan Hunt     pub fn contains_block(&self, block: Block) -> bool {
33832666c4SRyan Hunt         self.locations.contains_key(&block.into())
34747ad3c4Slazypassion     }
35747ad3c4Slazypassion 
36747ad3c4Slazypassion     /// Look up a stack slot entity.
contains_ss(&self, ss: StackSlot) -> bool37747ad3c4Slazypassion     pub fn contains_ss(&self, ss: StackSlot) -> bool {
38747ad3c4Slazypassion         self.locations.contains_key(&ss.into())
39747ad3c4Slazypassion     }
40747ad3c4Slazypassion 
419c43749dSSam Parker     /// Look up a dynamic stack slot entity.
contains_dss(&self, dss: DynamicStackSlot) -> bool429c43749dSSam Parker     pub fn contains_dss(&self, dss: DynamicStackSlot) -> bool {
439c43749dSSam Parker         self.locations.contains_key(&dss.into())
449c43749dSSam Parker     }
459c43749dSSam Parker 
46747ad3c4Slazypassion     /// Look up a global value entity.
contains_gv(&self, gv: GlobalValue) -> bool47747ad3c4Slazypassion     pub fn contains_gv(&self, gv: GlobalValue) -> bool {
48747ad3c4Slazypassion         self.locations.contains_key(&gv.into())
49747ad3c4Slazypassion     }
50747ad3c4Slazypassion 
51747ad3c4Slazypassion     /// Look up a signature entity.
contains_sig(&self, sig: SigRef) -> bool52747ad3c4Slazypassion     pub fn contains_sig(&self, sig: SigRef) -> bool {
53747ad3c4Slazypassion         self.locations.contains_key(&sig.into())
54747ad3c4Slazypassion     }
55747ad3c4Slazypassion 
56747ad3c4Slazypassion     /// Look up a function entity.
contains_fn(&self, fn_: FuncRef) -> bool57747ad3c4Slazypassion     pub fn contains_fn(&self, fn_: FuncRef) -> bool {
58747ad3c4Slazypassion         self.locations.contains_key(&fn_.into())
59747ad3c4Slazypassion     }
60747ad3c4Slazypassion 
61747ad3c4Slazypassion     /// Look up a jump table entity.
contains_jt(&self, jt: JumpTable) -> bool62747ad3c4Slazypassion     pub fn contains_jt(&self, jt: JumpTable) -> bool {
63747ad3c4Slazypassion         self.locations.contains_key(&jt.into())
64747ad3c4Slazypassion     }
65747ad3c4Slazypassion 
660672d1dcSAndrew Brown     /// Look up a constant entity.
contains_constant(&self, c: Constant) -> bool670672d1dcSAndrew Brown     pub fn contains_constant(&self, c: Constant) -> bool {
680672d1dcSAndrew Brown         self.locations.contains_key(&c.into())
690672d1dcSAndrew Brown     }
700672d1dcSAndrew Brown 
71747ad3c4Slazypassion     /// Look up an entity by source name.
72747ad3c4Slazypassion     /// Returns the entity reference corresponding to `name`, if it exists.
lookup_str(&self, name: &str) -> Option<AnyEntity>73747ad3c4Slazypassion     pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> {
74747ad3c4Slazypassion         split_entity_name(name).and_then(|(ent, num)| match ent {
75747ad3c4Slazypassion             "v" => Value::with_number(num).and_then(|v| {
76747ad3c4Slazypassion                 if !self.contains_value(v) {
77747ad3c4Slazypassion                     None
78747ad3c4Slazypassion                 } else {
79747ad3c4Slazypassion                     Some(v.into())
80747ad3c4Slazypassion                 }
81747ad3c4Slazypassion             }),
82832666c4SRyan Hunt             "block" => Block::with_number(num).and_then(|block| {
83832666c4SRyan Hunt                 if !self.contains_block(block) {
84747ad3c4Slazypassion                     None
85747ad3c4Slazypassion                 } else {
86832666c4SRyan Hunt                     Some(block.into())
87747ad3c4Slazypassion                 }
88747ad3c4Slazypassion             }),
89747ad3c4Slazypassion             "ss" => StackSlot::with_number(num).and_then(|ss| {
90747ad3c4Slazypassion                 if !self.contains_ss(ss) {
91747ad3c4Slazypassion                     None
92747ad3c4Slazypassion                 } else {
93747ad3c4Slazypassion                     Some(ss.into())
94747ad3c4Slazypassion                 }
95747ad3c4Slazypassion             }),
96747ad3c4Slazypassion             "gv" => GlobalValue::with_number(num).and_then(|gv| {
97747ad3c4Slazypassion                 if !self.contains_gv(gv) {
98747ad3c4Slazypassion                     None
99747ad3c4Slazypassion                 } else {
100747ad3c4Slazypassion                     Some(gv.into())
101747ad3c4Slazypassion                 }
102747ad3c4Slazypassion             }),
103747ad3c4Slazypassion             "sig" => SigRef::with_number(num).and_then(|sig| {
104747ad3c4Slazypassion                 if !self.contains_sig(sig) {
105747ad3c4Slazypassion                     None
106747ad3c4Slazypassion                 } else {
107747ad3c4Slazypassion                     Some(sig.into())
108747ad3c4Slazypassion                 }
109747ad3c4Slazypassion             }),
110747ad3c4Slazypassion             "fn" => FuncRef::with_number(num).and_then(|fn_| {
111747ad3c4Slazypassion                 if !self.contains_fn(fn_) {
112747ad3c4Slazypassion                     None
113747ad3c4Slazypassion                 } else {
114747ad3c4Slazypassion                     Some(fn_.into())
115747ad3c4Slazypassion                 }
116747ad3c4Slazypassion             }),
117747ad3c4Slazypassion             "jt" => JumpTable::with_number(num).and_then(|jt| {
118747ad3c4Slazypassion                 if !self.contains_jt(jt) {
119747ad3c4Slazypassion                     None
120747ad3c4Slazypassion                 } else {
121747ad3c4Slazypassion                     Some(jt.into())
122747ad3c4Slazypassion                 }
123747ad3c4Slazypassion             }),
124747ad3c4Slazypassion             _ => None,
125747ad3c4Slazypassion         })
126747ad3c4Slazypassion     }
127747ad3c4Slazypassion 
128747ad3c4Slazypassion     /// Get the source location where an entity was defined.
location(&self, entity: AnyEntity) -> Option<Location>129747ad3c4Slazypassion     pub fn location(&self, entity: AnyEntity) -> Option<Location> {
130747ad3c4Slazypassion         self.locations.get(&entity).cloned()
131747ad3c4Slazypassion     }
132747ad3c4Slazypassion }
133747ad3c4Slazypassion 
134747ad3c4Slazypassion impl SourceMap {
135747ad3c4Slazypassion     /// Create a new empty `SourceMap`.
new() -> Self136747ad3c4Slazypassion     pub fn new() -> Self {
137747ad3c4Slazypassion         Self {
138747ad3c4Slazypassion             locations: HashMap::new(),
139747ad3c4Slazypassion         }
140747ad3c4Slazypassion     }
141747ad3c4Slazypassion 
142747ad3c4Slazypassion     /// Define the value `entity`.
def_value(&mut self, entity: Value, loc: Location) -> ParseResult<()>143747ad3c4Slazypassion     pub fn def_value(&mut self, entity: Value, loc: Location) -> ParseResult<()> {
144747ad3c4Slazypassion         self.def_entity(entity.into(), loc)
145747ad3c4Slazypassion     }
146747ad3c4Slazypassion 
147832666c4SRyan Hunt     /// Define the block `entity`.
def_block(&mut self, entity: Block, loc: Location) -> ParseResult<()>148832666c4SRyan Hunt     pub fn def_block(&mut self, entity: Block, loc: Location) -> ParseResult<()> {
149747ad3c4Slazypassion         self.def_entity(entity.into(), loc)
150747ad3c4Slazypassion     }
151747ad3c4Slazypassion 
152747ad3c4Slazypassion     /// Define the stack slot `entity`.
def_ss(&mut self, entity: StackSlot, loc: Location) -> ParseResult<()>153747ad3c4Slazypassion     pub fn def_ss(&mut self, entity: StackSlot, loc: Location) -> ParseResult<()> {
154747ad3c4Slazypassion         self.def_entity(entity.into(), loc)
155747ad3c4Slazypassion     }
156747ad3c4Slazypassion 
1579c43749dSSam Parker     /// Define the dynamic stack slot `entity`.
def_dss(&mut self, entity: DynamicStackSlot, loc: Location) -> ParseResult<()>1589c43749dSSam Parker     pub fn def_dss(&mut self, entity: DynamicStackSlot, loc: Location) -> ParseResult<()> {
1599c43749dSSam Parker         self.def_entity(entity.into(), loc)
1609c43749dSSam Parker     }
1619c43749dSSam Parker 
1629c43749dSSam Parker     /// Define the dynamic type `entity`.
def_dt(&mut self, entity: DynamicType, loc: Location) -> ParseResult<()>1639c43749dSSam Parker     pub fn def_dt(&mut self, entity: DynamicType, loc: Location) -> ParseResult<()> {
1649c43749dSSam Parker         self.def_entity(entity.into(), loc)
1659c43749dSSam Parker     }
1669c43749dSSam Parker 
167747ad3c4Slazypassion     /// Define the global value `entity`.
def_gv(&mut self, entity: GlobalValue, loc: Location) -> ParseResult<()>168747ad3c4Slazypassion     pub fn def_gv(&mut self, entity: GlobalValue, loc: Location) -> ParseResult<()> {
169747ad3c4Slazypassion         self.def_entity(entity.into(), loc)
170747ad3c4Slazypassion     }
171747ad3c4Slazypassion 
172747ad3c4Slazypassion     /// Define the signature `entity`.
def_sig(&mut self, entity: SigRef, loc: Location) -> ParseResult<()>173747ad3c4Slazypassion     pub fn def_sig(&mut self, entity: SigRef, loc: Location) -> ParseResult<()> {
174747ad3c4Slazypassion         self.def_entity(entity.into(), loc)
175747ad3c4Slazypassion     }
176747ad3c4Slazypassion 
177747ad3c4Slazypassion     /// Define the external function `entity`.
def_fn(&mut self, entity: FuncRef, loc: Location) -> ParseResult<()>178747ad3c4Slazypassion     pub fn def_fn(&mut self, entity: FuncRef, loc: Location) -> ParseResult<()> {
179747ad3c4Slazypassion         self.def_entity(entity.into(), loc)
180747ad3c4Slazypassion     }
181747ad3c4Slazypassion 
182747ad3c4Slazypassion     /// Define the jump table `entity`.
def_jt(&mut self, entity: JumpTable, loc: Location) -> ParseResult<()>183747ad3c4Slazypassion     pub fn def_jt(&mut self, entity: JumpTable, loc: Location) -> ParseResult<()> {
184747ad3c4Slazypassion         self.def_entity(entity.into(), loc)
185747ad3c4Slazypassion     }
186747ad3c4Slazypassion 
1870672d1dcSAndrew Brown     /// Define the jump table `entity`.
def_constant(&mut self, entity: Constant, loc: Location) -> ParseResult<()>1880672d1dcSAndrew Brown     pub fn def_constant(&mut self, entity: Constant, loc: Location) -> ParseResult<()> {
1890672d1dcSAndrew Brown         self.def_entity(entity.into(), loc)
1900672d1dcSAndrew Brown     }
1910672d1dcSAndrew Brown 
192747ad3c4Slazypassion     /// Define an entity. This can be used for instructions whose numbers never
193747ad3c4Slazypassion     /// appear in source, or implicitly defined signatures.
def_entity(&mut self, entity: AnyEntity, loc: Location) -> ParseResult<()>194747ad3c4Slazypassion     pub fn def_entity(&mut self, entity: AnyEntity, loc: Location) -> ParseResult<()> {
195747ad3c4Slazypassion         if self.locations.insert(entity, loc).is_some() {
196747ad3c4Slazypassion             err!(loc, "duplicate entity: {}", entity)
197747ad3c4Slazypassion         } else {
198747ad3c4Slazypassion             Ok(())
199747ad3c4Slazypassion         }
200747ad3c4Slazypassion     }
201747ad3c4Slazypassion }
202747ad3c4Slazypassion 
203747ad3c4Slazypassion #[cfg(test)]
204747ad3c4Slazypassion mod tests {
20590ac295eSAlex Crichton     use crate::{ParseOptions, parse_test};
206747ad3c4Slazypassion 
207747ad3c4Slazypassion     #[test]
details()208747ad3c4Slazypassion     fn details() {
209747ad3c4Slazypassion         let tf = parse_test(
210747ad3c4Slazypassion             "function %detail() {
211a894594aSbjorn3                                ss10 = explicit_slot 13
212832666c4SRyan Hunt                              block0(v4: i32, v7: i32):
213747ad3c4Slazypassion                                v10 = iadd v4, v7
214747ad3c4Slazypassion                              }",
2156fdc69ffSAndrew Brown             ParseOptions::default(),
216747ad3c4Slazypassion         )
217747ad3c4Slazypassion         .unwrap();
218747ad3c4Slazypassion         let map = &tf.functions[0].1.map;
219747ad3c4Slazypassion 
220747ad3c4Slazypassion         assert_eq!(map.lookup_str("v0"), None);
221747ad3c4Slazypassion         assert_eq!(map.lookup_str("ss1"), None);
222747ad3c4Slazypassion         assert_eq!(map.lookup_str("ss10").unwrap().to_string(), "ss10");
223832666c4SRyan Hunt         assert_eq!(map.lookup_str("block0").unwrap().to_string(), "block0");
224747ad3c4Slazypassion         assert_eq!(map.lookup_str("v4").unwrap().to_string(), "v4");
225747ad3c4Slazypassion         assert_eq!(map.lookup_str("v7").unwrap().to_string(), "v7");
226747ad3c4Slazypassion         assert_eq!(map.lookup_str("v10").unwrap().to_string(), "v10");
227747ad3c4Slazypassion     }
228747ad3c4Slazypassion }
229