1 //! Verify CPU flags values.
2 
3 use crate::entity::{EntitySet, SecondaryMap};
4 use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
5 use crate::ir;
6 use crate::ir::instructions::BranchInfo;
7 use crate::isa;
8 use crate::packed_option::PackedOption;
9 use crate::timing;
10 use crate::verifier::{VerifierErrors, VerifierStepResult};
11 
12 /// Verify that CPU flags are used correctly.
13 ///
14 /// The value types `iflags` and `fflags` represent CPU flags which usually live in a
15 /// special-purpose register, so they can't be used as freely as other value types that can live in
16 /// any register.
17 ///
18 /// We verify the following conditions:
19 ///
20 /// - At most one flags value can be live at a time.
21 /// - A flags value can not be live across an instruction that clobbers the flags.
22 ///
23 ///
verify_flags( func: &ir::Function, cfg: &ControlFlowGraph, isa: Option<&dyn isa::TargetIsa>, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>24 pub fn verify_flags(
25     func: &ir::Function,
26     cfg: &ControlFlowGraph,
27     isa: Option<&dyn isa::TargetIsa>,
28     errors: &mut VerifierErrors,
29 ) -> VerifierStepResult<()> {
30     let _tt = timing::verify_flags();
31     let encinfo = if isa.is_none() || isa.unwrap().get_mach_backend().is_some() {
32         None
33     } else {
34         Some(isa.unwrap().encoding_info())
35     };
36     let mut verifier = FlagsVerifier {
37         func,
38         cfg,
39         encinfo,
40         livein: SecondaryMap::new(),
41     };
42     verifier.check(errors)
43 }
44 
45 struct FlagsVerifier<'a> {
46     func: &'a ir::Function,
47     cfg: &'a ControlFlowGraph,
48     encinfo: Option<isa::EncInfo>,
49 
50     /// The single live-in flags value (if any) for each block.
51     livein: SecondaryMap<ir::Block, PackedOption<ir::Value>>,
52 }
53 
54 impl<'a> FlagsVerifier<'a> {
check(&mut self, errors: &mut VerifierErrors) -> VerifierStepResult<()>55     fn check(&mut self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
56         // List of blocks that need to be processed. blocks may be re-added to this list when we detect
57         // that one of their successor blocks needs a live-in flags value.
58         let mut worklist = EntitySet::with_capacity(self.func.layout.block_capacity());
59         for block in self.func.layout.blocks() {
60             worklist.insert(block);
61         }
62 
63         while let Some(block) = worklist.pop() {
64             if let Some(value) = self.visit_block(block, errors)? {
65                 // The block has live-in flags. Check if the value changed.
66                 match self.livein[block].expand() {
67                     // Revisit any predecessor blocks the first time we see a live-in for `block`.
68                     None => {
69                         self.livein[block] = value.into();
70                         for BlockPredecessor { block: pred, .. } in self.cfg.pred_iter(block) {
71                             worklist.insert(pred);
72                         }
73                     }
74                     Some(old) if old != value => {
75                         return errors.fatal((
76                             block,
77                             format!("conflicting live-in CPU flags: {} and {}", old, value),
78                         ));
79                     }
80                     x => assert_eq!(x, Some(value)),
81                 }
82             } else {
83                 // Existing live-in flags should never be able to disappear.
84                 assert_eq!(self.livein[block].expand(), None);
85             }
86         }
87 
88         Ok(())
89     }
90 
91     /// Check flags usage in `block` and return the live-in flags value, if any.
visit_block( &self, block: ir::Block, errors: &mut VerifierErrors, ) -> VerifierStepResult<Option<ir::Value>>92     fn visit_block(
93         &self,
94         block: ir::Block,
95         errors: &mut VerifierErrors,
96     ) -> VerifierStepResult<Option<ir::Value>> {
97         // The single currently live flags value.
98         let mut live_val = None;
99 
100         // Visit instructions backwards so we can track liveness accurately.
101         for inst in self.func.layout.block_insts(block).rev() {
102             // Check if `inst` interferes with existing live flags.
103             if let Some(live) = live_val {
104                 for &res in self.func.dfg.inst_results(inst) {
105                     if res == live {
106                         // We've reached the def of `live_flags`, so it is no longer live above.
107                         live_val = None;
108                     } else if self.func.dfg.value_type(res).is_flags() {
109                         errors
110                             .report((inst, format!("{} clobbers live CPU flags in {}", res, live)));
111                         return Err(());
112                     }
113                 }
114 
115                 // Does the instruction have an encoding that clobbers the CPU flags?
116                 if self
117                     .encinfo
118                     .as_ref()
119                     .and_then(|ei| ei.operand_constraints(self.func.encodings[inst]))
120                     .map_or(false, |c| c.clobbers_flags)
121                     && live_val.is_some()
122                 {
123                     errors.report((
124                         inst,
125                         format!("encoding clobbers live CPU flags in {}", live),
126                     ));
127                     return Err(());
128                 }
129             }
130 
131             // Now look for live ranges of CPU flags that end here.
132             for &arg in self.func.dfg.inst_args(inst) {
133                 if self.func.dfg.value_type(arg).is_flags() {
134                     merge(&mut live_val, arg, inst, errors)?;
135                 }
136             }
137 
138             // Include live-in flags to successor blocks.
139             match self.func.dfg.analyze_branch(inst) {
140                 BranchInfo::NotABranch => {}
141                 BranchInfo::SingleDest(dest, _) => {
142                     if let Some(val) = self.livein[dest].expand() {
143                         merge(&mut live_val, val, inst, errors)?;
144                     }
145                 }
146                 BranchInfo::Table(jt, dest) => {
147                     if let Some(dest) = dest {
148                         if let Some(val) = self.livein[dest].expand() {
149                             merge(&mut live_val, val, inst, errors)?;
150                         }
151                     }
152                     for dest in self.func.jump_tables[jt].iter() {
153                         if let Some(val) = self.livein[*dest].expand() {
154                             merge(&mut live_val, val, inst, errors)?;
155                         }
156                     }
157                 }
158             }
159         }
160 
161         // Return the required live-in flags value.
162         Ok(live_val)
163     }
164 }
165 
166 // Merge live flags values, or return an error on conflicting values.
merge( a: &mut Option<ir::Value>, b: ir::Value, inst: ir::Inst, errors: &mut VerifierErrors, ) -> VerifierStepResult<()>167 fn merge(
168     a: &mut Option<ir::Value>,
169     b: ir::Value,
170     inst: ir::Inst,
171     errors: &mut VerifierErrors,
172 ) -> VerifierStepResult<()> {
173     if let Some(va) = *a {
174         if b != va {
175             return errors.fatal((
176                 inst,
177                 format!("conflicting live CPU flags: {} and {}", va, b),
178             ));
179         }
180     } else {
181         *a = Some(b);
182     }
183 
184     Ok(())
185 }
186