Skip to main content

cranelift_reader/
sourcemap.rs

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
9use crate::error::{Location, ParseResult};
10use crate::lexer::split_entity_name;
11use cranelift_codegen::ir::entities::{AnyEntity, DynamicType};
12use cranelift_codegen::ir::{
13    Block, Constant, DynamicStackSlot, FuncRef, GlobalValue, JumpTable, SigRef, StackSlot, Value,
14};
15use std::collections::HashMap;
16
17/// Mapping from entity names to source locations.
18#[derive(Debug, Default)]
19pub 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.
25impl 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
134impl 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)]
204mod 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}