Coverage Report

Created: 2023-04-25 07:07

/src/regalloc2/src/fuzzing/func.rs
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Released under the terms of the Apache 2.0 license with LLVM
3
 * exception. See `LICENSE` for details.
4
 */
5
6
use crate::{
7
    domtree, postorder, Allocation, Block, Function, Inst, InstRange, MachineEnv, Operand,
8
    OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, RegClass, VReg,
9
};
10
11
use alloc::vec::Vec;
12
use alloc::{format, vec};
13
14
use super::arbitrary::Result as ArbitraryResult;
15
use super::arbitrary::{Arbitrary, Unstructured};
16
17
13.1M
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18
pub enum InstOpcode {
19
    Op,
20
    Ret,
21
    Branch,
22
}
23
24
3.48M
#[derive(Clone, Debug)]
25
pub struct InstData {
26
    op: InstOpcode,
27
    operands: Vec<Operand>,
28
    clobbers: Vec<PReg>,
29
    is_safepoint: bool,
30
}
31
32
impl InstData {
33
0
    pub fn op(def: usize, uses: &[usize]) -> InstData {
34
0
        let mut operands = vec![Operand::reg_def(VReg::new(def, RegClass::Int))];
35
0
        for &u in uses {
36
0
            operands.push(Operand::reg_use(VReg::new(u, RegClass::Int)));
37
0
        }
38
0
        InstData {
39
0
            op: InstOpcode::Op,
40
0
            operands,
41
0
            clobbers: vec![],
42
0
            is_safepoint: false,
43
0
        }
44
0
    }
45
439k
    pub fn branch() -> InstData {
46
439k
        InstData {
47
439k
            op: InstOpcode::Branch,
48
439k
            operands: vec![],
49
439k
            clobbers: vec![],
50
439k
            is_safepoint: false,
51
439k
        }
52
439k
    }
53
9.54k
    pub fn ret() -> InstData {
54
9.54k
        InstData {
55
9.54k
            op: InstOpcode::Ret,
56
9.54k
            operands: vec![],
57
9.54k
            clobbers: vec![],
58
9.54k
            is_safepoint: false,
59
9.54k
        }
60
9.54k
    }
61
}
62
63
0
#[derive(Clone)]
64
pub struct Func {
65
    insts: Vec<InstData>,
66
    blocks: Vec<InstRange>,
67
    block_preds: Vec<Vec<Block>>,
68
    block_succs: Vec<Vec<Block>>,
69
    block_params_in: Vec<Vec<VReg>>,
70
    block_params_out: Vec<Vec<Vec<VReg>>>,
71
    num_vregs: usize,
72
    reftype_vregs: Vec<VReg>,
73
    debug_value_labels: Vec<(VReg, Inst, Inst, u32)>,
74
}
75
76
impl Function for Func {
77
57.2k
    fn num_insts(&self) -> usize {
78
57.2k
        self.insts.len()
79
57.2k
    }
80
81
19.6M
    fn num_blocks(&self) -> usize {
82
19.6M
        self.blocks.len()
83
19.6M
    }
84
85
2.67M
    fn entry_block(&self) -> Block {
86
0
        debug_assert!(self.blocks.len() > 0);
87
2.67M
        Block::new(0)
88
2.67M
    }
89
90
7.14M
    fn block_insns(&self, block: Block) -> InstRange {
91
7.14M
        self.blocks[block.index()]
92
7.14M
    }
93
94
11.5M
    fn block_succs(&self, block: Block) -> &[Block] {
95
11.5M
        &self.block_succs[block.index()][..]
96
11.5M
    }
97
98
10.7M
    fn block_preds(&self, block: Block) -> &[Block] {
99
10.7M
        &self.block_preds[block.index()][..]
100
10.7M
    }
101
102
3.02M
    fn block_params(&self, block: Block) -> &[VReg] {
103
3.02M
        &self.block_params_in[block.index()][..]
104
3.02M
    }
105
106
4.68M
    fn is_ret(&self, insn: Inst) -> bool {
107
4.68M
        self.insts[insn.index()].op == InstOpcode::Ret
108
4.68M
    }
109
110
8.44M
    fn is_branch(&self, insn: Inst) -> bool {
111
8.44M
        self.insts[insn.index()].op == InstOpcode::Branch
112
8.44M
    }
113
114
2.40M
    fn branch_blockparams(&self, block: Block, _: Inst, succ: usize) -> &[VReg] {
115
2.40M
        &self.block_params_out[block.index()][succ][..]
116
2.40M
    }
117
118
8.26M
    fn requires_refs_on_stack(&self, insn: Inst) -> bool {
119
8.26M
        self.insts[insn.index()].is_safepoint
120
8.26M
    }
121
122
66.1k
    fn reftype_vregs(&self) -> &[VReg] {
123
66.1k
        &self.reftype_vregs[..]
124
66.1k
    }
125
126
9.54k
    fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] {
127
9.54k
        &self.debug_value_labels[..]
128
9.54k
    }
