1 //! Verify value locations.
2 
3 use crate::flowgraph::ControlFlowGraph;
4 use crate::ir;
5 use crate::isa;
6 use crate::regalloc::liveness::Liveness;
7 use crate::regalloc::RegDiversions;
8 use crate::timing;
9 use crate::verifier::{VerifierErrors, VerifierStepResult};
10 
11 /// Verify value locations for `func`.
12 ///
13 /// After register allocation, every value must be assigned to a location - either a register or a
14 /// stack slot. These locations must be compatible with the constraints described by the
15 /// instruction encoding recipes.
16 ///
17 /// Values can be temporarily diverted to a different location by using the `regmove`, `regspill`,
18 /// and `regfill` instructions, but only inside a block.
19 ///
20 /// If a liveness analysis is provided, it is used to verify that there are no active register
21 /// diversions across control flow edges.
verify_locations( isa: &dyn isa::TargetIsa, func: &ir::Function, cfg: &ControlFlowGraph, liveness: Option<&Liveness>, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>22 pub fn verify_locations(
23     isa: &dyn isa::TargetIsa,
24     func: &ir::Function,
25     cfg: &ControlFlowGraph,
26     liveness: Option<&Liveness>,
27     errors: &mut VerifierErrors,
28 ) -> VerifierStepResult<()> {
29     let _tt = timing::verify_locations();
30     let verifier = LocationVerifier {
31         isa,
32         func,
33         reginfo: isa.register_info(),
34         encinfo: isa.encoding_info(),
35         cfg,
36         liveness,
37     };
38     verifier.check_constraints(errors)?;
39     Ok(())
40 }
41 
42 struct LocationVerifier<'a> {
43     isa: &'a dyn isa::TargetIsa,
44     func: &'a ir::Function,
45     reginfo: isa::RegInfo,
46     encinfo: isa::EncInfo,
47     cfg: &'a ControlFlowGraph,
48     liveness: Option<&'a Liveness>,
49 }
50 
51 impl<'a> LocationVerifier<'a> {
52     /// Check that the assigned value locations match the operand constraints of their uses.
check_constraints(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()>53     fn check_constraints(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
54         let dfg = &self.func.dfg;
55         let mut divert = RegDiversions::new();
56 
57         for block in self.func.layout.blocks() {
58             divert.at_block(&self.func.entry_diversions, block);
59 
60             let mut is_after_branch = false;
61             for inst in self.func.layout.block_insts(block) {
62                 let enc = self.func.encodings[inst];
63 
64                 if enc.is_legal() {
65                     self.check_enc_constraints(inst, enc, &divert, errors)?
66                 } else {
67                     self.check_ghost_results(inst, errors)?;
68                 }
69 
70                 if let Some(sig) = dfg.call_signature(inst) {
71                     self.check_call_abi(inst, sig, &divert, errors)?;
72                 }
73 
74                 let opcode = dfg[inst].opcode();
75                 if opcode.is_return() {
76                     self.check_return_abi(inst, &divert, errors)?;
77                 } else if opcode.is_branch() && !divert.is_empty() {
78                     self.check_cfg_edges(inst, &mut divert, is_after_branch, errors)?;
79                 }
80 
81                 self.update_diversions(inst, &mut divert, errors)?;
82                 is_after_branch = opcode.is_branch();
83             }
84         }
85 
86         Ok(())
87     }
88 
89     /// Check encoding constraints against the current value locations.
check_enc_constraints( &self, inst: ir::Inst, enc: isa::Encoding, divert: &RegDiversions, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>90     fn check_enc_constraints(
91         &self,
92         inst: ir::Inst,
93         enc: isa::Encoding,
94         divert: &RegDiversions,
95         errors: &mut VerifierErrors,
96     ) -> VerifierStepResult<()> {
97         let constraints = self
98             .encinfo
99             .operand_constraints(enc)
100             .expect("check_enc_constraints requires a legal encoding");
101 
102         if constraints.satisfied(inst, divert, self.func) {
103             return Ok(());
104         }
105 
106         // TODO: We could give a better error message here.
107         errors.fatal((
108             inst,
109             format!(
110                 "{} constraints not satisfied in: {}\n{}",
111                 self.encinfo.display(enc),
112                 self.func.dfg.display_inst(inst, self.isa),
113                 self.func.display(self.isa),
114             ),
115         ))
116     }
117 
118     /// Check that the result values produced by a ghost instruction are not assigned a value
119     /// location.
check_ghost_results( &self, inst: ir::Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>120     fn check_ghost_results(
121         &self,
122         inst: ir::Inst,
123         errors: &mut VerifierErrors,
124     ) -> VerifierStepResult<()> {
125         let results = self.func.dfg.inst_results(inst);
126 
127         for &res in results {
128             let loc = self.func.locations[res];
129             if loc.is_assigned() {
130                 return errors.fatal((
131                     inst,
132                     format!(
133                         "ghost result {} value must not have a location ({}).",
134                         res,
135                         loc.display(&self.reginfo)
136                     ),
137                 ));
138             }
139         }
140 
141         Ok(())
142     }
143 
144     /// Check the ABI argument and result locations for a call.
check_call_abi( &self, inst: ir::Inst, sig: ir::SigRef, divert: &RegDiversions, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>145     fn check_call_abi(
146         &self,
147         inst: ir::Inst,
148         sig: ir::SigRef,
149         divert: &RegDiversions,
150         errors: &mut VerifierErrors,
151     ) -> VerifierStepResult<()> {
152         let sig = &self.func.dfg.signatures[sig];
153         let varargs = self.func.dfg.inst_variable_args(inst);
154         let results = self.func.dfg.inst_results(inst);
155 
156         for (abi, &value) in sig.params.iter().zip(varargs) {
157             self.check_abi_location(
158                 inst,
159                 value,
160                 abi,
161                 divert.get(value, &self.func.locations),
162                 ir::StackSlotKind::OutgoingArg,
163                 errors,
164             )?;
165         }
166 
167         for (abi, &value) in sig.returns.iter().zip(results) {
168             self.check_abi_location(
169                 inst,
170                 value,
171                 abi,
172                 self.func.locations[value],
173                 ir::StackSlotKind::OutgoingArg,
174                 errors,
175             )?;
176         }
177 
178         Ok(())
179     }
180 
181     /// Check the ABI argument locations for a return.
check_return_abi( &self, inst: ir::Inst, divert: &RegDiversions, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>182     fn check_return_abi(
183         &self,
184         inst: ir::Inst,
185         divert: &RegDiversions,
186         errors: &mut VerifierErrors,
187     ) -> VerifierStepResult<()> {
188         let sig = &self.func.signature;
189         let varargs = self.func.dfg.inst_variable_args(inst);
190 
191         for (abi, &value) in sig.returns.iter().zip(varargs) {
192             self.check_abi_location(
193                 inst,
194                 value,
195                 abi,
196                 divert.get(value, &self.func.locations),
197                 ir::StackSlotKind::IncomingArg,
198                 errors,
199             )?;
200         }
201 
202         Ok(())
203     }
204 
205     /// Check a single ABI location.
check_abi_location( &self, inst: ir::Inst, value: ir::Value, abi: &ir::AbiParam, loc: ir::ValueLoc, want_kind: ir::StackSlotKind, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>206     fn check_abi_location(
207         &self,
208         inst: ir::Inst,
209         value: ir::Value,
210         abi: &ir::AbiParam,
211         loc: ir::ValueLoc,
212         want_kind: ir::StackSlotKind,
213         errors: &mut VerifierErrors,
214     ) -> VerifierStepResult<()> {
215         match abi.location {
216             ir::ArgumentLoc::Unassigned => {}
217             ir::ArgumentLoc::Reg(reg) => {
218                 if loc != ir::ValueLoc::Reg(reg) {
219                     return errors.fatal((
220                         inst,
221                         format!(
222                             "ABI expects {} in {}, got {}",
223                             value,
224                             abi.location.display(&self.reginfo),
225                             loc.display(&self.reginfo),
226                         ),
227                     ));
228                 }
229             }
230             ir::ArgumentLoc::Stack(offset) => {
231                 if let ir::ValueLoc::Stack(ss) = loc {
232                     let slot = &self.func.stack_slots[ss];
233                     if slot.kind != want_kind {
234                         return errors.fatal((
235                             inst,
236                             format!(
237                                 "call argument {} should be in a {} slot, but {} is {}",
238                                 value, want_kind, ss, slot.kind
239                             ),
240                         ));
241                     }
242                     if slot.offset.unwrap() != offset {
243                         return errors.fatal((
244                             inst,
245                             format!(
246                                 "ABI expects {} at stack offset {}, but {} is at {}",
247                                 value,
248                                 offset,
249                                 ss,
250                                 slot.offset.unwrap()
251                             ),
252                         ));
253                     }
254                 } else {
255                     return errors.fatal((
256                         inst,
257                         format!(
258                             "ABI expects {} at stack offset {}, got {}",
259                             value,
260                             offset,
261                             loc.display(&self.reginfo)
262                         ),
263                     ));
264                 }
265             }
266         }
267 
268         Ok(())
269     }
270 
271     /// Update diversions to reflect the current instruction and check their consistency.
update_diversions( &self, inst: ir::Inst, divert: &mut RegDiversions, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>272     fn update_diversions(
273         &self,
274         inst: ir::Inst,
275         divert: &mut RegDiversions,
276         errors: &mut VerifierErrors,
277     ) -> VerifierStepResult<()> {
278         let (arg, src) = match self.func.dfg[inst] {
279             ir::InstructionData::RegMove { arg, src, .. }
280             | ir::InstructionData::RegSpill { arg, src, .. } => (arg, ir::ValueLoc::Reg(src)),
281             ir::InstructionData::RegFill { arg, src, .. } => (arg, ir::ValueLoc::Stack(src)),
282             _ => return Ok(()),
283         };
284 
285         if let Some(d) = divert.diversion(arg) {
286             if d.to != src {
287                 return errors.fatal((
288                     inst,
289                     format!(
290                         "inconsistent with current diversion to {}",
291                         d.to.display(&self.reginfo)
292                     ),
293                 ));
294             }
295         } else if self.func.locations[arg] != src {
296             return errors.fatal((
297                 inst,
298                 format!(
299                     "inconsistent with global location {} ({})",
300                     self.func.locations[arg].display(&self.reginfo),
301                     self.func.dfg.display_inst(inst, None)
302                 ),
303             ));
304         }
305 
306         divert.apply(&self.func.dfg[inst]);
307 
308         Ok(())
309     }
310 
311     /// We have active diversions before a branch. Make sure none of the diverted values are live
312     /// on the outgoing CFG edges.
check_cfg_edges( &self, inst: ir::Inst, divert: &mut RegDiversions, is_after_branch: bool, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>313     fn check_cfg_edges(
314         &self,
315         inst: ir::Inst,
316         divert: &mut RegDiversions,
317         is_after_branch: bool,
318         errors: &mut VerifierErrors,
319     ) -> VerifierStepResult<()> {
320         use crate::ir::instructions::BranchInfo::*;
321         let dfg = &self.func.dfg;
322         let branch_kind = dfg.analyze_branch(inst);
323 
324         // We can only check CFG edges if we have a liveness analysis.
325         let liveness = match self.liveness {
326             Some(l) => l,
327             None => return Ok(()),
328         };
329 
330         match branch_kind {
331             NotABranch => panic!(
332                 "No branch information for {}",
333                 dfg.display_inst(inst, self.isa)
334             ),
335             SingleDest(block, _) => {
336                 let unique_predecessor = self.cfg.pred_iter(block).count() == 1;
337                 let mut val_to_remove = vec![];
338                 for (&value, d) in divert.iter() {
339                     let lr = &liveness[value];
340                     if is_after_branch && unique_predecessor {
341                         // Forward diversions based on the targeted branch.
342                         if !lr.is_livein(block, &self.func.layout) {
343                             val_to_remove.push(value)
344                         }
345                     } else if lr.is_livein(block, &self.func.layout) {
346                         return errors.fatal((
347                             inst,
348                             format!(
349                                 "SingleDest: {} is diverted to {} and live in to {}",
350                                 value,
351                                 d.to.display(&self.reginfo),
352                                 block,
353                             ),
354                         ));
355                     }
356                 }
357                 if is_after_branch && unique_predecessor {
358                     for val in val_to_remove.into_iter() {
359                         divert.remove(val);
360                     }
361                     debug_assert!(divert.check_block_entry(&self.func.entry_diversions, block));
362                 }
363             }
364             Table(jt, block) => {
365                 for (&value, d) in divert.iter() {
366                     let lr = &liveness[value];
367                     if let Some(block) = block {
368                         if lr.is_livein(block, &self.func.layout) {
369                             return errors.fatal((
370                                 inst,
371                                 format!(
372                                     "Table.default: {} is diverted to {} and live in to {}",
373                                     value,
374                                     d.to.display(&self.reginfo),
375                                     block,
376                                 ),
377                             ));
378                         }
379                     }
380                     for block in self.func.jump_tables[jt].iter() {
381                         if lr.is_livein(*block, &self.func.layout) {
382                             return errors.fatal((
383                                 inst,
384                                 format!(
385                                     "Table.case: {} is diverted to {} and live in to {}",
386                                     value,
387                                     d.to.display(&self.reginfo),
388                                     block,
389                                 ),
390                             ));
391                         }
392                     }
393                 }
394             }
395         }
396 
397         Ok(())
398     }
399 }
400