@@ -207,6 +207,27 @@ impl FuncBuilder {
207207 ) ;
208208 }
209209
210+ fn add_arbitrary_debug_labels (
211+ & mut self ,
212+ u : & mut Unstructured < ' _ > ,
213+ num_blocks : usize ,
214+ vreg : VReg ,
215+ ) -> ArbitraryResult < ( ) > {
216+ let assumed_end_inst = 10 * num_blocks;
217+ let mut start = u. int_in_range :: < usize > ( 0 ..=assumed_end_inst) ?;
218+ Ok ( for _ in 0 ..10 {
219+ if start >= assumed_end_inst {
220+ break ;
221+ }
222+ let end = u. int_in_range :: < usize > ( start..=assumed_end_inst) ?;
223+ let label = u. int_in_range :: < u32 > ( 0 ..=100 ) ?;
224+ self . f
225+ . debug_value_labels
226+ . push ( ( vreg, Inst :: new ( start) , Inst :: new ( end) , label) ) ;
227+ start = end;
228+ } )
229+ }
230+
210231 fn finalize ( mut self ) -> Func {
211232 for ( blocknum, blockrange) in self . f . blocks . iter_mut ( ) . enumerate ( ) {
212233 let begin_inst = self . f . insts . len ( ) ;
@@ -227,6 +248,12 @@ impl Arbitrary<'_> for RegClass {
227248 }
228249}
229250
251+ impl Arbitrary < ' _ > for OperandPos {
252+ fn arbitrary ( u : & mut Unstructured ) -> ArbitraryResult < Self > {
253+ Ok ( * u. choose ( & [ OperandPos :: Early , OperandPos :: Late ] ) ?)
254+ }
255+ }
256+
230257impl Arbitrary < ' _ > for OperandConstraint {
231258 fn arbitrary ( u : & mut Unstructured ) -> ArbitraryResult < Self > {
232259 Ok ( * u. choose ( & [ OperandConstraint :: Any , OperandConstraint :: Reg ] ) ?)
@@ -258,6 +285,82 @@ fn choose_dominating_block(
258285 Ok ( block)
259286}
260287
288+ fn convert_def_to_reuse ( u : & mut Unstructured < ' _ > , operands : & mut [ Operand ] ) -> ArbitraryResult < ( ) > {
289+ let op = operands[ 0 ] ;
290+ debug_assert_eq ! ( op. kind( ) , OperandKind :: Def ) ;
291+
292+ let reused = u. int_in_range ( 1 ..=( operands. len ( ) - 1 ) ) ?;
293+ Ok ( if op. class ( ) == operands[ reused] . class ( ) {
294+ // Replace the def with a reuse of an existing input.
295+ operands[ 0 ] = Operand :: new (
296+ op. vreg ( ) ,
297+ OperandConstraint :: Reuse ( reused) ,
298+ op. kind ( ) ,
299+ OperandPos :: Late ,
300+ ) ;
301+
302+ // Make sure reused input is a register.
303+ let op = operands[ reused] ;
304+ operands[ reused] = Operand :: new (
305+ op. vreg ( ) ,
306+ OperandConstraint :: Reg ,
307+ op. kind ( ) ,
308+ OperandPos :: Early ,
309+ ) ;
310+ } )
311+ }
312+
313+ fn convert_op_to_fixed (
314+ u : & mut Unstructured < ' _ > ,
315+ op : & mut Operand ,
316+ fixed_early : & mut Vec < PReg > ,
317+ fixed_late : & mut Vec < PReg > ,
318+ ) -> ArbitraryResult < ( ) > {
319+ let fixed_reg = PReg :: new ( u. int_in_range ( 0 ..=62 ) ?, op. class ( ) ) ;
320+
321+ if op. kind ( ) == OperandKind :: Def && op. pos ( ) == OperandPos :: Early {
322+ // Early-defs with fixed constraints conflict with
323+ // any other fixed uses of the same preg.
324+ if fixed_late. contains ( & fixed_reg) {
325+ return Ok ( ( ) ) ;
326+ }
327+ }
328+
329+ if op. kind ( ) == OperandKind :: Use && op. pos ( ) == OperandPos :: Late {
330+ // Late-use with fixed constraints conflict with
331+ // any other fixed uses of the same preg.
332+ if fixed_early. contains ( & fixed_reg) {
333+ return Ok ( ( ) ) ;
334+ }
335+ }
336+
337+ // Check that it is not already fixed.
338+ let fixed_list = match op. pos ( ) {
339+ OperandPos :: Early => fixed_early,
340+ OperandPos :: Late => fixed_late,
341+ } ;
342+ if fixed_list. contains ( & fixed_reg) {
343+ return Ok ( ( ) ) ;
344+ }
345+
346+ fixed_list. push ( fixed_reg) ;
347+ * op = Operand :: new (
348+ op. vreg ( ) ,
349+ OperandConstraint :: FixedReg ( fixed_reg) ,
350+ op. kind ( ) ,
351+ op. pos ( ) ,
352+ ) ;
353+
354+ Ok ( ( ) )
355+ }
356+
357+ fn has_fixed_def_with ( preg : PReg ) -> impl Fn ( & Operand ) -> bool {
358+ move |op| match ( op. kind ( ) , op. constraint ( ) ) {
359+ ( OperandKind :: Def , OperandConstraint :: FixedReg ( fixed) ) => fixed == preg,
360+ _ => false ,
361+ }
362+ }
363+
261364#[ derive( Clone , Debug ) ]
262365pub struct Options {
263366 pub reused_inputs : bool ,
@@ -371,22 +474,7 @@ impl Func {
371474 builder. f . reftype_vregs . push ( vreg) ;
372475 }
373476 if bool:: arbitrary ( u) ? {
374- let assumed_end_inst = 10 * num_blocks;
375- let mut start = u. int_in_range :: < usize > ( 0 ..=assumed_end_inst) ?;
376- for _ in 0 ..10 {
377- if start >= assumed_end_inst {
378- break ;
379- }
380- let end = u. int_in_range :: < usize > ( start..=assumed_end_inst) ?;
381- let label = u. int_in_range :: < u32 > ( 0 ..=100 ) ?;
382- builder. f . debug_value_labels . push ( (
383- vreg,
384- Inst :: new ( start) ,
385- Inst :: new ( end) ,
386- label,
387- ) ) ;
388- start = end;
389- }
477+ builder. add_arbitrary_debug_labels ( u, num_blocks, vreg) ?;
390478 }
391479 }
392480 vregs_by_block. push ( vregs. clone ( ) ) ;
@@ -417,9 +505,9 @@ impl Func {
417505 } ;
418506 let mut operands = vec ! [ Operand :: new(
419507 vreg,
420- def_constraint ,
508+ OperandConstraint :: arbitrary ( u ) ? ,
421509 OperandKind :: Def ,
422- def_pos ,
510+ OperandPos :: arbitrary ( u ) ? ,
423511 ) ] ;
424512 let mut allocations = vec ! [ Allocation :: none( ) ] ;
425513 for _ in 0 ..u. int_in_range ( opts. num_uses_per_inst . clone ( ) ) ? {
@@ -442,86 +530,33 @@ impl Func {
442530 remaining_nonlocal_uses -= 1 ;
443531 * u. choose ( & vregs_by_block[ def_block. index ( ) ] ) ?
444532 } ;
445- let use_constraint = OperandConstraint :: arbitrary ( u) ?;
446533 operands. push ( Operand :: new (
447534 vreg,
448- use_constraint ,
535+ OperandConstraint :: arbitrary ( u ) ? ,
449536 OperandKind :: Use ,
450537 OperandPos :: Early ,
451538 ) ) ;
452539 allocations. push ( Allocation :: none ( ) ) ;
453540 }
454541 let mut clobbers: Vec < PReg > = vec ! [ ] ;
455542 if operands. len ( ) > 1 && opts. reused_inputs && bool:: arbitrary ( u) ? {
456- // Make the def a reused input.
457- let op = operands[ 0 ] ;
458- debug_assert_eq ! ( op. kind( ) , OperandKind :: Def ) ;
459- let reused = u. int_in_range ( 1 ..=( operands. len ( ) - 1 ) ) ?;
460- if op. class ( ) == operands[ reused] . class ( ) {
461- operands[ 0 ] = Operand :: new (
462- op. vreg ( ) ,
463- OperandConstraint :: Reuse ( reused) ,
464- op. kind ( ) ,
465- OperandPos :: Late ,
466- ) ;
467- // Make sure reused input is a Reg.
468- let op = operands[ reused] ;
469- operands[ reused] = Operand :: new (
470- op. vreg ( ) ,
471- OperandConstraint :: Reg ,
472- op. kind ( ) ,
473- OperandPos :: Early ,
474- ) ;
475- }
543+ convert_def_to_reuse ( u, & mut operands) ?;
476544 } else if opts. fixed_regs && bool:: arbitrary ( u) ? {
477545 let mut fixed_early = vec ! [ ] ;
478546 let mut fixed_late = vec ! [ ] ;
479547 for _ in 0 ..u. int_in_range ( 0 ..=operands. len ( ) - 1 ) ? {
480548 // Pick an operand and make it a fixed reg.
481549 let i = u. int_in_range ( 0 ..=( operands. len ( ) - 1 ) ) ?;
482- let op = operands[ i] ;
483- let fixed_reg = PReg :: new ( u. int_in_range ( 0 ..=62 ) ?, op. class ( ) ) ;
484- if op. kind ( ) == OperandKind :: Def && op. pos ( ) == OperandPos :: Early {
485- // Early-defs with fixed constraints conflict with
486- // any other fixed uses of the same preg.
487- if fixed_late. contains ( & fixed_reg) {
488- continue ;
489- }
490- }
491- if op. kind ( ) == OperandKind :: Use && op. pos ( ) == OperandPos :: Late {
492- // Late-use with fixed constraints conflict with
493- // any other fixed uses of the same preg.
494- if fixed_early. contains ( & fixed_reg) {
495- continue ;
496- }
497- }
498- let fixed_list = match op. pos ( ) {
499- OperandPos :: Early => & mut fixed_early,
500- OperandPos :: Late => & mut fixed_late,
501- } ;
502- if fixed_list. contains ( & fixed_reg) {
503- continue ;
504- }
505- fixed_list. push ( fixed_reg) ;
506- operands[ i] = Operand :: new (
507- op. vreg ( ) ,
508- OperandConstraint :: FixedReg ( fixed_reg) ,
509- op. kind ( ) ,
510- op. pos ( ) ,
511- ) ;
550+ let op = & mut operands[ i] ;
551+ convert_op_to_fixed ( u, op, & mut fixed_early, & mut fixed_late) ?;
512552 }
513553
514554 if opts. callsite_ish_constraints && bool:: arbitrary ( u) ? {
515555 // Define some new vregs with `any`
516556 // constraints.
517557 for _ in 0 ..u. int_in_range ( opts. num_callsite_ish_vregs_per_inst . clone ( ) ) ? {
518558 let vreg = alloc_vreg ( & mut builder, u) ?;
519- operands. push ( Operand :: new (
520- vreg,
521- OperandConstraint :: Any ,
522- OperandKind :: Def ,
523- OperandPos :: Late ,
524- ) ) ;
559+ operands. push ( Operand :: any_def ( vreg) ) ;
525560 }
526561
527562 // Create some clobbers, avoiding regs named
@@ -534,15 +569,7 @@ impl Func {
534569 for _ in 0 ..u. int_in_range ( opts. num_clobbers_per_inst . clone ( ) ) ? {
535570 let reg = u. int_in_range ( 0 ..=30 ) ?;
536571 let preg = PReg :: new ( reg, RegClass :: arbitrary ( u) ?) ;
537- if operands
538- . iter ( )
539- . any ( |op| match ( op. kind ( ) , op. constraint ( ) ) {
540- ( OperandKind :: Def , OperandConstraint :: FixedReg ( fixed) ) => {
541- fixed == preg
542- }
543- _ => false ,
544- } )
545- {
572+ if operands. iter ( ) . any ( has_fixed_def_with ( preg) ) {
546573 continue ;
547574 }
548575 clobbers. push ( preg) ;
0 commit comments