67
67
68
68
use crate :: {
69
69
Allocation , AllocationKind , Block , Edit , Function , Inst , InstPosition , Operand , OperandKind ,
70
- OperandPolicy , OperandPos , Output , ProgPoint , VReg ,
70
+ OperandPolicy , OperandPos , Output , PReg , ProgPoint , SpillSlot , VReg ,
71
71
} ;
72
72
73
- use std:: collections:: { HashMap , VecDeque } ;
73
+ use std:: collections:: { HashMap , HashSet , VecDeque } ;
74
74
use std:: default:: Default ;
75
75
use std:: hash:: Hash ;
76
76
use std:: result:: Result ;
@@ -127,6 +127,20 @@ pub enum CheckerError {
127
127
alloc : Allocation ,
128
128
expected_alloc : Allocation ,
129
129
} ,
130
+ AllocationIsNotStack {
131
+ inst : Inst ,
132
+ op : Operand ,
133
+ alloc : Allocation ,
134
+ } ,
135
+ ConflictedValueInStackmap {
136
+ inst : Inst ,
137
+ slot : SpillSlot ,
138
+ } ,
139
+ NonRefValueInStackmap {
140
+ inst : Inst ,
141
+ slot : SpillSlot ,
142
+ vreg : VReg ,
143
+ } ,
130
144
}
131
145
132
146
/// Abstract state for an allocation.
@@ -162,8 +176,10 @@ impl CheckerValue {
162
176
( _, & CheckerValue :: Unknown ) => * self ,
163
177
( & CheckerValue :: Conflicted , _) => * self ,
164
178
( _, & CheckerValue :: Conflicted ) => * other,
165
- ( & CheckerValue :: Reg ( r1, ref1) , & CheckerValue :: Reg ( r2, ref2) ) if r1 == r2 => {
166
- CheckerValue :: Reg ( r1, ref1 || ref2)
179
+ ( & CheckerValue :: Reg ( r1, ref1) , & CheckerValue :: Reg ( r2, ref2) )
180
+ if r1 == r2 && ref1 == ref2 =>
181
+ {
182
+ CheckerValue :: Reg ( r1, ref1)
167
183
}
168
184
_ => {
169
185
log:: debug!( "{:?} and {:?} meet to Conflicted" , self , other) ;
@@ -192,7 +208,8 @@ impl std::fmt::Display for CheckerValue {
192
208
match self {
193
209
CheckerValue :: Unknown => write ! ( f, "?" ) ,
194
210
CheckerValue :: Conflicted => write ! ( f, "!" ) ,
195
- CheckerValue :: Reg ( r, _) => write ! ( f, "{}" , r) ,
211
+ CheckerValue :: Reg ( r, false ) => write ! ( f, "{}" , r) ,
212
+ CheckerValue :: Reg ( r, true ) => write ! ( f, "{}/ref" , r) ,
196
213
}
197
214
}
198
215
}
@@ -305,13 +322,38 @@ impl CheckerState {
305
322
self . check_val ( inst, * op, * alloc, val, allocs) ?;
306
323
}
307
324
}
325
+ & CheckerInst :: Safepoint { inst, ref slots } => {
326
+ for & slot in slots {
327
+ let alloc = Allocation :: stack ( slot) ;
328
+ let val = self
329
+ . allocations
330
+ . get ( & alloc)
331
+ . cloned ( )
332
+ . unwrap_or ( Default :: default ( ) ) ;
333
+ debug ! (
334
+ "checker: checkinst {:?}: safepoint slot {}, checker value {:?}" ,
335
+ checkinst, slot, val
336
+ ) ;
337
+
338
+ match val {
339
+ CheckerValue :: Unknown => { }
340
+ CheckerValue :: Conflicted => {
341
+ return Err ( CheckerError :: ConflictedValueInStackmap { inst, slot } ) ;
342
+ }
343
+ CheckerValue :: Reg ( vreg, false ) => {
344
+ return Err ( CheckerError :: NonRefValueInStackmap { inst, slot, vreg } ) ;
345
+ }
346
+ CheckerValue :: Reg ( _, true ) => { }
347
+ }
348
+ }
349
+ }
308
350
_ => { }
309
351
}
310
352
Ok ( ( ) )
311
353
}
312
354
313
355
/// Update according to instruction.
314
- fn update ( & mut self , checkinst : & CheckerInst ) {
356
+ fn update < ' a , F : Function > ( & mut self , checkinst : & CheckerInst , checker : & Checker < ' a , F > ) {
315
357
match checkinst {
316
358
& CheckerInst :: Move { into, from } => {
317
359
let val = self
@@ -328,14 +370,19 @@ impl CheckerState {
328
370
& CheckerInst :: Op {
329
371
ref operands,
330
372
ref allocs,
373
+ ref clobbers,
331
374
..
332
375
} => {
333
376
for ( op, alloc) in operands. iter ( ) . zip ( allocs. iter ( ) ) {
334
377
if op. kind ( ) != OperandKind :: Def {
335
378
continue ;
336
379
}
380
+ let reftyped = checker. reftyped_vregs . contains ( & op. vreg ( ) ) ;
337
381
self . allocations
338
- . insert ( * alloc, CheckerValue :: Reg ( op. vreg ( ) , false ) ) ;
382
+ . insert ( * alloc, CheckerValue :: Reg ( op. vreg ( ) , reftyped) ) ;
383
+ }
384
+ for clobber in clobbers {
385
+ self . allocations . remove ( & Allocation :: reg ( * clobber) ) ;
339
386
}
340
387
}
341
388
& CheckerInst :: BlockParams {
@@ -344,8 +391,20 @@ impl CheckerState {
344
391
..
345
392
} => {
346
393
for ( vreg, alloc) in vregs. iter ( ) . zip ( allocs. iter ( ) ) {
394
+ let reftyped = checker. reftyped_vregs . contains ( vreg) ;
347
395
self . allocations
348
- . insert ( * alloc, CheckerValue :: Reg ( * vreg, false ) ) ;
396
+ . insert ( * alloc, CheckerValue :: Reg ( * vreg, reftyped) ) ;
397
+ }
398
+ }
399
+ & CheckerInst :: Safepoint { ref slots, .. } => {
400
+ for ( alloc, value) in & mut self . allocations {
401
+ if let CheckerValue :: Reg ( _, true ) = * value {
402
+ if alloc. is_reg ( ) {
403
+ * value = CheckerValue :: Conflicted ;
404
+ } else if alloc. is_stack ( ) && !slots. contains ( & alloc. as_stack ( ) . unwrap ( ) ) {
405
+ * value = CheckerValue :: Conflicted ;
406
+ }
407
+ }
349
408
}
350
409
}
351
410
}
@@ -365,6 +424,11 @@ impl CheckerState {
365
424
return Err ( CheckerError :: AllocationIsNotReg { inst, op, alloc } ) ;
366
425
}
367
426
}
427
+ OperandPolicy :: Stack => {
428
+ if alloc. kind ( ) != AllocationKind :: Stack {
429
+ return Err ( CheckerError :: AllocationIsNotStack { inst, op, alloc } ) ;
430
+ }
431
+ }
368
432
OperandPolicy :: FixedReg ( preg) => {
369
433
if alloc != Allocation :: reg ( preg) {
370
434
return Err ( CheckerError :: AllocationIsNotFixedReg { inst, op, alloc } ) ;
@@ -402,6 +466,7 @@ pub(crate) enum CheckerInst {
402
466
inst : Inst ,
403
467
operands : Vec < Operand > ,
404
468
allocs : Vec < Allocation > ,
469
+ clobbers : Vec < PReg > ,
405
470
} ,
406
471
407
472
/// The top of a block with blockparams. We define the given vregs
@@ -411,13 +476,18 @@ pub(crate) enum CheckerInst {
411
476
vregs : Vec < VReg > ,
412
477
allocs : Vec < Allocation > ,
413
478
} ,
479
+
480
+ /// A safepoint, with the given SpillSlots specified as containing
481
+ /// reftyped values. All other reftyped values become invalid.
482
+ Safepoint { inst : Inst , slots : Vec < SpillSlot > } ,
414
483
}
415
484
416
485
#[ derive( Debug ) ]
417
486
pub struct Checker < ' a , F : Function > {
418
487
f : & ' a F ,
419
488
bb_in : HashMap < Block , CheckerState > ,
420
489
bb_insts : HashMap < Block , Vec < CheckerInst > > ,
490
+ reftyped_vregs : HashSet < VReg > ,
421
491
}
422
492
423
493
impl < ' a , F : Function > Checker < ' a , F > {
@@ -428,20 +498,39 @@ impl<'a, F: Function> Checker<'a, F> {
428
498
pub fn new ( f : & ' a F ) -> Checker < ' a , F > {
429
499
let mut bb_in = HashMap :: new ( ) ;
430
500
let mut bb_insts = HashMap :: new ( ) ;
501
+ let mut reftyped_vregs = HashSet :: new ( ) ;
431
502
432
503
for block in 0 ..f. blocks ( ) {
433
504
let block = Block :: new ( block) ;
434
505
bb_in. insert ( block, Default :: default ( ) ) ;
435
506
bb_insts. insert ( block, vec ! [ ] ) ;
436
507
}
437
508
438
- Checker { f, bb_in, bb_insts }
509
+ for & vreg in f. reftype_vregs ( ) {
510
+ reftyped_vregs. insert ( vreg) ;
511
+ }
512
+
513
+ Checker {
514
+ f,
515
+ bb_in,
516
+ bb_insts,
517
+ reftyped_vregs,
518
+ }
439
519
}
440
520
441
521
/// Build the list of checker instructions based on the given func
442
522
/// and allocation results.
443
523
pub fn prepare ( & mut self , out : & Output ) {
444
524
debug ! ( "checker: out = {:?}" , out) ;
525
+ // Preprocess safepoint stack-maps into per-inst vecs.
526
+ let mut safepoint_slots: HashMap < Inst , Vec < SpillSlot > > = HashMap :: new ( ) ;
527
+ for & ( progpoint, slot) in & out. safepoint_slots {
528
+ safepoint_slots
529
+ . entry ( progpoint. inst )
530
+ . or_insert_with ( || vec ! [ ] )
531
+ . push ( slot) ;
532
+ }
533
+
445
534
// For each original instruction, create an `Op`.
446
535
let mut last_inst = None ;
447
536
let mut insert_idx = 0 ;
@@ -454,13 +543,23 @@ impl<'a, F: Function> Checker<'a, F> {
454
543
// Any inserted edits before instruction.
455
544
self . handle_edits ( block, out, & mut insert_idx, ProgPoint :: before ( inst) ) ;
456
545
546
+ // If this is a safepoint, then check the spillslots at this point.
547
+ if self . f . is_safepoint ( inst) {
548
+ let slots = safepoint_slots. remove ( & inst) . unwrap_or_else ( || vec ! [ ] ) ;
549
+
550
+ let checkinst = CheckerInst :: Safepoint { inst, slots } ;
551
+ self . bb_insts . get_mut ( & block) . unwrap ( ) . push ( checkinst) ;
552
+ }
553
+
457
554
// Instruction itself.
458
555
let operands: Vec < _ > = self . f . inst_operands ( inst) . iter ( ) . cloned ( ) . collect ( ) ;
459
556
let allocs: Vec < _ > = out. inst_allocs ( inst) . iter ( ) . cloned ( ) . collect ( ) ;
557
+ let clobbers: Vec < _ > = self . f . inst_clobbers ( inst) . iter ( ) . cloned ( ) . collect ( ) ;
460
558
let checkinst = CheckerInst :: Op {
461
559
inst,
462
560
operands,
463
561
allocs,
562
+ clobbers,
464
563
} ;
465
564
debug ! ( "checker: adding inst {:?}" , checkinst) ;
466
565
self . bb_insts . get_mut ( & block) . unwrap ( ) . push ( checkinst) ;
@@ -511,7 +610,7 @@ impl<'a, F: Function> Checker<'a, F> {
511
610
let mut state = self . bb_in . get ( & block) . cloned ( ) . unwrap ( ) ;
512
611
debug ! ( "analyze: block {} has state {:?}" , block. index( ) , state) ;
513
612
for inst in self . bb_insts . get ( & block) . unwrap ( ) {
514
- state. update ( inst) ;
613
+ state. update ( inst, self ) ;
515
614
debug ! ( "analyze: inst {:?} -> state {:?}" , inst, state) ;
516
615
}
517
616
@@ -546,7 +645,7 @@ impl<'a, F: Function> Checker<'a, F> {
546
645
debug ! ( "Checker error: {:?}" , e) ;
547
646
errors. push ( e) ;
548
647
}
549
- state. update ( inst) ;
648
+ state. update ( inst, self ) ;
550
649
if let Err ( e) = state. check ( InstPosition :: After , inst) {
551
650
debug ! ( "Checker error: {:?}" , e) ;
552
651
errors. push ( e) ;
@@ -575,6 +674,9 @@ impl<'a, F: Function> Checker<'a, F> {
575
674
}
576
675
debug ! ( " {{ {} }}" , s. join( ", " ) )
577
676
}
677
+ for vreg in self . f . reftype_vregs ( ) {
678
+ debug ! ( " REF: {}" , vreg) ;
679
+ }
578
680
for bb in 0 ..self . f . blocks ( ) {
579
681
let bb = Block :: new ( bb) ;
580
682
debug ! ( "block{}:" , bb. index( ) ) ;
@@ -587,8 +689,15 @@ impl<'a, F: Function> Checker<'a, F> {
587
689
inst,
588
690
ref operands,
589
691
ref allocs,
692
+ ref clobbers,
590
693
} => {
591
- debug ! ( " inst{}: {:?} ({:?})" , inst. index( ) , operands, allocs) ;
694
+ debug ! (
695
+ " inst{}: {:?} ({:?}) clobbers:{:?}" ,
696
+ inst. index( ) ,
697
+ operands,
698
+ allocs,
699
+ clobbers
700
+ ) ;
592
701
}
593
702
& CheckerInst :: Move { from, into } => {
594
703
debug ! ( " {} -> {}" , from, into) ;
@@ -604,8 +713,15 @@ impl<'a, F: Function> Checker<'a, F> {
604
713
}
605
714
debug ! ( " blockparams: {}" , args. join( ", " ) ) ;
606
715
}
716
+ & CheckerInst :: Safepoint { ref slots, .. } => {
717
+ let mut slotargs = vec ! [ ] ;
718
+ for & slot in slots {
719
+ slotargs. push ( format ! ( "{}" , slot) ) ;
720
+ }
721
+ debug ! ( " safepoint: {}" , slotargs. join( ", " ) ) ;
722
+ }
607
723
}
608
- state. update ( inst) ;
724
+ state. update ( inst, & self ) ;
609
725
print_state ( & state) ;
610
726
}
611
727
}
0 commit comments