@@ -30,18 +30,6 @@ pub struct InstData {
30
30
}
31
31
32
32
impl InstData {
33
- pub fn op ( def : usize , uses : & [ usize ] ) -> InstData {
34
- let mut operands = vec ! [ Operand :: reg_def( VReg :: new( def, RegClass :: Int ) ) ] ;
35
- for & u in uses {
36
- operands. push ( Operand :: reg_use ( VReg :: new ( u, RegClass :: Int ) ) ) ;
37
- }
38
- InstData {
39
- op : InstOpcode :: Op ,
40
- operands,
41
- clobbers : vec ! [ ] ,
42
- is_safepoint : false ,
43
- }
44
- }
45
33
pub fn branch ( ) -> InstData {
46
34
InstData {
47
35
op : InstOpcode :: Branch ,
@@ -145,8 +133,10 @@ impl Function for Func {
145
133
146
134
fn spillslot_size ( & self , regclass : RegClass ) -> usize {
147
135
match regclass {
136
+ // Test the case where 2 classes share the same
148
137
RegClass :: Int => 1 ,
149
- RegClass :: Float | RegClass :: Vector => 2 ,
138
+ RegClass :: Float => 1 ,
139
+ RegClass :: Vector => 2 ,
150
140
}
151
141
}
152
142
}
@@ -234,6 +224,12 @@ impl FuncBuilder {
234
224
}
235
225
}
236
226
227
+ impl Arbitrary < ' _ > for RegClass {
228
+ fn arbitrary ( u : & mut Unstructured ) -> ArbitraryResult < Self > {
229
+ Ok ( * u. choose ( & [ RegClass :: Int , RegClass :: Float , RegClass :: Vector ] ) ?)
230
+ }
231
+ }
232
+
237
233
impl Arbitrary < ' _ > for OperandConstraint {
238
234
fn arbitrary ( u : & mut Unstructured ) -> ArbitraryResult < Self > {
239
235
Ok ( * u. choose ( & [ OperandConstraint :: Any , OperandConstraint :: Reg ] ) ?)
@@ -380,7 +376,7 @@ impl Func {
380
376
for block in 0 ..num_blocks {
381
377
let mut vregs = vec ! [ ] ;
382
378
for _ in 0 ..u. int_in_range ( 5 ..=15 ) ? {
383
- let vreg = VReg :: new ( builder. f . num_vregs , RegClass :: Int ) ;
379
+ let vreg = VReg :: new ( builder. f . num_vregs , RegClass :: arbitrary ( u ) ? ) ;
384
380
builder. f . num_vregs += 1 ;
385
381
vregs. push ( vreg) ;
386
382
if opts. reftypes && bool:: arbitrary ( u) ? {
@@ -476,28 +472,30 @@ impl Func {
476
472
let op = operands[ 0 ] ;
477
473
debug_assert_eq ! ( op. kind( ) , OperandKind :: Def ) ;
478
474
let reused = u. int_in_range ( 1 ..=( operands. len ( ) - 1 ) ) ?;
479
- operands[ 0 ] = Operand :: new (
480
- op. vreg ( ) ,
481
- OperandConstraint :: Reuse ( reused) ,
482
- op. kind ( ) ,
483
- OperandPos :: Late ,
484
- ) ;
485
- // Make sure reused input is a Reg.
486
- let op = operands[ reused] ;
487
- operands[ reused] = Operand :: new (
488
- op. vreg ( ) ,
489
- OperandConstraint :: Reg ,
490
- op. kind ( ) ,
491
- OperandPos :: Early ,
492
- ) ;
475
+ if op. class ( ) == operands[ reused] . class ( ) {
476
+ operands[ 0 ] = Operand :: new (
477
+ op. vreg ( ) ,
478
+ OperandConstraint :: Reuse ( reused) ,
479
+ op. kind ( ) ,
480
+ OperandPos :: Late ,
481
+ ) ;
482
+ // Make sure reused input is a Reg.
483
+ let op = operands[ reused] ;
484
+ operands[ reused] = Operand :: new (
485
+ op. vreg ( ) ,
486
+ OperandConstraint :: Reg ,
487
+ op. kind ( ) ,
488
+ OperandPos :: Early ,
489
+ ) ;
490
+ }
493
491
} else if opts. fixed_regs && bool:: arbitrary ( u) ? {
494
492
let mut fixed_early = vec ! [ ] ;
495
493
let mut fixed_late = vec ! [ ] ;
496
494
for _ in 0 ..u. int_in_range ( 0 ..=operands. len ( ) - 1 ) ? {
497
495
// Pick an operand and make it a fixed reg.
498
496
let i = u. int_in_range ( 0 ..=( operands. len ( ) - 1 ) ) ?;
499
497
let op = operands[ i] ;
500
- let fixed_reg = PReg :: new ( u. int_in_range ( 0 ..=62 ) ?, RegClass :: Int ) ;
498
+ let fixed_reg = PReg :: new ( u. int_in_range ( 0 ..=62 ) ?, op . class ( ) ) ;
501
499
let fixed_list = match op. pos ( ) {
502
500
OperandPos :: Early => & mut fixed_early,
503
501
OperandPos :: Late => & mut fixed_late,
@@ -535,10 +533,13 @@ impl Func {
535
533
if clobbers. iter ( ) . any ( |r| r. hw_enc ( ) == reg) {
536
534
break ;
537
535
}
538
- clobbers. push ( PReg :: new ( reg, RegClass :: Int ) ) ;
536
+ clobbers. push ( PReg :: new ( reg, RegClass :: arbitrary ( u ) ? ) ) ;
539
537
}
540
538
} else if opts. fixed_nonallocatable && bool:: arbitrary ( u) ? {
541
- operands. push ( Operand :: fixed_nonallocatable ( PReg :: new ( 63 , RegClass :: Int ) ) ) ;
539
+ operands. push ( Operand :: fixed_nonallocatable ( PReg :: new (
540
+ 63 ,
541
+ RegClass :: arbitrary ( u) ?,
542
+ ) ) ) ;
542
543
}
543
544
544
545
let is_safepoint = opts. reftypes
@@ -565,18 +566,30 @@ impl Func {
565
566
let mut params = vec ! [ ] ;
566
567
for & succ in & builder. f . block_succs [ block] {
567
568
let mut args = vec ! [ ] ;
568
- for _ in 0 ..builder. f . block_params_in [ succ. index ( ) ] . len ( ) {
569
+ for i in 0 ..builder. f . block_params_in [ succ. index ( ) ] . len ( ) {
569
570
let dom_block = choose_dominating_block (
570
571
& builder. idom [ ..] ,
571
572
Block :: new ( block) ,
572
573
false ,
573
574
u,
574
575
) ?;
575
- let vreg = if dom_block. is_valid ( ) && bool:: arbitrary ( u) ? {
576
- u. choose ( & vregs_by_block[ dom_block. index ( ) ] [ ..] ) ?
576
+
577
+ // Look for a vreg with a suitable class. If no
578
+ // suitable vreg is available then we error out, which
579
+ // causes the fuzzer to skip this function.
580
+ let vregs = if dom_block. is_valid ( ) && bool:: arbitrary ( u) ? {
581
+ & vregs_by_block[ dom_block. index ( ) ] [ ..]
577
582
} else {
578
- u . choose ( & avail[ ..] ) ?
583
+ & avail[ ..]
579
584
} ;
585
+ let suitable_vregs: Vec < _ > = vregs
586
+ . iter ( )
587
+ . filter ( |vreg| {
588
+ vreg. class ( ) == builder. f . block_params_in [ succ. index ( ) ] [ i] . class ( )
589
+ } )
590
+ . copied ( )
591
+ . collect ( ) ;
592
+ let vreg = u. choose ( & suitable_vregs) ?;
580
593
args. push ( * vreg) ;
581
594
}
582
595
params. push ( args) ;
@@ -656,13 +669,29 @@ impl core::fmt::Debug for Func {
656
669
}
657
670
658
671
pub fn machine_env ( ) -> MachineEnv {
659
- fn regs ( r : core:: ops:: Range < usize > ) -> Vec < PReg > {
660
- r. map ( |i| PReg :: new ( i, RegClass :: Int ) ) . collect ( )
661
- }
662
- let preferred_regs_by_class: [ Vec < PReg > ; 3 ] = [ regs ( 0 ..24 ) , vec ! [ ] , vec ! [ ] ] ;
663
- let non_preferred_regs_by_class: [ Vec < PReg > ; 3 ] = [ regs ( 24 ..32 ) , vec ! [ ] , vec ! [ ] ] ;
672
+ fn regs ( r : core:: ops:: Range < usize > , c : RegClass ) -> Vec < PReg > {
673
+ r. map ( |i| PReg :: new ( i, c) ) . collect ( )
674
+ }
675
+ let preferred_regs_by_class: [ Vec < PReg > ; 3 ] = [
676
+ regs ( 0 ..24 , RegClass :: Int ) ,
677
+ regs ( 0 ..24 , RegClass :: Float ) ,
678
+ regs ( 0 ..24 , RegClass :: Vector ) ,
679
+ ] ;
680
+ let non_preferred_regs_by_class: [ Vec < PReg > ; 3 ] = [
681
+ regs ( 24 ..32 , RegClass :: Int ) ,
682
+ regs ( 24 ..32 , RegClass :: Float ) ,
683
+ regs ( 24 ..32 , RegClass :: Vector ) ,
684
+ ] ;
664
685
let scratch_by_class: [ Option < PReg > ; 3 ] = [ None , None , None ] ;
665
- let fixed_stack_slots = regs ( 32 ..63 ) ;
686
+ let fixed_stack_slots = ( 32 ..63 )
687
+ . flat_map ( |i| {
688
+ [
689
+ PReg :: new ( i, RegClass :: Int ) ,
690
+ PReg :: new ( i, RegClass :: Float ) ,
691
+ PReg :: new ( i, RegClass :: Vector ) ,
692
+ ]
693
+ } )
694
+ . collect ( ) ;
666
695
// Register 63 is reserved for use as a fixed non-allocatable register.
667
696
MachineEnv {
668
697
preferred_regs_by_class,
0 commit comments