129
130
62.3M
    fn inst_operands(&self, insn: Inst) -> &[Operand] {
131
62.3M
        &self.insts[insn.index()].operands[..]
132
62.3M
    }
133
134
10.5M
    fn inst_clobbers(&self, insn: Inst) -> PRegSet {
135
10.5M
        let mut set = PRegSet::default();
136
10.5M
        for &preg in &self.insts[insn.index()].clobbers {
137
532k
            set = set.with(preg);
138
532k
        }
139
10.5M
        set
140
10.5M
    }
141
142
19.0k
    fn num_vregs(&self) -> usize {
143
19.0k
        self.num_vregs
144
19.0k
    }
145
146
3.30M
    fn spillslot_size(&self, regclass: RegClass) -> usize {
147
3.30M
        match regclass {
148
3.30M
            RegClass::Int => 1,
149
0
            RegClass::Float => 2,
150
        }
151
3.30M
    }
152
}
153
154
struct FuncBuilder {
155
    postorder: Vec<Block>,
156
    idom: Vec<Block>,
157
    f: Func,
158
    insts_per_block: Vec<Vec<InstData>>,
159
}
160
161
impl FuncBuilder {
162
9.54k
    fn new() -> Self {
163
9.54k
        FuncBuilder {
164
9.54k
            postorder: vec![],
165
9.54k
            idom: vec![],
166
9.54k
            f: Func {
167
9.54k
                block_preds: vec![],
168
9.54k
                block_succs: vec![],
169
9.54k
                block_params_in: vec![],
170
9.54k
                block_params_out: vec![],
171
9.54k
                insts: vec![],
172
9.54k
                blocks: vec![],
173
9.54k
                num_vregs: 0,
174
9.54k
                reftype_vregs: vec![],
175
9.54k
                debug_value_labels: vec![],
176
9.54k
            },
177
9.54k
            insts_per_block: vec![],
178
9.54k
        }
179
9.54k
    }
180
181
448k
    pub fn add_block(&mut self) -> Block {
182
448k
        let b = Block::new(self.f.blocks.len());
183
448k
        self.f
184
448k
            .blocks
185
448k
            .push(InstRange::forward(Inst::new(0), Inst::new(0)));
186
448k
        self.f.block_preds.push(vec![]);
187
448k
        self.f.block_succs.push(vec![]);
188
448k
        self.f.block_params_in.push(vec![]);
189
448k
        self.f.block_params_out.push(vec![]);
190
448k
        self.insts_per_block.push(vec![]);
191
448k
        b
192
448k
    }
193
194
3.48M
    pub fn add_inst(&mut self, block: Block, data: InstData) {
195
3.48M
        self.insts_per_block[block.index()].push(data);
196
3.48M
    }
197
198
553k
    pub fn add_edge(&mut self, from: Block, to: Block) {
199
553k
        self.f.block_succs[from.index()].push(to);
200
553k
        self.f.block_preds[to.index()].push(from);
201
553k
    }
202
203
448k
    pub fn set_block_params_in(&mut self, block: Block, params: &[VReg]) {
204
448k
        self.f.block_params_in[block.index()] = params.iter().cloned().collect();
205
448k
    }
206
207
439k
    pub fn set_block_params_out(&mut self, block: Block, params: Vec<Vec<VReg>>) {
208
439k
        self.f.block_params_out[block.index()] = params;
209
439k
    }
210
211
19.0k
    fn compute_doms(&mut self) {
212
897k
        self.postorder = postorder::calculate(self.f.blocks.len(), Block::new(0), |block| {
213
897k
            &self.f.block_succs[block.index()][..]
214
897k
        });
215
19.0k
        self.idom = domtree::calculate(
216
19.0k
            self.f.blocks.len(),
217
4.40M
            |block| &self.f.block_preds[block.index()][..],
218
19.0k
            &self.postorder[..],
219
19.0k
            Block::new(0),
220
19.0k
        );
221
19.0k
    }
222
223
9.54k
    fn finalize(mut self) -> Func {
224
448k
        for (blocknum, blockrange) in self.f.blocks.iter_mut().enumerate() {
225
448k
            let begin_inst = self.f.insts.len();
226
3.48M
            for inst in &self.insts_per_block[blocknum] {
227
3.48M
                self.f.insts.push(inst.clone());
228
3.48M
            }
229
448k
            let end_inst = self.f.insts.len();
230
448k
            *blockrange = InstRange::forward(Inst::new(begin_inst), Inst::new(end_inst));
231
        }
232
233
9.54k
        self.f
234
9.54k
    }
235
}
236
237
impl Arbitrary<'_> for OperandConstraint {
238
5.04M
    fn arbitrary(u: &mut Unstructured) -> ArbitraryResult<Self> {
239
5.04M
        Ok(*u.choose(&[OperandConstraint::Any, OperandConstraint::Reg])?)
240
5.04M
    }
