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