@@ -30,18 +30,6 @@ pub struct InstData {
3030}
3131
3232impl 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- }
4533 pub fn branch ( ) -> InstData {
4634 InstData {
4735 op : InstOpcode :: Branch ,
@@ -145,8 +133,10 @@ impl Function for Func {
145133
146134 fn spillslot_size ( & self , regclass : RegClass ) -> usize {
147135 match regclass {
136+ // Test the case where 2 classes share the same
148137 RegClass :: Int => 1 ,
149- RegClass :: Float | RegClass :: Vector => 2 ,
138+ RegClass :: Float => 1 ,
139+ RegClass :: Vector => 2 ,
150140 }
151141 }
152142}
@@ -234,6 +224,12 @@ impl FuncBuilder {
234224 }
235225}
236226
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+
237233impl Arbitrary < ' _ > for OperandConstraint {
238234 fn arbitrary ( u : & mut Unstructured ) -> ArbitraryResult < Self > {
239235 Ok ( * u. choose ( & [ OperandConstraint :: Any , OperandConstraint :: Reg ] ) ?)
@@ -380,7 +376,7 @@ impl Func {
380376 for block in 0 ..num_blocks {
381377 let mut vregs = vec ! [ ] ;
382378 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 ) ? ) ;
384380 builder. f . num_vregs += 1 ;
385381 vregs. push ( vreg) ;
386382 if opts. reftypes && bool:: arbitrary ( u) ? {
@@ -476,28 +472,30 @@ impl Func {
476472 let op = operands[ 0 ] ;
477473 debug_assert_eq ! ( op. kind( ) , OperandKind :: Def ) ;
478474 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+ }
493491 } else if opts. fixed_regs && bool:: arbitrary ( u) ? {
494492 let mut fixed_early = vec ! [ ] ;
495493 let mut fixed_late = vec ! [ ] ;
496494 for _ in 0 ..u. int_in_range ( 0 ..=operands. len ( ) - 1 ) ? {
497495 // Pick an operand and make it a fixed reg.
498496 let i = u. int_in_range ( 0 ..=( operands. len ( ) - 1 ) ) ?;
499497 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 ( ) ) ;
501499 let fixed_list = match op. pos ( ) {
502500 OperandPos :: Early => & mut fixed_early,
503501 OperandPos :: Late => & mut fixed_late,
@@ -535,10 +533,13 @@ impl Func {
535533 if clobbers. iter ( ) . any ( |r| r. hw_enc ( ) == reg) {
536534 break ;
537535 }
538- clobbers. push ( PReg :: new ( reg, RegClass :: Int ) ) ;
536+ clobbers. push ( PReg :: new ( reg, RegClass :: arbitrary ( u ) ? ) ) ;
539537 }
540538 } 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+ ) ) ) ;
542543 }
543544
544545 let is_safepoint = opts. reftypes
@@ -565,18 +566,30 @@ impl Func {
565566 let mut params = vec ! [ ] ;
566567 for & succ in & builder. f . block_succs [ block] {
567568 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 ( ) {
569570 let dom_block = choose_dominating_block (
570571 & builder. idom [ ..] ,
571572 Block :: new ( block) ,
572573 false ,
573574 u,
574575 ) ?;
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 ( ) ] [ ..]
577582 } else {
578- u . choose ( & avail[ ..] ) ?
583+ & avail[ ..]
579584 } ;
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) ?;
580593 args. push ( * vreg) ;
581594 }
582595 params. push ( args) ;
@@ -656,13 +669,29 @@ impl core::fmt::Debug for Func {
656669}
657670
658671pub 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+ ] ;
664685 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 ( ) ;
666695 // Register 63 is reserved for use as a fixed non-allocatable register.
667696 MachineEnv {
668697 preferred_regs_by_class,
0 commit comments