241
}
242
243
805k
fn choose_dominating_block(
244
805k
    idom: &[Block],
245
805k
    mut block: Block,
246
805k
    allow_self: bool,
247
805k
    u: &mut Unstructured,
248
805k
) -> ArbitraryResult<Block> {
249
0
    debug_assert!(block.is_valid());
250
805k
    let orig_block = block;
251
    loop {
252
7.93M
        if (allow_self || block != orig_block) && bool::arbitrary(u)? {
253
478k
            break;
254
7.46M
        }
255
7.46M
        if idom[block.index()].is_invalid() {
256
327k
            break;
257
7.13M
        }
258
7.13M
        block = idom[block.index()];
259
    }
260
805k
    let block = if block != orig_block || allow_self {
261
769k
        block
262
    } else {
263
36.2k
        Block::invalid()
264
    };
265
805k
    Ok(block)
266
805k
}
267
268
0
#[derive(Clone, Copy, Debug)]
269
pub struct Options {
270
    pub reused_inputs: bool,
271
    pub fixed_regs: bool,
272
    pub fixed_nonallocatable: bool,
273
    pub clobbers: bool,
274
    pub control_flow: bool,
275
    pub reducible: bool,
276
    pub block_params: bool,
277
    pub always_local_uses: bool,
278
    pub reftypes: bool,
279
}
280
281
impl core::default::Default for Options {
282
0
    fn default() -> Self {
283
0
        Options {
284
0
            reused_inputs: false,
285
0
            fixed_regs: false,
286
0
            fixed_nonallocatable: false,
287
0
            clobbers: false,
288
0
            control_flow: true,
289
0
            reducible: false,
290
0
            block_params: true,
291
0
            always_local_uses: false,
292
0
            reftypes: false,
293
0
        }
294
0
    }
295
}
296
297
impl Arbitrary<'_> for Func {
298
0
    fn arbitrary(u: &mut Unstructured) -> ArbitraryResult<Func> {
299
0
        Func::arbitrary_with_options(u, &Options::default())
300
0
    }
