1#![allow(dead_code)]
97
98use crate::{
99 Allocation, AllocationKind, Block, Edit, Function, Inst, InstOrEdit, InstPosition, MachineEnv,
100 Operand, OperandConstraint, OperandKind, OperandPos, Output, PReg, PRegSet, VReg,
101};
102use fxhash::{FxHashMap, FxHashSet};
103use smallvec::{smallvec, SmallVec};
104use std::default::Default;
105use std::hash::Hash;
106use std::result::Result;
107
108#[derive(Clone, Debug)]
110pub struct CheckerErrors {
111 errors: Vec<CheckerError>,
112}
113
114#[derive(Clone, Debug)]
116pub enum CheckerError {
117 MissingAllocation {
118 inst: Inst,
119 op: Operand,
120 },
121 UnknownValueInAllocation {
122 inst: Inst,
123 op: Operand,
124 alloc: Allocation,
125 },
126 ConflictedValueInAllocation {
127 inst: Inst,
128 op: Operand,
129 alloc: Allocation,
130 },
131 IncorrectValuesInAllocation {
132 inst: Inst,
133 op: Operand,
134 alloc: Allocation,
135 actual: FxHashSet<VReg>,
136 },
137 ConstraintViolated {
138 inst: Inst,
139 op: Operand,
140 alloc: Allocation,
141 },
142 AllocationIsNotReg {
143 inst: Inst,
144 op: Operand,
145 alloc: Allocation,
146 },
147 AllocationIsNotFixedReg {
148 inst: Inst,
149 op: Operand,
150 alloc: Allocation,
151 },
152 AllocationIsNotReuse {
153 inst: Inst,
154 op: Operand,
155 alloc: Allocation,
156 expected_alloc: Allocation,
157 },
158 AllocationIsNotStack {
159 inst: Inst,
160 op: Operand,
161 alloc: Allocation,
162 },
163 ConflictedValueInStackmap {
164 inst: Inst,
165 alloc: Allocation,
166 },
167 NonRefValuesInStackmap {
168 inst: Inst,
169 alloc: Allocation,
170 vregs: FxHashSet<VReg>,
171 },
172 StackToStackMove {
173 into: Allocation,
174 from: Allocation,
175 },
176}
177
178#[derive(Clone, Debug, PartialEq, Eq)]
184enum CheckerValue {
185 Universe,
188 VRegs(FxHashSet<VReg>),
190}
191
192impl CheckerValue {
193 fn vregs(&self) -> Option<&FxHashSet<VReg>> {
194 match self {
195 CheckerValue::Universe => None,
196 CheckerValue::VRegs(vregs) => Some(vregs),
197 }
198 }
199
200 fn vregs_mut(&mut self) -> Option<&mut FxHashSet<VReg>> {
201 match self {
202 CheckerValue::Universe => None,
203 CheckerValue::VRegs(vregs) => Some(vregs),
204 }
205 }
206}
207
208impl Default for CheckerValue {
209 fn default() -> CheckerValue {
210 CheckerValue::Universe
211 }
212}
213
214impl CheckerValue {
215 fn meet_with(&mut self, other: &CheckerValue) {
219 match (self, other) {
220 (_, CheckerValue::Universe) => {
221 }
223 (this @ CheckerValue::Universe, _) => {
224 *this = other.clone();
225 }
226 (CheckerValue::VRegs(my_vregs), CheckerValue::VRegs(other_vregs)) => {
227 my_vregs.retain(|vreg| other_vregs.contains(vreg));
228 }
229 }
230 }
231
232 fn from_reg(reg: VReg) -> CheckerValue {
233 CheckerValue::VRegs(std::iter::once(reg).collect())
234 }
235
236 fn remove_vreg(&mut self, reg: VReg) {
237 match self {
238 CheckerValue::Universe => {
239 panic!("Cannot remove VReg from Universe set (we do not have the full list of vregs available");
240 }
241 CheckerValue::VRegs(vregs) => {
242 vregs.remove(®);
243 }
244 }
245 }
246
247 fn copy_vreg(&mut self, src: VReg, dst: VReg) {
248 match self {
249 CheckerValue::Universe => {
250 }
252 CheckerValue::VRegs(vregs) => {
253 if vregs.contains(&src) {
254 vregs.insert(dst);
255 }
256 }
257 }
258 }
259
260 fn empty() -> CheckerValue {
261 CheckerValue::VRegs(FxHashSet::default())
262 }
263}
264
265fn visit_all_vregs<F: Function, V: FnMut(VReg)>(f: &F, mut v: V) {
266 for block in 0..f.num_blocks() {
267 let block = Block::new(block);
268 for inst in f.block_insns(block).iter() {
269 for op in f.inst_operands(inst) {
270 v(op.vreg());
271 }
272 if let Some((src, dst)) = f.is_move(inst) {
273 v(src.vreg());
274 v(dst.vreg());
275 }
276 if f.is_branch(inst) {
277 for succ_idx in 0..f.block_succs(block).len() {
278 for ¶m in f.branch_blockparams(block, inst, succ_idx) {
279 v(param);
280 }
281 }
282 }
283 }
284 for &vreg in f.block_params(block) {
285 v(vreg);
286 }
287 }
288}
289
290#[derive(Clone, Debug, PartialEq, Eq)]
292enum CheckerState {
293 Top,
294 Allocations(FxHashMap<Allocation, CheckerValue>),
295}
296
297impl CheckerState {
298 fn get_value(&self, alloc: &Allocation) -> Option<&CheckerValue> {
299 match self {
300 CheckerState::Top => None,
301 CheckerState::Allocations(allocs) => allocs.get(alloc),
302 }
303 }
304
305 fn get_values_mut(&mut self) -> impl Iterator<Item = &mut CheckerValue> {
306 match self {
307 CheckerState::Top => panic!("Cannot get mutable values iterator on Top state"),
308 CheckerState::Allocations(allocs) => allocs.values_mut(),
309 }
310 }
311
312 fn get_mappings(&self) -> impl Iterator<Item = (&Allocation, &CheckerValue)> {
313 match self {
314 CheckerState::Top => panic!("Cannot get mappings iterator on Top state"),
315 CheckerState::Allocations(allocs) => allocs.iter(),
316 }
317 }
318
319 fn get_mappings_mut(&mut self) -> impl Iterator<Item = (&Allocation, &mut CheckerValue)> {
320 match self {
321 CheckerState::Top => panic!("Cannot get mutable mappings iterator on Top state"),
322 CheckerState::Allocations(allocs) => allocs.iter_mut(),
323 }
324 }
325
326 fn become_defined(&mut self) {
328 match self {
329 CheckerState::Top => *self = CheckerState::Allocations(FxHashMap::default()),
330 _ => {}
331 }
332 }
333
334 fn set_value(&mut self, alloc: Allocation, value: CheckerValue) {
335 match self {
336 CheckerState::Top => {
337 panic!("Cannot set value on Top state");
338 }
339 CheckerState::Allocations(allocs) => {
340 allocs.insert(alloc, value);
341 }
342 }
343 }
344
345 fn copy_vreg(&mut self, src: VReg, dst: VReg) {
346 match self {
347 CheckerState::Top => {
348 }
350 CheckerState::Allocations(allocs) => {
351 for value in allocs.values_mut() {
352 value.copy_vreg(src, dst);
353 }
354 }
355 }
356 }
357
358 fn remove_value(&mut self, alloc: &Allocation) {
359 match self {
360 CheckerState::Top => {
361 panic!("Cannot remove value on Top state");
362 }
363 CheckerState::Allocations(allocs) => {
364 allocs.remove(alloc);
365 }
366 }
367 }
368
369 fn initial() -> Self {
370 CheckerState::Allocations(FxHashMap::default())
371 }
372}
373
374impl Default for CheckerState {
375 fn default() -> CheckerState {
376 CheckerState::Top
377 }
378}
379
380impl std::fmt::Display for CheckerValue {
381 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
382 match self {
383 CheckerValue::Universe => {
384 write!(f, "top")
385 }
386 CheckerValue::VRegs(vregs) => {
387 write!(f, "{{ ")?;
388 for vreg in vregs {
389 write!(f, "{} ", vreg)?;
390 }
391 write!(f, "}}")?;
392 Ok(())
393 }
394 }
395 }
396}
397
398fn merge_map<K: Copy + Clone + PartialEq + Eq + Hash>(
403 into: &mut FxHashMap<K, CheckerValue>,
404 from: &FxHashMap<K, CheckerValue>,
405) {
406 into.retain(|k, _| from.contains_key(k));
407 for (k, into_v) in into.iter_mut() {
408 let from_v = from.get(k).unwrap();
409 into_v.meet_with(from_v);
410 }
411}
412
413impl CheckerState {
414 fn new() -> CheckerState {
416 Default::default()
417 }
418
419 fn meet_with(&mut self, other: &CheckerState) {
421 match (self, other) {
422 (_, CheckerState::Top) => {
423 }
425 (this @ CheckerState::Top, _) => {
426 *this = other.clone();
427 }
428 (
429 CheckerState::Allocations(my_allocations),
430 CheckerState::Allocations(other_allocations),
431 ) => {
432 merge_map(my_allocations, other_allocations);
433 }
434 }
435 }
436
437 fn check_val<'a, F: Function>(
438 &self,
439 inst: Inst,
440 op: Operand,
441 alloc: Allocation,
442 val: &CheckerValue,
443 allocs: &[Allocation],
444 checker: &Checker<'a, F>,
445 ) -> Result<(), CheckerError> {
446 if alloc == Allocation::none() {
447 return Err(CheckerError::MissingAllocation { inst, op });
448 }
449
450 if op.as_fixed_nonallocatable().is_none() {
451 match val {
452 CheckerValue::Universe => {
453 return Err(CheckerError::UnknownValueInAllocation { inst, op, alloc });
454 }
455 CheckerValue::VRegs(vregs) if !vregs.contains(&op.vreg()) => {
456 return Err(CheckerError::IncorrectValuesInAllocation {
457 inst,
458 op,
459 alloc,
460 actual: vregs.clone(),
461 });
462 }
463 _ => {}
464 }
465 }
466
467 self.check_constraint(inst, op, alloc, allocs, checker)?;
468
469 Ok(())
470 }
471
472 fn check<'a, F: Function>(
476 &self,
477 pos: InstPosition,
478 checkinst: &CheckerInst,
479 checker: &Checker<'a, F>,
480 ) -> Result<(), CheckerError> {
481 let default_val = Default::default();
482 match checkinst {
483 &CheckerInst::Op {
484 inst,
485 ref operands,
486 ref allocs,
487 ..
488 } => {
489 let has_reused_input = operands
493 .iter()
494 .any(|op| matches!(op.constraint(), OperandConstraint::Reuse(_)));
495 if has_reused_input && pos == InstPosition::After {
496 return Ok(());
497 }
498
499 for (op, alloc) in operands.iter().zip(allocs.iter()) {
503 let is_here = match (op.pos(), pos) {
504 (OperandPos::Early, InstPosition::Before) => true,
505 (OperandPos::Late, InstPosition::After) => true,
506 _ => false,
507 };
508 if !is_here {
509 continue;
510 }
511 if op.kind() == OperandKind::Def {
512 continue;
513 }
514
515 let val = self.get_value(alloc).unwrap_or(&default_val);
516 trace!(
517 "checker: checkinst {:?}: op {:?}, alloc {:?}, checker value {:?}",
518 checkinst,
519 op,
520 alloc,
521 val
522 );
523 self.check_val(inst, *op, *alloc, val, allocs, checker)?;
524 }
525 }
526 &CheckerInst::Safepoint { inst, ref allocs } => {
527 for &alloc in allocs {
528 let val = self.get_value(&alloc).unwrap_or(&default_val);
529 trace!(
530 "checker: checkinst {:?}: safepoint slot {}, checker value {:?}",
531 checkinst,
532 alloc,
533 val
534 );
535
536 let reffy = val
537 .vregs()
538 .expect("checker value should not be Universe set")
539 .iter()
540 .any(|vreg| checker.reftyped_vregs.contains(vreg));
541 if !reffy {
542 return Err(CheckerError::NonRefValuesInStackmap {
543 inst,
544 alloc,
545 vregs: val.vregs().unwrap().clone(),
546 });
547 }
548 }
549 }
550 &CheckerInst::Move { into, from } => {
551 let is_stack = |alloc: Allocation| {
553 if let Some(reg) = alloc.as_reg() {
554 checker.stack_pregs.contains(reg)
555 } else {
556 alloc.is_stack()
557 }
558 };
559 if is_stack(into) && is_stack(from) {
560 return Err(CheckerError::StackToStackMove { into, from });
561 }
562 }
563 &CheckerInst::ParallelMove { .. } => {
564 }
568 &CheckerInst::ProgramMove { inst, src, dst: _ } => {
569 if let OperandConstraint::FixedReg(preg) = src.constraint() {
572 let alloc = Allocation::reg(preg);
573 let val = self.get_value(&alloc).unwrap_or(&default_val);
574 trace!(
575 "checker: checkinst {:?}: cheker value in {:?} is {:?}",
576 checkinst,
577 alloc,
578 val
579 );
580 self.check_val(inst, src, alloc, val, &[alloc], checker)?;
581 }
582 }
587 }
588 Ok(())
589 }
590
591 fn update<'a, F: Function>(&mut self, checkinst: &CheckerInst, checker: &Checker<'a, F>) {
593 self.become_defined();
594
595 match checkinst {
596 &CheckerInst::Move { into, from } => {
597 if let Some(val) = self.get_value(&from).cloned() {
604 trace!(
605 "checker: checkinst {:?} updating: move {:?} -> {:?} val {:?}",
606 checkinst,
607 from,
608 into,
609 val
610 );
611 self.set_value(into, val);
612 }
613 }
614 &CheckerInst::ParallelMove { ref moves } => {
615 let mut additions: FxHashMap<VReg, SmallVec<[VReg; 2]>> = FxHashMap::default();
622 let mut deletions: FxHashSet<VReg> = FxHashSet::default();
623
624 for &(dest, src) in moves {
625 deletions.insert(dest);
626 additions
627 .entry(src)
628 .or_insert_with(|| smallvec![])
629 .push(dest);
630 }
631
632 for value in self.get_values_mut() {
637 if let Some(vregs) = value.vregs_mut() {
638 let mut insertions: SmallVec<[VReg; 2]> = smallvec![];
639 for &vreg in vregs.iter() {
640 if let Some(additions) = additions.get(&vreg) {
641 insertions.extend(additions.iter().cloned());
642 }
643 }
644 for &d in &deletions {
645 vregs.remove(&d);
646 }
647 vregs.extend(insertions);
648 }
649 }
650 }
651 &CheckerInst::Op {
652 ref operands,
653 ref allocs,
654 ref clobbers,
655 ..
656 } => {
657 for (op, alloc) in operands.iter().zip(allocs.iter()) {
662 if op.kind() != OperandKind::Def {
663 continue;
664 }
665 self.remove_vreg(op.vreg());
666 self.set_value(*alloc, CheckerValue::from_reg(op.vreg()));
667 }
668 for clobber in clobbers {
669 self.remove_value(&Allocation::reg(*clobber));
670 }
671 }
672 &CheckerInst::Safepoint { ref allocs, .. } => {
673 for (alloc, value) in self.get_mappings_mut() {
674 if alloc.is_reg() {
675 continue;
676 }
677 if !allocs.contains(&alloc) {
678 let new_vregs = value
680 .vregs()
681 .unwrap()
682 .difference(&checker.reftyped_vregs)
683 .cloned()
684 .collect();
685 *value = CheckerValue::VRegs(new_vregs);
686 }
687 }
688 }
689 &CheckerInst::ProgramMove { inst: _, src, dst } => {
690 self.remove_vreg(dst.vreg());
693 for (_, value) in self.get_mappings_mut() {
695 value.copy_vreg(src.vreg(), dst.vreg());
696 }
697 }
698 }
699 }
700
701 fn remove_vreg(&mut self, vreg: VReg) {
702 for (_, value) in self.get_mappings_mut() {
703 value.remove_vreg(vreg);
704 }
705 }
706
707 fn check_constraint<'a, F: Function>(
708 &self,
709 inst: Inst,
710 op: Operand,
711 alloc: Allocation,
712 allocs: &[Allocation],
713 checker: &Checker<'a, F>,
714 ) -> Result<(), CheckerError> {
715 match op.constraint() {
716 OperandConstraint::Any => {}
717 OperandConstraint::Reg => {
718 if let Some(preg) = alloc.as_reg() {
719 if !checker.machine_env.fixed_stack_slots.contains(&preg) {
721 return Ok(());
722 }
723 }
724 return Err(CheckerError::AllocationIsNotReg { inst, op, alloc });
725 }
726 OperandConstraint::Stack => {
727 if alloc.kind() != AllocationKind::Stack {
728 if let Some(preg) = alloc.as_reg() {
730 if checker.machine_env.fixed_stack_slots.contains(&preg) {
731 return Ok(());
732 }
733 }
734 return Err(CheckerError::AllocationIsNotStack { inst, op, alloc });
735 }
736 }
737 OperandConstraint::FixedReg(preg) => {
738 if alloc != Allocation::reg(preg) {
739 return Err(CheckerError::AllocationIsNotFixedReg { inst, op, alloc });
740 }
741 }
742 OperandConstraint::Reuse(idx) => {
743 if alloc.kind() != AllocationKind::Reg {
744 return Err(CheckerError::AllocationIsNotReg { inst, op, alloc });
745 }
746 if alloc != allocs[idx] {
747 return Err(CheckerError::AllocationIsNotReuse {
748 inst,
749 op,
750 alloc,
751 expected_alloc: allocs[idx],
752 });
753 }
754 }
755 }
756 Ok(())
757 }
758}
759
760#[derive(Clone, Debug)]
762pub(crate) enum CheckerInst {
763 Move { into: Allocation, from: Allocation },
766
767 ParallelMove {
772 moves: Vec<(VReg, VReg)>,
774 },
775
776 Op {
780 inst: Inst,
781 operands: Vec<Operand>,
782 allocs: Vec<Allocation>,
783 clobbers: Vec<PReg>,
784 },
785
786 Safepoint { inst: Inst, allocs: Vec<Allocation> },
789
790 ProgramMove {
802 inst: Inst,
803 src: Operand,
804 dst: Operand,
805 },
806}
807
808#[derive(Debug)]
809pub struct Checker<'a, F: Function> {
810 f: &'a F,
811 bb_in: FxHashMap<Block, CheckerState>,
812 bb_insts: FxHashMap<Block, Vec<CheckerInst>>,
813 edge_insts: FxHashMap<(Block, Block), Vec<CheckerInst>>,
814 reftyped_vregs: FxHashSet<VReg>,
815 machine_env: &'a MachineEnv,
816 stack_pregs: PRegSet,
817}
818
819impl<'a, F: Function> Checker<'a, F> {
820 pub fn new(f: &'a F, machine_env: &'a MachineEnv) -> Checker<'a, F> {
825 let mut bb_in = FxHashMap::default();
826 let mut bb_insts = FxHashMap::default();
827 let mut edge_insts = FxHashMap::default();
828 let mut reftyped_vregs = FxHashSet::default();
829
830 for block in 0..f.num_blocks() {
831 let block = Block::new(block);
832 bb_in.insert(block, Default::default());
833 bb_insts.insert(block, vec![]);
834 for &succ in f.block_succs(block) {
835 edge_insts.insert((block, succ), vec![]);
836 }
837 }
838
839 for &vreg in f.reftype_vregs() {
840 reftyped_vregs.insert(vreg);
841 }
842
843 bb_in.insert(f.entry_block(), CheckerState::default());
844
845 let mut stack_pregs = PRegSet::empty();
846 for &preg in &machine_env.fixed_stack_slots {
847 stack_pregs.add(preg);
848 }
849
850 Checker {
851 f,
852 bb_in,
853 bb_insts,
854 edge_insts,
855 reftyped_vregs,
856 machine_env,
857 stack_pregs,
858 }
859 }
860
861 pub fn prepare(&mut self, out: &Output) {
864 trace!("checker: out = {:?}", out);
865 let mut safepoint_slots: FxHashMap<Inst, Vec<Allocation>> = FxHashMap::default();
867 for &(progpoint, slot) in &out.safepoint_slots {
868 safepoint_slots
869 .entry(progpoint.inst())
870 .or_insert_with(|| vec![])
871 .push(slot);
872 }
873
874 let mut last_inst = None;
875 for block in 0..self.f.num_blocks() {
876 let block = Block::new(block);
877 for inst_or_edit in out.block_insts_and_edits(self.f, block) {
878 match inst_or_edit {
879 InstOrEdit::Inst(inst) => {
880 debug_assert!(last_inst.is_none() || inst > last_inst.unwrap());
881 last_inst = Some(inst);
882 self.handle_inst(block, inst, &mut safepoint_slots, out);
883 }
884 InstOrEdit::Edit(edit) => self.handle_edit(block, edit),
885 }
886 }
887 }
888 }
889
890 fn handle_inst(
892 &mut self,
893 block: Block,
894 inst: Inst,
895 safepoint_slots: &mut FxHashMap<Inst, Vec<Allocation>>,
896 out: &Output,
897 ) {
898 if self.f.requires_refs_on_stack(inst) {
900 let allocs = safepoint_slots.remove(&inst).unwrap_or_else(|| vec![]);
901
902 let checkinst = CheckerInst::Safepoint { inst, allocs };
903 self.bb_insts.get_mut(&block).unwrap().push(checkinst);
904 }
905
906 if let Some((src, dst)) = self.f.is_move(inst) {
921 let src_op = Operand::any_use(src.vreg());
922 let dst_op = Operand::any_def(dst.vreg());
923 let checkinst = CheckerInst::ProgramMove {
924 inst,
925 src: src_op,
926 dst: dst_op,
927 };
928 trace!("checker: adding inst {:?}", checkinst);
929 self.bb_insts.get_mut(&block).unwrap().push(checkinst);
930 }
931 else if !self.f.is_branch(inst) {
935 let operands: Vec<_> = self.f.inst_operands(inst).iter().cloned().collect();
936 let allocs: Vec<_> = out.inst_allocs(inst).iter().cloned().collect();
937 let clobbers: Vec<_> = self.f.inst_clobbers(inst).into_iter().collect();
938 let checkinst = CheckerInst::Op {
939 inst,
940 operands,
941 allocs,
942 clobbers,
943 };
944 trace!("checker: adding inst {:?}", checkinst);
945 self.bb_insts.get_mut(&block).unwrap().push(checkinst);
946 }
947 else {
950 for (i, &succ) in self.f.block_succs(block).iter().enumerate() {
951 let args = self.f.branch_blockparams(block, inst, i);
952 let params = self.f.block_params(succ);
953 assert_eq!(
954 args.len(),
955 params.len(),
956 "block{} has succ block{}; gave {} args for {} params",
957 block.index(),
958 succ.index(),
959 args.len(),
960 params.len()
961 );
962 if args.len() > 0 {
963 let moves = params.iter().cloned().zip(args.iter().cloned()).collect();
964 self.edge_insts
965 .get_mut(&(block, succ))
966 .unwrap()
967 .push(CheckerInst::ParallelMove { moves });
968 }
969 }
970 }
971 }
972
973 fn handle_edit(&mut self, block: Block, edit: &Edit) {
974 trace!("checker: adding edit {:?}", edit);
975 match edit {
976 &Edit::Move { from, to } => {
977 self.bb_insts
978 .get_mut(&block)
979 .unwrap()
980 .push(CheckerInst::Move { into: to, from });
981 }
982 }
983 }
984
985 fn analyze(&mut self) {
987 let mut queue = Vec::new();
988 let mut queue_set = FxHashSet::default();
989
990 for block in (0..self.f.num_blocks()).rev() {
999 let block = Block::new(block);
1000 queue.push(block);
1001 queue_set.insert(block);
1002 }
1003
1004 while let Some(block) = queue.pop() {
1005 queue_set.remove(&block);
1006 let mut state = self.bb_in.get(&block).cloned().unwrap();
1007 trace!("analyze: block {} has state {:?}", block.index(), state);
1008 for inst in self.bb_insts.get(&block).unwrap() {
1009 state.update(inst, self);
1010 trace!("analyze: inst {:?} -> state {:?}", inst, state);
1011 }
1012
1013 for &succ in self.f.block_succs(block) {
1014 let mut new_state = state.clone();
1015 for edge_inst in self.edge_insts.get(&(block, succ)).unwrap() {
1016 new_state.update(edge_inst, self);
1017 trace!(
1018 "analyze: succ {:?}: inst {:?} -> state {:?}",
1019 succ,
1020 edge_inst,
1021 new_state
1022 );
1023 }
1024
1025 let cur_succ_in = self.bb_in.get(&succ).unwrap();
1026 trace!(
1027 "meeting state {:?} for block {} with state {:?} for block {}",
1028 new_state,
1029 block.index(),
1030 cur_succ_in,
1031 succ.index()
1032 );
1033 new_state.meet_with(cur_succ_in);
1034 let changed = &new_state != cur_succ_in;
1035 trace!(" -> {:?}, changed {}", new_state, changed);
1036
1037 if changed {
1038 trace!(
1039 "analyze: block {} state changed from {:?} to {:?}; pushing onto queue",
1040 succ.index(),
1041 cur_succ_in,
1042 new_state
1043 );
1044 self.bb_in.insert(succ, new_state);
1045 if queue_set.insert(succ) {
1046 queue.push(succ);
1047 }
1048 }
1049 }
1050 }
1051 }
1052
1053 fn find_errors(&self) -> Result<(), CheckerErrors> {
1057 let mut errors = vec![];
1058 for (block, input) in &self.bb_in {
1059 let mut state = input.clone();
1060 for inst in self.bb_insts.get(block).unwrap() {
1061 if let Err(e) = state.check(InstPosition::Before, inst, self) {
1062 trace!("Checker error: {:?}", e);
1063 errors.push(e);
1064 }
1065 state.update(inst, self);
1066 if let Err(e) = state.check(InstPosition::After, inst, self) {
1067 trace!("Checker error: {:?}", e);
1068 errors.push(e);
1069 }
1070 }
1071 }
1072
1073 if errors.is_empty() {
1074 Ok(())
1075 } else {
1076 Err(CheckerErrors { errors })
1077 }
1078 }
1079
1080 pub fn run(mut self) -> Result<(), CheckerErrors> {
1083 self.analyze();
1084 let result = self.find_errors();
1085
1086 trace!("=== CHECKER RESULT ===");
1087 fn print_state(state: &CheckerState) {
1088 if let CheckerState::Allocations(allocs) = state {
1089 let mut s = vec![];
1090 for (alloc, state) in allocs {
1091 s.push(format!("{} := {}", alloc, state));
1092 }
1093 trace!(" {{ {} }}", s.join(", "))
1094 }
1095 }
1096 for vreg in self.f.reftype_vregs() {
1097 trace!(" REF: {}", vreg);
1098 }
1099 for bb in 0..self.f.num_blocks() {
1100 let bb = Block::new(bb);
1101 trace!("block{}:", bb.index());
1102 let insts = self.bb_insts.get(&bb).unwrap();
1103 let mut state = self.bb_in.get(&bb).unwrap().clone();
1104 print_state(&state);
1105 for inst in insts {
1106 match inst {
1107 &CheckerInst::Op {
1108 inst,
1109 ref operands,
1110 ref allocs,
1111 ref clobbers,
1112 } => {
1113 trace!(
1114 " inst{}: {:?} ({:?}) clobbers:{:?}",
1115 inst.index(),
1116 operands,
1117 allocs,
1118 clobbers
1119 );
1120 }
1121 &CheckerInst::Move { from, into } => {
1122 trace!(" {} -> {}", from, into);
1123 }
1124 &CheckerInst::Safepoint { ref allocs, .. } => {
1125 let mut slotargs = vec![];
1126 for &slot in allocs {
1127 slotargs.push(format!("{}", slot));
1128 }
1129 trace!(" safepoint: {}", slotargs.join(", "));
1130 }
1131 &CheckerInst::ProgramMove { inst, src, dst } => {
1132 trace!(" inst{}: prog_move {} -> {}", inst.index(), src, dst);
1133 }
1134 &CheckerInst::ParallelMove { .. } => {
1135 panic!("unexpected parallel_move in body (non-edge)")
1136 }
1137 }
1138 state.update(inst, &self);
1139 print_state(&state);
1140 }
1141
1142 for &succ in self.f.block_succs(bb) {
1143 trace!(" succ {:?}:", succ);
1144 let mut state = state.clone();
1145 for edge_inst in self.edge_insts.get(&(bb, succ)).unwrap() {
1146 match edge_inst {
1147 &CheckerInst::ParallelMove { ref moves } => {
1148 let moves = moves
1149 .iter()
1150 .map(|(dest, src)| format!("{} -> {}", src, dest))
1151 .collect::<Vec<_>>();
1152 trace!(" parallel_move {}", moves.join(", "));
1153 }
1154 _ => panic!("unexpected edge_inst: not a parallel move"),
1155 }
1156 state.update(edge_inst, &self);
1157 print_state(&state);
1158 }
1159 }
1160 }
1161
1162 result
1163 }
1164}