301
}
302
303
impl Func {
304
9.54k
    pub fn arbitrary_with_options(u: &mut Unstructured, opts: &Options) -> ArbitraryResult<Func> {
305
9.54k
        // General strategy:
306
9.54k
        // 1. Create an arbitrary CFG.
307
9.54k
        // 2. Create a list of vregs to define in each block.
308
9.54k
        // 3. Define some of those vregs in each block as blockparams.f.
309
9.54k
        // 4. Populate blocks with ops that define the rest of the vregs.
310
9.54k
        //    - For each use, choose an available vreg: either one
311
9.54k
        //      already defined (via blockparam or inst) in this block,
312
9.54k
        //      or one defined in a dominating block.
313
9.54k
314
9.54k
        let mut builder = FuncBuilder::new();
315
448k
        for _ in 0..u.int_in_range(1..=100)? {
316
448k
            builder.add_block();
317
448k
        }
318
9.54k
        let num_blocks = builder.f.blocks.len();
319
9.54k
320
9.54k
        // Generate a CFG. Create a "spine" of either single blocks,
321
9.54k
        // with links to the next; or fork patterns, with the left
322
9.54k
        // fork linking to the next and the right fork in `out_blocks`
323
9.54k
        // to be connected below. This creates an arbitrary CFG with
324
9.54k
        // split critical edges, which is a property that we require
325
9.54k
        // for the regalloc.
326
9.54k
        let mut from = 0;
327
9.54k
        let mut out_blocks = vec![];
328
9.54k
        let mut in_blocks = vec![];
329
9.54k
        // For reducibility, if selected: enforce strict nesting of backedges
330
9.54k
        let mut max_backedge_src = 0;
331
9.54k
        let mut min_backedge_dest = num_blocks;
332
229k
        while from < num_blocks {
333
219k
            in_blocks.push(from);
334
219k
            if num_blocks > 3 && from < num_blocks - 3 && bool::arbitrary(u)? && opts.control_flow {
335
114k
                // To avoid critical edges, we use from+1 as an edge
336
114k
                // block, and advance `from` an extra block; `from+2`
337
114k
                // will be the next normal iteration.
338
114k
                builder.add_edge(Block::new(from), Block::new(from + 1));
339
114k
                builder.add_edge(Block::new(from), Block::new(from + 2));
340
114k
                builder.add_edge(Block::new(from + 2), Block::new(from + 3));
341
114k
                out_blocks.push(from + 1);
342
114k
                from += 2;
343
114k
            } else if from < num_blocks - 1 {
344
95.7k
                builder.add_edge(Block::new(from), Block::new(from + 1));
345
95.7k
            }
346
219k
            from += 1;
347
        }
348
124k
        for pred in out_blocks {
349
114k
            let mut succ = *u.choose(&in_blocks[..])?;
350
114k
            if opts.reducible && (pred >= succ) {
351
0
                if pred < max_backedge_src || succ > min_backedge_dest {
352
0
                    // If the chosen edge would result in an
353
0
                    // irreducible CFG, just make this a diamond
354
0
                    // instead.
355
0
                    succ = pred + 2;
356
0
                } else {
357
0
                    max_backedge_src = pred;
358
0
                    min_backedge_dest = succ;
359
0
                }
360
114k
            }
361
114k
            builder.add_edge(Block::new(pred), Block::new(succ));
362
        }
363
364
9.54k
        builder.compute_doms();
365
366
448k
        for block in 0..num_blocks {
367
448k
            builder.f.block_preds[block].clear();
368
448k
        }
369
448k
        for block in 0..num_blocks {
370
553k
            for &succ in &builder.f.block_succs[block] {
371
553k
                builder.f.block_preds[succ.index()].push(Block::new(block));
372
553k
            }
373
        }
374
375
9.54k
        builder.compute_doms();
376
9.54k
377
9.54k
        let mut vregs_by_block = vec![];
378
9.54k
        let mut vregs_by_block_to_be_defined = vec![];
379
9.54k
        let mut block_params = vec![vec![]; num_blocks];
380
448k
        for block in 0..num_blocks {
381
448k
            let mut vregs = vec![];
382
448k
            for _ in 0..u.int_in_range(5..=15)? {
383
3.30M
                let vreg = VReg::new(builder.f.num_vregs, RegClass::Int);
384
3.30M
                builder.f.num_vregs += 1;
385
3.30M
                vregs.push(vreg);
386
3.30M
                if opts.reftypes && bool::arbitrary(u)? {
387
930k
                    builder.f.reftype_vregs.push(vreg);
388
2.37M
                }
389
3.30M
                if bool::arbitrary(u)? {
390
294k
                    let assumed_end_inst = 10 * num_blocks;
391
294k
                    let mut start = u.int_in_range::<usize>(0..=assumed_end_inst)?;
392
2.23M
                    for _ in 0..10 {
393
2.12M
                        if start >= assumed_end_inst {
394
180k
                            break;
395
1.94M
                        }
396
1.94M
                        let end = u.int_in_range::<usize>(start..=assumed_end_inst)?;
397
1.94M
                        let label = u.int_in_range::<u32>(0..=100)?;
398
1.94M
                        builder.f.debug_value_labels.push((
399
1.94M
                            vreg,
400
1.94M
                            Inst::new(start),
401
1.94M
                            Inst::new(end),
402
1.94M
                            label,
403
1.94M
                        ));
404
1.94M
                        start = end;
405
                    }
406
3.00M
                }
407
            }
408
448k
            vregs_by_block.push(vregs.clone());
409
448k
            vregs_by_block_to_be_defined.push(vec![]);
410
448k
            let mut max_block_params = u.int_in_range(0..=core::cmp::min(3, vregs.len() / 3))?;
411
3.74M
            for &vreg in &vregs {
412
3.30M
                if block > 0 && opts.block_params && bool::arbitrary(u)? && max_block_params > 0 {
413
260k
                    block_params[block].push(vreg);
414
260k
                    max_block_params -= 1;
415
3.04M
                } else {
416
3.04M
                    vregs_by_block_to_be_defined.last_mut().unwrap().push(vreg);
417
3.04M
                }
418
            }
419
448k
            vregs_by_block_to_be_defined.last_mut().unwrap().reverse();
420
448k
            builder.set_block_params_in(Block::new(block), &block_params[block][..]);
421
        }
422
423
448k
        for block in 0..num_blocks {
424
448k
            let mut avail = block_params[block].clone();
425
448k
            let mut remaining_nonlocal_uses = u.int_in_range(0..=3)?;
426
3.48M
            while let Some(vreg) = vregs_by_block_to_be_defined[block].pop() {
427
3.04M
                let def_constraint = OperandConstraint::arbitrary(u)?;
428
3.04M
                let def_pos = if bool::arbitrary(u)? {
429
765k
                    OperandPos::Early
430
                } else {
431
2.27M
                    OperandPos::Late
432
                };
433
3.04M
                let mut operands = vec![Operand::new(
434
3.04M
                    vreg,
435
3.04M
                    def_constraint,
436
3.04M
                    OperandKind::Def,
437
3.04M
                    def_pos,
438
3.04M
                )];
439
3.04M
                let mut allocations = vec![Allocation::none()];
440
3.04M
                for _ in 0..u.int_in_range(0..=3)? {
441
2.02M
                    let vreg = if avail.len() > 0
442
1.83M
                        && (opts.always_local_uses
443
1.83M
                            || remaining_nonlocal_uses == 0
444
586k
                            || bool::arbitrary(u)?)
445
                    {
446
1.58M
                        *u.choose(&avail[..])?
447
442k
                    } else if !opts.always_local_uses {
448
442k
                        let def_block = choose_dominating_block(
449
442k
                            &builder.idom[..],
450
442k
                            Block::new(block),
451
442k
                            /* allow_self = */ false,
452
442k
                            u,
453
442k
                        )?;
454
442k
                        if !def_block.is_valid() {
455
                            // No vregs already defined, and no pred blocks that dominate us
456
                            // (perhaps we are the entry block): just stop generating inputs.
457
24.3k
                            break;
458
418k
                        }
459
418k
                        remaining_nonlocal_uses -= 1;
460
418k
                        *u.choose(&vregs_by_block[def_block.index()])?
461
                    } else {
462
0
                        break;
463
                    };
464
2.00M
                    let use_constraint = OperandConstraint::arbitrary(u)?;
465
2.00M
                    operands.push(Operand::new(
466
2.00M
                        vreg,
467
2.00M
                        use_constraint,
468
2.00M
                        OperandKind::Use,
469
2.00M
                        OperandPos::Early,
470
2.00M
                    ));
471
2.00M
                    allocations.push(Allocation::none());
472
                }
473
3.04M
                let mut clobbers: Vec<PReg> = vec![];
474
3.04M
                if operands.len() > 1 && opts.reused_inputs && bool::arbitrary(u)? {
475
                    // Make the def a reused input.
476
627k
                    let op = operands[0];
477
0
                    debug_assert_eq!(op.kind(), OperandKind::Def);
478
627k
                    let reused = u.int_in_range(1..=(operands.len() - 1))?;
479
627k
                    operands[0] = Operand::new(
480
627k
                        op.vreg(),
481
627k
                        OperandConstraint::Reuse(reused),
482
627k
                        op.kind(),
483
627k
                        OperandPos::Late,
484
627k
                    );
485
627k
                    // Make sure reused input is a Reg.
486
627k
                    let op = operands[reused];
487
627k
                    operands[reused] = Operand::new(
488
627k
                        op.vreg(),
489
627k
                        OperandConstraint::Reg,
490
627k
                        op.kind(),
491
627k
                        OperandPos::Early,
492
627k
                    );
493
2.41M
                } else if opts.fixed_regs && bool::arbitrary(u)? {
494
296k
                    let mut fixed_early = vec![];
495
296k
                    let mut fixed_late = vec![];
496
296k
                    for _ in 0..u.int_in_range(0..=operands.len() - 1)? {
497
                        // Pick an operand and make it a fixed reg.
498
254k
                        let i = u.int_in_range(0..=(operands.len() - 1))?;
499
254k
                        let op = operands[i];
500
254k
                        let fixed_reg = PReg::new(u.int_in_range(0..=62)?, RegClass::Int);
501
254k
                        let fixed_list = match op.pos() {
502
236k
                            OperandPos::Early => &mut fixed_early,
503
17.8k
                            OperandPos::Late => &mut fixed_late,
504
                        };
505
254k
                        if fixed_list.contains(&fixed_reg) {
506
54.6k
                            break;
507
199k
                        }
508
199k
                        if op.kind() != OperandKind::Def && op.pos() == OperandPos::Late {
509
                            // Late-uses/mods with fixed constraints
510
                            // can't be allowed if we're allowing
511
                            // different constraints at Early and
512
                            // Late, because we can't move something
513
                            // into a location between Early and
514
                            // Late. Differing constraints only make
515
                            // sense if the instruction itself
516
                            // produces the newly-constrained values.
517
0
                            break;
518
199k
                        }
519
199k
                        if op.kind() != OperandKind::Use && op.pos() == OperandPos::Early {
520
                            // Likewise, we can *only* allow uses for
521
                            // fixed constraints at Early.
522
10.1k
                            break;
523
189k
                        }
524
189k
                        fixed_list.push(fixed_reg);
525
189k
                        operands[i] = Operand::new(
526
189k
                            op.vreg(),
527
189k
                            OperandConstraint::FixedReg(fixed_reg),
528
189k
                            op.kind(),
529
189k
                            op.pos(),
530
189k
                        );
531
                    }
532
2.11M
                } else if opts.clobbers && bool::arbitrary(u)? {
533
118k
                    for _ in 0..u.int_in_range(0..=5)? {
534
192k
                        let reg = u.int_in_range(0..=30)?;
535
196k
                        if clobbers.iter().any(|r| r.hw_enc() == reg) {
536
29.0k
                            break;
537
163k
                        }
538
163k
                        clobbers.push(PReg::new(reg, RegClass::Int));
539
                    }
540
1.99M
                } else if opts.fixed_nonallocatable && bool::arbitrary(u)? {
541
62.5k
                    operands.push(Operand::fixed_nonallocatable(PReg::new(63, RegClass::Int)));
542
1.93M
                }
543
544
3.04M
                let is_safepoint = opts.reftypes
545
3.04M
                    && operands
546
3.04M
                        .iter()
547
4.52M
                        .all(|op| !builder.f.reftype_vregs.contains(&op.vreg()))
548
2.23M
                    && bool::arbitrary(u)?;
549
550
3.04M
                builder.add_inst(
551
3.04M
                    Block::new(block),
552
3.04M
                    InstData {
553
3.04M
                        op: InstOpcode::Op,
554
3.04M
                        operands,
555
3.04M
                        clobbers,
556
3.04M
                        is_safepoint,
557
3.04M
                    },
558
3.04M
                );
559
3.04M
                avail.push(vreg);
560
            }
561
562
            // Define the branch with blockparam args that must end
563
            // the block.
564
448k
            if builder.f.block_succs[block].len() > 0 {
565
439k
                let mut params = vec![];
566
553k
                for &succ in &builder.f.block_succs[block] {
567
553k
                    let mut args = vec![];
568
553k
                    for _ in 0..builder.f.block_params_in[succ.index()].len() {
569
362k
                        let dom_block = choose_dominating_block(
570
362k
                            &builder.idom[..],
571
362k
                            Block::new(block),
572
362k
                            false,
573
362k
                            u,
574
362k
                        )?;
575
362k
                        let vreg = if dom_block.is_valid() && bool::arbitrary(u)? {
576
51.2k
                            u.choose(&vregs_by_block[dom_block.index()][..])?
577
                        } else {
578
311k
                            u.choose(&avail[..])?
579
                        };
580
362k
                        args.push(*vreg);
581
                    }
582
553k
                    params.push(args);
583
                }
584
439k
                builder.set_block_params_out(Block::new(block), params);
585
439k
                builder.add_inst(Block::new(block), InstData::branch());
586
9.54k
            } else {
587
9.54k
                builder.add_inst(Block::new(block), InstData::ret());
588
9.54k
            }
589
        }
590
591
9.54k
        builder.f.debug_value_labels.sort_unstable();
592
9.54k
593
9.54k
        Ok(builder.finalize())
594
9.54k
    }
595
}
596
597
impl core::fmt::Debug for Func {
598
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
599
0
        write!(f, "{{\n")?;
600
0
        for vreg in self.reftype_vregs() {
601
0
            write!(f, "  REF: {}\n", vreg)?;
602
        }
603
0
        for (i, blockrange) in self.blocks.iter().enumerate() {
604
0
            let succs = self.block_succs[i]
605
0
                .iter()
606
0
                .map(|b| b.index())
607
0
                .collect::<Vec<_>>();
608
0
            let preds = self.block_preds[i]
609
0
                .iter()
610
0
                .map(|b| b.index())
611
0
                .collect::<Vec<_>>();
612
0
            let params_in = self.block_params_in[i]
613
0
                .iter()
614
0
                .map(|v| format!("v{}", v.vreg()))
615
0
                .collect::<Vec<_>>()
616
0
                .join(", ");
617
0
            let params_out = self.block_params_out[i]
618
0
                .iter()
619
0
                .enumerate()
620
0
                .map(|(succ_idx, vec)| {
621
0
                    let succ = self.block_succs[i][succ_idx];
622
0
                    let params = vec
623
0
                        .iter()
624
0
                        .map(|v| format!("v{}", v.vreg()))
625
0
                        .collect::<Vec<_>>()
626
0
                        .join(", ");
627
0
                    format!("block{}({})", succ.index(), params)
628
0
                })
629
0
                .collect::<Vec<_>>()
630
0
                .join(", ");
631
0
            write!(
632
0
                f,
633
0
                "  block{}({}): # succs:{:?} preds:{:?}\n",
634
0
                i, params_in, succs, preds
635
0
            )?;
636
0
            for inst in blockrange.iter() {
637
0
                if self.requires_refs_on_stack(inst) {
638
0
                    write!(f, "    -- SAFEPOINT --\n")?;
639
0
                }
640
0
                write!(
641
0
                    f,
642
0
                    "    inst{}: {:?} ops:{:?} clobber:{:?}\n",
643
0
                    inst.index(),
644
0
                    self.insts[inst.index()].op,
645
0
                    self.insts[inst.index()].operands,
646
0
                    self.insts[inst.index()].clobbers
647
0
                )?;
648
0
                if let InstOpcode::Branch = self.insts[inst.index()].op {
649
0
                    write!(f, "    params: {}\n", params_out)?;
650
0
                }
651
            }
652
        }
653
0
        write!(f, "}}\n")?;
654
0
        Ok(())
655
0
    }
656
}
657
658
9.54k
pub fn machine_env() -> MachineEnv {
659
28.6k
    fn regs(r: core::ops::Range<usize>) -> Vec<PReg> {
660
601k
        r.map(|i| PReg::new(i, RegClass::Int)).collect()
661
28.6k
    }
662
9.54k
    let preferred_regs_by_class: [Vec<PReg>; 2] = [regs(0..24), vec![]];
663
9.54k
    let non_preferred_regs_by_class: [Vec<PReg>; 2] = [regs(24..32), vec![]];
664
9.54k
    let scratch_by_class: [Option<PReg>; 2] = [None, None];
665
9.54k
    let fixed_stack_slots = regs(32..63);
666
9.54k
    // Register 63 is reserved for use as a fixed non-allocatable register.
667
9.54k
    MachineEnv {
668
9.54k
        preferred_regs_by_class,
669
9.54k
        non_preferred_regs_by_class,
670
9.54k
        scratch_by_class,
671
9.54k
        fixed_stack_slots,
672
9.54k
    }
673
9.54k
}