Coverage Report

Created: 2021-03-22 08:29

/src/regalloc.rs/bin/test_framework.rs
Line
Count
Source (jump to first uncovered line)
1
//! As part of this set of test cases, we define a mini IR and implement the
2
//! `Function` trait for it so that we can use the regalloc public interface.
3
4
use arbitrary::Arbitrary;
5
use regalloc::*;
6
use std::collections::HashSet;
7
8
use std::{borrow::Cow, fmt};
9
10
use crate::{
11
    parser::REFTYPE_START,
12
    validator::{validate, Context as ValidatorContext, RegRef},
13
};
14
15
use log::debug;
16
17
//=============================================================================
18
// Definition of: Label, RI (reg-or-immediate operands), AM (address modes),
19
// and Inst (instructions).  Also the get-regs and map-regs operations for
20
// them.  Destinations are on the left.
21
22
51.2k
#[derive(Clone)]
<minira::test_framework::Label as core::clone::Clone>::clone
Line
Count
Source
22
51.2k
#[derive(Clone)]
23
pub enum Label {
24
    Unresolved { name: String },
25
    Resolved { name: String, bix: BlockIx },
26
}
27
28
impl Label {
29
    pub fn new_unresolved(name: String) -> Label {
30
        Label::Unresolved { name }
31
    }
32
46.9k
    pub fn get_block_ix(&self) -> BlockIx {
33
46.9k
        match self {
34
46.9k
            Label::Resolved { name: _, bix } => *bix,
35
0
            Label::Unresolved { .. } => panic!("Label::getBlockIx: unresolved label!"),
36
        }
37
46.9k
    }
38
0
    pub fn type_checks(&self, cx: &ValidatorContext) -> bool {
39
0
        match self {
40
0
            Label::Unresolved { .. } => false,
41
0
            Label::Resolved { bix, .. } => {
42
0
                let bix_u32: u32 = (*bix).into();
43
0
                bix_u32 < cx.num_blocks
44
            }
45
        }
46
0
    }
47
}
48
49
impl fmt::Debug for Label {
50
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
51
0
        match self {
52
0
            Label::Unresolved { name } => write!(fmt, "??:{}", &name),
53
0
            Label::Resolved { name, bix } => write!(fmt, "{:?}:{}", bix, name),
54
        }
55
0
    }
56
}
57
58
6.49k
#[derive(Copy, Clone)]
59
pub enum RI {
60
    Reg { reg: Reg },
61
    Imm { imm: u32 },
62
}
63
64
#[allow(non_snake_case)]
65
pub fn RI_R(reg: Reg) -> RI {
66
    debug_assert!(reg.get_class() == RegClass::I32);
67
    RI::Reg { reg }
68
}
69
70
#[allow(non_snake_case)]
71
pub fn RI_I(imm: u32) -> RI {
72
    RI::Imm { imm }
73
}
74
75
impl fmt::Debug for RI {
76
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
77
0
        match self {
78
0
            RI::Reg { reg } => reg.fmt(fmt),
79
0
            RI::Imm { imm } => write!(fmt, "{}", imm),
80
        }
81
0
    }
82
}
83
impl RI {
84
8.73k
    fn add_reg_reads_to(&self, collector: &mut RegUsageCollector) {
85
8.73k
        match self {
86
5.61k
            RI::Reg { reg } => collector.add_use(*reg),
87
3.11k
            RI::Imm { .. } => {}
88
        }
89
8.73k
    }
90
2.84k
    fn apply_uses<RUM: RegUsageMapper>(&mut self, mapper: &RUM) {
91
2.84k
        match self {
92
1.83k
            RI::Reg { ref mut reg } => {
93
1.83k
                reg.apply_uses(mapper);
94
1.83k
            }
95
1.01k
            RI::Imm { .. } => {}
96
        }
97
2.84k
    }
Unexecuted instantiation: <minira::test_framework::RI>::apply_uses::<regalloc::reg_maps::MentionRegUsageMapper>
<minira::test_framework::RI>::apply_uses::<regalloc::reg_maps::VrangeRegUsageMapper>
Line
Count
Source
90
2.84k
    fn apply_uses<RUM: RegUsageMapper>(&mut self, mapper: &RUM) {
91
2.84k
        match self {
92
1.83k
            RI::Reg { ref mut reg } => {
93
1.83k
                reg.apply_uses(mapper);
94
1.83k
            }
95
1.01k
            RI::Imm { .. } => {}
96
        }
97
2.84k
    }
98
0
    fn type_checks(&self, cx: &mut ValidatorContext) -> bool {
99
0
        match self {
100
0
            RI::Reg { reg } => cx.check_reg_rc(reg, RegRef::Use, RegClass::I32),
101
0
            RI::Imm { .. } => true,
102
        }
103
0
    }
104
}
105
106
12.9k
#[derive(Copy, Clone)]
107
pub enum AM {
108
    RI { base: Reg, offset: u32 },
109
    RR { base: Reg, offset: Reg },
110
}
111
112
#[allow(non_snake_case)]
113
pub fn AM_R(base: Reg) -> AM {
114
    debug_assert!(base.get_class() == RegClass::I32);
115
    AM::RI { base, offset: 0 }
116
}
117
118
#[allow(non_snake_case)]
119
pub fn AM_RI(base: Reg, offset: u32) -> AM {
120
    debug_assert!(base.get_class() == RegClass::I32);
121
    AM::RI { base, offset }
122
}
123
124
#[allow(non_snake_case)]
125
pub fn AM_RR(base: Reg, offset: Reg) -> AM {
126
    debug_assert!(base.get_class() == RegClass::I32);
127
    debug_assert!(offset.get_class() == RegClass::I32);
128
    AM::RR { base, offset }
129
}
130
131
impl fmt::Debug for AM {
132
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
133
0
        match self {
134
0
            AM::RI { base, offset } => write!(fmt, "[{:?}, {:?}]", base, offset),
135
0
            AM::RR { base, offset } => write!(fmt, "[{:?}, {:?}]", base, offset),
136
        }
137
0
    }
138
}
139
140
impl AM {
141
17.1k
    fn add_reg_reads_to(&self, collector: &mut RegUsageCollector) {
142
17.1k
        match self {
143
8.87k
            AM::RI { base, .. } => collector.add_use(*base),
144
8.23k
            AM::RR { base, offset } => {
145
8.23k
                collector.add_use(*base);
146
8.23k
                collector.add_use(*offset);
147
8.23k
            }
148
        }
149
17.1k
    }
150
151
5.37k
    fn apply_uses<RUM: RegUsageMapper>(&mut self, mapper: &RUM) {
152
5.37k
        match self {
153
2.83k
            AM::RI { ref mut base, .. } => {
154
2.83k
                base.apply_uses(mapper);
155
2.83k
            }
156
            AM::RR {
157
2.53k
                ref mut base,
158
2.53k
                ref mut offset,
159
2.53k
            } => {
160
2.53k
                base.apply_uses(mapper);
161
2.53k
                offset.apply_uses(mapper);
162
2.53k
            }
163
        }
164
5.37k
    }
<minira::test_framework::AM>::apply_uses::<regalloc::reg_maps::VrangeRegUsageMapper>
Line
Count
Source
151
5.37k
    fn apply_uses<RUM: RegUsageMapper>(&mut self, mapper: &RUM) {
152
5.37k
        match self {
153
2.83k
            AM::RI { ref mut base, .. } => {
154
2.83k
                base.apply_uses(mapper);
155
2.83k
            }
156
            AM::RR {
157
2.53k
                ref mut base,
158
2.53k
                ref mut offset,
159
2.53k
            } => {
160
2.53k
                base.apply_uses(mapper);
161
2.53k
                offset.apply_uses(mapper);
162
2.53k
            }
163
        }
164
5.37k
    }
Unexecuted instantiation: <minira::test_framework::AM>::apply_uses::<regalloc::reg_maps::MentionRegUsageMapper>
165
166
0
    fn type_checks(&self, cx: &mut ValidatorContext) -> bool {
167
0
        use RegClass::*;
168
0
        match self {
169
0
            AM::RI { base, .. } => cx.check_reg_rc(base, RegRef::Use, I32),
170
0
            AM::RR { base, offset } => {
171
0
                cx.check_reg_rc(base, RegRef::Use, I32) && cx.check_reg_rc(offset, RegRef::Use, I32)
172
            }
173
        }
174
0
    }
175
}
176
177
6.49k
#[derive(Copy, Clone, Arbitrary)]
178
pub enum BinOp {
179
    Add,
180
    Sub,
181
    Mul,
182
    Mod,
183
    Shr,
184
    And,
185
    CmpEQ,
186
    CmpLT,
187
    CmpLE,
188
    CmpGE,
189
    CmpGT,
190
}
191
192
impl fmt::Debug for BinOp {
193
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
194
        write!(
195
0
            fmt,
196
0
            "{}",
197
0
            match self {
198
0
                BinOp::Add => "add",
199
0
                BinOp::Sub => "sub",
200
0
                BinOp::Mul => "mul",
201
0
                BinOp::Mod => "mod",
202
0
                BinOp::Shr => "shr",
203
0
                BinOp::And => "and",
204
0
                BinOp::CmpEQ => "cmp_eq",
205
0
                BinOp::CmpLT => "cmp_lt",
206
0
                BinOp::CmpLE => "cmp_le",
207
0
                BinOp::CmpGE => "cmp_ge",
208
0
                BinOp::CmpGT => "cmp_gt",
209
            }
210
        )
211
0
    }
212
}
213
214
impl fmt::Display for BinOp {
215
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
216
        (self as &dyn fmt::Debug).fmt(fmt)
217
    }
218
}
219
220
impl BinOp {
221
0
    pub fn calc(self, arg_left: u32, arg_right: u32) -> IResult<u32> {
222
0
        Ok(match self {
223
0
            BinOp::Add => u32::wrapping_add(arg_left, arg_right),
224
0
            BinOp::Sub => u32::wrapping_sub(arg_left, arg_right),
225
0
            BinOp::Mul => u32::wrapping_mul(arg_left, arg_right),
226
            BinOp::Mod => {
227
0
                if arg_right == 0 {
228
0
                    return Err("modulo by 0".into());
229
0
                }
230
0
                arg_left % arg_right
231
            }
232
0
            BinOp::Shr => arg_left >> (arg_right & 31),
233
0
            BinOp::And => arg_left & arg_right,
234
            BinOp::CmpEQ => {
235
0
                if arg_left == arg_right {
236
0
                    1
237
                } else {
238
0
                    0
239
                }
240
            }
241
            BinOp::CmpLT => {
242
0
                if arg_left < arg_right {
243
0
                    1
244
                } else {
245
0
                    0
246
                }
247
            }
248
            BinOp::CmpLE => {
249
0
                if arg_left <= arg_right {
250
0
                    1
251
                } else {
252
0
                    0
253
                }
254
            }
255
            BinOp::CmpGE => {
256
0
                if arg_left >= arg_right {
257
0
                    1
258
                } else {
259
0
                    0
260
                }
261
            }
262
            BinOp::CmpGT => {
263
0
                if arg_left > arg_right {
264
0
                    1
265
                } else {
266
0
                    0
267
                }
268
            }
269
        })
270
0
    }
271
}
272
273
661
#[derive(Copy, Clone, Arbitrary)]
274
pub enum BinOpF {
275
    FAdd,
276
    FSub,
277
    FMul,
278
    FDiv,
279
}
280
281
impl fmt::Debug for BinOpF {
282
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
283
        write!(
284
0
            fmt,
285
0
            "{}",
286
0
            match self {
287
0
                BinOpF::FAdd => "fadd".to_string(),
288
0
                BinOpF::FSub => "fsub".to_string(),
289
0
                BinOpF::FMul => "fmul".to_string(),
290
0
                BinOpF::FDiv => "fdiv".to_string(),
291
            }
292
        )
293
0
    }
294
}
295
296
impl fmt::Display for BinOpF {
297
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
298
        (self as &dyn fmt::Debug).fmt(fmt)
299
    }
300
}
301
302
impl BinOpF {
303
0
    pub fn calc(self, arg_left: f32, arg_right: f32) -> IResult<f32> {
304
0
        Ok(match self {
305
0
            BinOpF::FAdd => arg_left + arg_right,
306
0
            BinOpF::FSub => arg_left - arg_right,
307
0
            BinOpF::FMul => arg_left * arg_right,
308
            BinOpF::FDiv => {
309
0
                if arg_right == 0.0 {
310
0
                    return Err("division by zero".into());
311
0
                }
312
0
                arg_left / arg_right
313
            }
314
        })
315
0
    }
316
}
317
318
221k
#[derive(Clone)]
319
pub enum Inst {
320
    NopZ {},
321
    Imm {
322
        dst: Reg,
323
        imm: u32,
324
    },
325
    ImmF {
326
        dst: Reg,
327
        imm: f32,
328
    },
329
    Copy {
330
        dst: Reg,
331
        src: Reg,
332
    },
333
    CopyF {
334
        dst: Reg,
335
        src: Reg,
336
    },
337
    BinOp {
338
        op: BinOp,
339
        dst: Reg,
340
        src_left: Reg,
341
        src_right: RI,
342
    },
343
    BinOpM {
344
        op: BinOp,
345
        dst: Reg,
346
        src_right: RI,
347
    }, // "mod" semantics for `dst`
348
    BinOpF {
349
        op: BinOpF,
350
        dst: Reg,
351
        src_left: Reg,
352
        src_right: Reg,
353
    },
354
    Load {
355
        dst: Reg,
356
        addr: AM,
357
    },
358
    LoadF {
359
        dst: Reg,
360
        addr: AM,
361
    },
362
    Store {
363
        addr: AM,
364
        src: Reg,
365
    },
366
    StoreF {
367
        addr: AM,
368
        src: Reg,
369
    },
370
    MakeRef {
371
        dst: Reg,
372
        src: Reg,
373
    },
374
    UseRef {
375
        dst: Reg,
376
        src: Reg,
377
    },
378
    Safepoint,
379
    Spill {
380
        dst: SpillSlot,
381
        src: RealReg,
382
    },
383
    SpillF {
384
        dst: SpillSlot,
385
        src: RealReg,
386
    },
387
    Reload {
388
        dst: RealReg,
389
        src: SpillSlot,
390
    },
391
    ReloadF {
392
        dst: RealReg,
393
        src: SpillSlot,
394
    },
395
    Goto {
396
        target: Label,
397
    },
398
    GotoCTF {
399
        cond: Reg,
400
        target_true: Label,
401
        target_false: Label,
402
    },
403
    PrintS {
404
        str: String,
405
    },
406
    PrintI {
407
        reg: Reg,
408
    },
409
    PrintF {
410
        reg: Reg,
411
    },
412
    Finish {
413
        reg: Option<Reg>,
414
    },
415
}
416
417
pub fn i_imm(dst: Reg, imm: u32) -> Inst {
418
    debug_assert!(dst.get_class() == RegClass::I32);
419
    Inst::Imm { dst, imm }
420
}
421
pub fn i_immf(dst: Reg, imm: f32) -> Inst {
422
    debug_assert!(dst.get_class() == RegClass::F32);
423
    Inst::ImmF { dst, imm }
424
}
425
pub fn i_copy(dst: Reg, src: Reg) -> Inst {
426
    debug_assert!(dst.get_class() == RegClass::I32);
427
    debug_assert!(src.get_class() == RegClass::I32);
428
    Inst::Copy { dst, src }
429
}
430
pub fn i_copyf(dst: Reg, src: Reg) -> Inst {
431
    debug_assert!(dst.get_class() == RegClass::F32);
432
    debug_assert!(src.get_class() == RegClass::F32);
433
    Inst::CopyF { dst, src }
434
}
435
// For BinOp variants see below
436
437
pub fn i_load(dst: Reg, addr: AM) -> Inst {
438
    debug_assert!(dst.get_class() == RegClass::I32);
439
    Inst::Load { dst, addr }
440
}
441
pub fn i_loadf(dst: Reg, addr: AM) -> Inst {
442
    debug_assert!(dst.get_class() == RegClass::F32);
443
    Inst::LoadF { dst, addr }
444
}
445
pub fn i_store(addr: AM, src: Reg) -> Inst {
446
    debug_assert!(src.get_class() == RegClass::I32);
447
    Inst::Store { addr, src }
448
}
449
pub fn i_storef(addr: AM, src: Reg) -> Inst {
450
    debug_assert!(src.get_class() == RegClass::F32);
451
    Inst::StoreF { addr, src }
452
}
453
11.2k
fn i_spill(dst: SpillSlot, src: RealReg) -> Inst {
454
    debug_assert!(src.get_class() == RegClass::I32);
455
11.2k
    Inst::Spill { dst, src }
456
11.2k
}
457
102
fn i_spillf(dst: SpillSlot, src: RealReg) -> Inst {
458
    debug_assert!(src.get_class() == RegClass::F32);
459
102
    Inst::SpillF { dst, src }
460
102
}
461
16.0k
fn i_reload(dst: RealReg, src: SpillSlot) -> Inst {
462
    debug_assert!(dst.get_class() == RegClass::I32);
463
16.0k
    Inst::Reload { dst, src }
464
16.0k
}
465
288
fn i_reloadf(dst: RealReg, src: SpillSlot) -> Inst {
466
    debug_assert!(dst.get_class() == RegClass::F32);
467
288
    Inst::ReloadF { dst, src }
468
288
}
469
pub fn i_goto<'a>(target: &'a str) -> Inst {
470
    Inst::Goto {
471
        target: Label::new_unresolved(target.to_string()),
472
    }
473
}
474
pub fn i_goto_ctf<'a>(cond: Reg, target_true: &'a str, target_false: &'a str) -> Inst {
475
    debug_assert!(cond.get_class() == RegClass::I32);
476
    Inst::GotoCTF {
477
        cond,
478
        target_true: Label::new_unresolved(target_true.to_string()),
479
        target_false: Label::new_unresolved(target_false.to_string()),
480
    }
481
}
482
pub fn i_print_s<'a>(str: &'a str) -> Inst {
483
    Inst::PrintS {
484
        str: str.to_string(),
485
    }
486
}
487
pub fn i_print_i(reg: Reg) -> Inst {
488
    debug_assert!(reg.get_class() == RegClass::I32);
489
    Inst::PrintI { reg }
490
}
491
0
pub fn i_print_f(reg: Reg) -> Inst {
492
    debug_assert!(reg.get_class() == RegClass::F32);
493
0
    Inst::PrintF { reg }
494
0
}
495
pub fn i_finish(reg: Option<Reg>) -> Inst {
496
    Inst::Finish { reg }
497
}
498
499
pub fn i_add(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
500
    debug_assert!(dst.get_class() == RegClass::I32);
501
    debug_assert!(src_left.get_class() == RegClass::I32);
502
    Inst::BinOp {
503
        op: BinOp::Add,
504
        dst,
505
        src_left,
506
        src_right,
507
    }
508
}
509
pub fn i_sub(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
510
    debug_assert!(dst.get_class() == RegClass::I32);
511
    debug_assert!(src_left.get_class() == RegClass::I32);
512
    Inst::BinOp {
513
        op: BinOp::Sub,
514
        dst,
515
        src_left,
516
        src_right,
517
    }
518
}
519
pub fn i_mul(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
520
    debug_assert!(dst.get_class() == RegClass::I32);
521
    debug_assert!(src_left.get_class() == RegClass::I32);
522
    Inst::BinOp {
523
        op: BinOp::Mul,
524
        dst,
525
        src_left,
526
        src_right,
527
    }
528
}
529
pub fn i_mod(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
530
    debug_assert!(dst.get_class() == RegClass::I32);
531
    debug_assert!(src_left.get_class() == RegClass::I32);
532
    Inst::BinOp {
533
        op: BinOp::Mod,
534
        dst,
535
        src_left,
536
        src_right,
537
    }
538
}
539
pub fn i_shr(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
540
    debug_assert!(dst.get_class() == RegClass::I32);
541
    debug_assert!(src_left.get_class() == RegClass::I32);
542
    Inst::BinOp {
543
        op: BinOp::Shr,
544
        dst,
545
        src_left,
546
        src_right,
547
    }
548
}
549
pub fn i_and(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
550
    debug_assert!(dst.get_class() == RegClass::I32);
551
    debug_assert!(src_left.get_class() == RegClass::I32);
552
    Inst::BinOp {
553
        op: BinOp::And,
554
        dst,
555
        src_left,
556
        src_right,
557
    }
558
}
559
pub fn i_cmp_eq(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
560
    debug_assert!(dst.get_class() == RegClass::I32);
561
    debug_assert!(src_left.get_class() == RegClass::I32);
562
    Inst::BinOp {
563
        op: BinOp::CmpEQ,
564
        dst,
565
        src_left,
566
        src_right,
567
    }
568
}
569
pub fn i_cmp_lt(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
570
    debug_assert!(dst.get_class() == RegClass::I32);
571
    debug_assert!(src_left.get_class() == RegClass::I32);
572
    Inst::BinOp {
573
        op: BinOp::CmpLT,
574
        dst,
575
        src_left,
576
        src_right,
577
    }
578
}
579
pub fn i_cmp_le(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
580
    debug_assert!(dst.get_class() == RegClass::I32);
581
    debug_assert!(src_left.get_class() == RegClass::I32);
582
    Inst::BinOp {
583
        op: BinOp::CmpLE,
584
        dst,
585
        src_left,
586
        src_right,
587
    }
588
}
589
pub fn i_cmp_ge(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
590
    debug_assert!(dst.get_class() == RegClass::I32);
591
    debug_assert!(src_left.get_class() == RegClass::I32);
592
    Inst::BinOp {
593
        op: BinOp::CmpGE,
594
        dst,
595
        src_left,
596
        src_right,
597
    }
598
}
599
pub fn i_cmp_gt(dst: Reg, src_left: Reg, src_right: RI) -> Inst {
600
    debug_assert!(dst.get_class() == RegClass::I32);
601
    debug_assert!(src_left.get_class() == RegClass::I32);
602
    Inst::BinOp {
603
        op: BinOp::CmpGT,
604
        dst,
605
        src_left,
606
        src_right,
607
    }
608
}
609
610
// 2-operand versions of i_add and i_sub, for experimentation
611
pub fn i_addm(dst: Reg, src_right: RI) -> Inst {
612
    debug_assert!(dst.get_class() == RegClass::I32);
613
    Inst::BinOpM {
614
        op: BinOp::Add,
615
        dst,
616
        src_right,
617
    }
618
}
619
pub fn i_andm(dst: Reg, src_right: RI) -> Inst {
620
    debug_assert!(dst.get_class() == RegClass::I32);
621
    Inst::BinOpM {
622
        op: BinOp::And,
623
        dst,
624
        src_right,
625
    }
626
}
627
pub fn i_modm(dst: Reg, src_right: RI) -> Inst {
628
    debug_assert!(dst.get_class() == RegClass::I32);
629
    Inst::BinOpM {
630
        op: BinOp::Mod,
631
        dst,
632
        src_right,
633
    }
634
}
635
pub fn i_mulm(dst: Reg, src_right: RI) -> Inst {
636
    debug_assert!(dst.get_class() == RegClass::I32);
637
    Inst::BinOpM {
638
        op: BinOp::Mul,
639
        dst,
640
        src_right,
641
    }
642
}
643
pub fn i_shrm(dst: Reg, src_right: RI) -> Inst {
644
    debug_assert!(dst.get_class() == RegClass::I32);
645
    Inst::BinOpM {
646
        op: BinOp::Shr,
647
        dst,
648
        src_right,
649
    }
650
}
651
pub fn i_subm(dst: Reg, src_right: RI) -> Inst {
652
    debug_assert!(dst.get_class() == RegClass::I32);
653
    Inst::BinOpM {
654
        op: BinOp::Sub,
655
        dst,
656
        src_right,
657
    }
658
}
659
pub fn i_cmp_eqm(dst: Reg, src_right: RI) -> Inst {
660
    debug_assert!(dst.get_class() == RegClass::I32);
661
    Inst::BinOpM {
662
        op: BinOp::CmpEQ,
663
        dst,
664
        src_right,
665
    }
666
}
667
pub fn i_cmp_gem(dst: Reg, src_right: RI) -> Inst {
668
    debug_assert!(dst.get_class() == RegClass::I32);
669
    Inst::BinOpM {
670
        op: BinOp::CmpGE,
671
        dst,
672
        src_right,
673
    }
674
}
675
pub fn i_cmp_gtm(dst: Reg, src_right: RI) -> Inst {
676
    debug_assert!(dst.get_class() == RegClass::I32);
677
    Inst::BinOpM {
678
        op: BinOp::CmpGT,
679
        dst,
680
        src_right,
681
    }
682
}
683
pub fn i_cmp_lem(dst: Reg, src_right: RI) -> Inst {
684
    debug_assert!(dst.get_class() == RegClass::I32);
685
    Inst::BinOpM {
686
        op: BinOp::CmpLE,
687
        dst,
688
        src_right,
689
    }
690
}
691
pub fn i_cmp_ltm(dst: Reg, src_right: RI) -> Inst {
692
    debug_assert!(dst.get_class() == RegClass::I32);
693
    Inst::BinOpM {
694
        op: BinOp::CmpLT,
695
        dst,
696
        src_right,
697
    }
698
}
699
700
pub fn i_fadd(dst: Reg, src_left: Reg, src_right: Reg) -> Inst {
701
    debug_assert!(dst.get_class() == RegClass::F32);
702
    debug_assert!(src_left.get_class() == RegClass::F32);
703
    debug_assert!(src_right.get_class() == RegClass::F32);
704
    Inst::BinOpF {
705
        op: BinOpF::FAdd,
706
        dst,
707
        src_left,
708
        src_right,
709
    }
710
}
711
pub fn i_fsub(dst: Reg, src_left: Reg, src_right: Reg) -> Inst {
712
    debug_assert!(dst.get_class() == RegClass::F32);
713
    debug_assert!(src_left.get_class() == RegClass::F32);
714
    debug_assert!(src_right.get_class() == RegClass::F32);
715
    Inst::BinOpF {
716
        op: BinOpF::FSub,
717
        dst,
718
        src_left,
719
        src_right,
720
    }
721
}
722
pub fn i_fmul(dst: Reg, src_left: Reg, src_right: Reg) -> Inst {
723
    debug_assert!(dst.get_class() == RegClass::F32);
724
    debug_assert!(src_left.get_class() == RegClass::F32);
725
    debug_assert!(src_right.get_class() == RegClass::F32);
726
    Inst::BinOpF {
727
        op: BinOpF::FMul,
728
        dst,
729
        src_left,
730
        src_right,
731
    }
732
}
733
pub fn i_fdiv(dst: Reg, src_left: Reg, src_right: Reg) -> Inst {
734
    debug_assert!(dst.get_class() == RegClass::F32);
735
    debug_assert!(src_left.get_class() == RegClass::F32);
736
    debug_assert!(src_right.get_class() == RegClass::F32);
737
    Inst::BinOpF {
738
        op: BinOpF::FDiv,
739
        dst,
740
        src_left,
741
        src_right,
742
    }
743
}
744
745
impl fmt::Debug for Inst {
746
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
747
0
        fn ljustify(s: String, w: usize) -> String {
748
0
            if s.len() >= w {
749
0
                s
750
0
            } else {
751
0
                // BEGIN hack
752
0
                let mut need = w - s.len();
753
0
                if need > 5 {
754
0
                    need = 5;
755
0
                }
756
0
                let extra = [" ", "  ", "   ", "    ", "     "][need - 1];
757
0
                // END hack
758
0
                s + &extra.to_string()
759
0
            }
760
0
        }
761
0
762
0
        match self {
763
0
            Inst::NopZ {} => write!(fmt, "nopz"),
764
0
            Inst::Imm { dst, imm } => write!(fmt, "imm     {:?}, {:?}", dst, imm),
765
0
            Inst::ImmF { dst, imm } => write!(fmt, "immf    {:?}, {:?}", dst, imm),
766
0
            Inst::Copy { dst, src } => write!(fmt, "copy    {:?}, {:?}", dst, src),
767
0
            Inst::CopyF { dst, src } => write!(fmt, "copyf   {:?}, {:?}", dst, src),
768
            Inst::BinOp {
769
0
                op,
770
0
                dst,
771
0
                src_left,
772
0
                src_right,
773
0
            } => write!(
774
0
                fmt,
775
0
                "{} {:?}, {:?}, {:?}",
776
0
                ljustify(op.to_string(), 7),
777
0
                dst,
778
0
                src_left,
779
0
                src_right
780
0
            ),
781
0
            Inst::BinOpM { op, dst, src_right } => write!(
782
0
                fmt,
783
0
                "{} {:?}, {:?}",
784
0
                ljustify(op.to_string() + &"m".to_string(), 7),
785
0
                dst,
786
0
                src_right
787
0
            ),
788
            Inst::BinOpF {
789
0
                op,
790
0
                dst,
791
0
                src_left,
792
0
                src_right,
793
0
            } => write!(
794
0
                fmt,
795
0
                "{} {:?}, {:?}, {:?}",
796
0
                ljustify(op.to_string(), 7),
797
0
                dst,
798
0
                src_left,
799
0
                src_right
800
0
            ),
801
0
            Inst::Load { dst, addr } => write!(fmt, "load    {:?}, {:?}", dst, addr),
802
0
            Inst::LoadF { dst, addr } => write!(fmt, "loadf   {:?}, {:?}", dst, addr),
803
0
            Inst::Store { addr, src } => write!(fmt, "store   {:?}, {:?}", addr, src),
804
0
            Inst::StoreF { addr, src } => write!(fmt, "storef  {:?}, {:?}", addr, src),
805
0
            Inst::MakeRef { dst, src } => write!(fmt, "makeref {:?}, {:?}", dst, src),
806
0
            Inst::UseRef { dst, src } => write!(fmt, "useref  {:?}, {:?}", dst, src),
807
0
            Inst::Safepoint => write!(fmt, "safepoint"),
808
0
            Inst::Spill { dst, src } => write!(fmt, "SPILL   {:?}, {:?}", dst, src),
809
0
            Inst::SpillF { dst, src } => write!(fmt, "SPILLF  {:?}, {:?}", dst, src),
810
0
            Inst::Reload { dst, src } => write!(fmt, "RELOAD  {:?}, {:?}", dst, src),
811
0
            Inst::ReloadF { dst, src } => write!(fmt, "RELOAD  {:?}, {:?}", dst, src),
812
0
            Inst::Goto { target } => write!(fmt, "goto    {:?}", target),
813
            Inst::GotoCTF {
814
0
                cond,
815
0
                target_true,
816
0
                target_false,
817
0
            } => write!(
818
0
                fmt,
819
0
                "if_then_else {:?}, {:?}, {:?}",
820
0
                cond, target_true, target_false
821
0
            ),
822
0
            Inst::PrintS { str } => {
823
0
                let mut res = "prints  '".to_string();
824
0
                for c in str.chars() {
825
0
                    res += &(if c == '\n' {
826
0
                        "\\n".to_string()
827
                    } else {
828
0
                        c.to_string()
829
                    });
830
                }
831
0
                write!(fmt, "{}'", res)
832
            }
833
0
            Inst::PrintI { reg } => write!(fmt, "printi  {:?}", reg),
834
0
            Inst::PrintF { reg } => write!(fmt, "printf  {:?}", reg),
835
0
            Inst::Finish { reg } => {
836
0
                if let Some(reg) = reg {
837
0
                    write!(fmt, "finish  {:?}", reg)
838
                } else {
839
0
                    write!(fmt, "finish")
840
                }
841
            }
842
        }
843
0
    }
844
}
845
846
impl Inst {
847
    // Returns a vector of BlockIxs, being those that this insn might jump to.
848
    // This might contain duplicates (although it would be pretty strange if
849
    // it did). This function should not be applied to non-control-flow
850
    // instructions.  The labels are assumed all to be "resolved".
851
38.2k
    pub fn get_targets(&self) -> Vec<BlockIx> {
852
38.2k
        match self {
853
25.7k
            Inst::Goto { target } => vec![target.get_block_ix()],
854
            Inst::GotoCTF {
855
                cond: _,
856
10.5k
                target_true,
857
10.5k
                target_false,
858
10.5k
            } => vec![target_true.get_block_ix(), target_false.get_block_ix()],
859
1.88k
            Inst::Finish { reg: _ } => vec![],
860
0
            _other => panic!("Inst::getTargets: incorrectly applied to: {:?}", self),
861
        }
862
38.2k
    }
863
864
    // Returns three sets of regs, (def, mod, use), being those def'd (written),
865
    // those mod'd (modified) and those use'd (read) by the instruction,
866
    // respectively.
867
    //
868
    // Be careful here.  If an instruction really modifies a register -- as is
869
    // typical for x86 -- that register needs to be in the `mod` set, and not in
870
    // the `def` and `use` sets.  *Any* mistake in describing register uses here
871
    // will almost certainly lead to incorrect register allocations.
872
    //
873
    // Also the following must hold: the union of `def` and `use` must be
874
    // disjoint from `mod`.
875
328k
    pub fn get_reg_usage(&self, collector: &mut RegUsageCollector) {
876
328k
        match self {
877
4.36k
            Inst::NopZ {} => {}
878
83.6k
            Inst::Imm { dst, imm: _ } => {
879
83.6k
                collector.add_def(Writable::from_reg(*dst));
880
83.6k
            }
881
10.7k
            Inst::ImmF { dst, imm: _ } => {
882
10.7k
                collector.add_def(Writable::from_reg(*dst));
883
10.7k
            }
884
62.1k
            Inst::Copy { dst, src } => {
885
62.1k
                collector.add_def(Writable::from_reg(*dst));
886
62.1k
                collector.add_use(*src);
887
62.1k
            }
888
4.87k
            Inst::CopyF { dst, src } => {
889
4.87k
                collector.add_def(Writable::from_reg(*dst));
890
4.87k
                collector.add_use(*src);
891
4.87k
            }
892
            Inst::BinOp {
893
                op: _,
894
1.76k
                dst,
895
1.76k
                src_left,
896
1.76k
                src_right,
897
1.76k
            } => {
898
1.76k
                collector.add_def(Writable::from_reg(*dst));
899
1.76k
                collector.add_use(*src_left);
900
1.76k
                src_right.add_reg_reads_to(collector);
901
1.76k
            }
902
            Inst::BinOpM {
903
                op: _,
904
6.96k
                dst,
905
6.96k
                src_right,
906
6.96k
            } => {
907
6.96k
                collector.add_mod(Writable::from_reg(*dst));
908
6.96k
                src_right.add_reg_reads_to(collector);
909
6.96k
            }
910
            Inst::BinOpF {
911
                op: _,
912
771
                dst,
913
771
                src_left,
914
771
                src_right,
915
771
            } => {
916
771
                collector.add_def(Writable::from_reg(*dst));
917
771
                collector.add_use(*src_left);
918
771
                collector.add_use(*src_right);
919
771
            }
920
4.32k
            Inst::Store { addr, src } => {
921
4.32k
                addr.add_reg_reads_to(collector);
922
4.32k
                collector.add_use(*src);
923
4.32k
            }
924
6.71k
            Inst::StoreF { addr, src } => {
925
6.71k
                addr.add_reg_reads_to(collector);
926
6.71k
                collector.add_use(*src);
927
6.71k
            }
928
14.1k
            Inst::MakeRef { dst, src } => {
929
14.1k
                collector.add_def(Writable::from_reg(*dst));
930
14.1k
                collector.add_use(*src);
931
14.1k
            }
932
6.05k
            Inst::UseRef { dst, src } => {
933
6.05k
                collector.add_def(Writable::from_reg(*dst));
934
6.05k
                collector.add_use(*src);
935
6.05k
            }
936
37.0k
            Inst::Safepoint => {}
937
2.29k
            Inst::Load { dst, addr } => {
938
2.29k
                collector.add_def(Writable::from_reg(*dst));
939
2.29k
                addr.add_reg_reads_to(collector);
940
2.29k
            }
941
3.77k
            Inst::LoadF { dst, addr } => {
942
3.77k
                collector.add_def(Writable::from_reg(*dst));
943
3.77k
                addr.add_reg_reads_to(collector);
944
3.77k
            }
945
33.8k
            Inst::Goto { .. } => {}
946
            Inst::GotoCTF {
947
14.8k
                cond,
948
14.8k
                target_true: _,
949
14.8k
                target_false: _,
950
14.8k
            } => {
951
14.8k
                collector.add_use(*cond);
952
14.8k
            }
953
0
            Inst::PrintS { .. } => {}
954
0
            Inst::PrintI { reg } => {
955
0
                collector.add_use(*reg);
956
0
            }
957
0
            Inst::PrintF { reg } => {
958
0
                collector.add_use(*reg);
959
0
            }
960
2.04k
            Inst::Finish { reg } => {
961
2.04k
                if let Some(reg) = reg {
962
597
                    collector.add_use(*reg);
963
1.44k
                }
964
            }
965
            // Spill and Reload are seen here during the final pass over insts that
966
            // computes clobbered regs.
967
11.3k
            Inst::Spill { src, .. } | Inst::SpillF { src, .. } => {
968
11.3k
                collector.add_use(src.to_reg());
969
11.3k
            }
970
16.3k
            Inst::Reload { dst, .. } | Inst::ReloadF { dst, .. } => {
971
16.3k
                collector.add_def(Writable::from_reg(dst.to_reg()));
972
16.3k
            }
973
        }
974
328k
    }
975
976
    /// Apply the specified VirtualReg->RealReg mappings to the instruction,
977
94.0k
    pub fn map_regs<RUM: RegUsageMapper>(&mut self, mapper: &RUM) {
978
94.0k
        match self {
979
0
            Inst::NopZ {} => {}
980
27.1k
            Inst::Imm { dst, imm: _ } => {
981
27.1k
                dst.apply_defs(mapper);
982
27.1k
            }
983
3.43k
            Inst::ImmF { dst, imm: _ } => {
984
3.43k
                dst.apply_defs(mapper);
985
3.43k
            }
986
18.6k
            Inst::Copy { dst, src } => {
987
18.6k
                dst.apply_defs(mapper);
988
18.6k
                src.apply_uses(mapper);
989
18.6k
            }
990
1.57k
            Inst::CopyF { dst, src } => {
991
1.57k
                dst.apply_defs(mapper);
992
1.57k
                src.apply_uses(mapper);
993
1.57k
            }
994
            Inst::BinOp {
995
                op: _,
996
563
                dst,
997
563
                src_left,
998
563
                src_right,
999
563
            } => {
1000
563
                dst.apply_defs(mapper);
1001
563
                src_left.apply_uses(mapper);
1002
563
                src_right.apply_uses(mapper);
1003
563
            }
1004
            Inst::BinOpM {
1005
                op: _,
1006
2.28k
                dst,
1007
2.28k
                src_right,
1008
2.28k
            } => {
1009
2.28k
                dst.apply_mods(mapper);
1010
2.28k
                src_right.apply_uses(mapper);
1011
2.28k
            }
1012
            Inst::BinOpF {
1013
                op: _,
1014
242
                dst,
1015
242
                src_left,
1016
242
                src_right,
1017
242
            } => {
1018
242
                dst.apply_defs(mapper);
1019
242
                src_left.apply_uses(mapper);
1020
242
                src_right.apply_uses(mapper);
1021
242
            }
1022
4.58k
            Inst::MakeRef { dst, src } => {
1023
4.58k
                dst.apply_defs(mapper);
1024
4.58k
                src.apply_uses(mapper);
1025
4.58k
            }
1026
1.98k
            Inst::UseRef { dst, src } => {
1027
1.98k
                dst.apply_defs(mapper);
1028
1.98k
                src.apply_uses(mapper);
1029
1.98k
            }
1030
11.8k
            Inst::Safepoint => {}
1031
1.32k
            Inst::Store { addr, src } => {
1032
1.32k
                addr.apply_uses(mapper);
1033
1.32k
                src.apply_uses(mapper);
1034
1.32k
            }
1035
2.10k
            Inst::StoreF { addr, src } => {
1036
2.10k
                addr.apply_uses(mapper);
1037
2.10k
                src.apply_uses(mapper);
1038
2.10k
            }
1039
724
            Inst::Load { dst, addr } => {
1040
724
                dst.apply_defs(mapper);
1041
724
                addr.apply_uses(mapper);
1042
724
            }
1043
1.21k
            Inst::LoadF { dst, addr } => {
1044
1.21k
                dst.apply_defs(mapper);
1045
1.21k
                addr.apply_uses(mapper);
1046
1.21k
            }
1047
10.9k
            Inst::Goto { .. } => {}
1048
            Inst::GotoCTF {
1049
4.71k
                cond,
1050
4.71k
                target_true: _,
1051
4.71k
                target_false: _,
1052
4.71k
            } => {
1053
4.71k
                cond.apply_uses(mapper);
1054
4.71k
            }
1055
0
            Inst::PrintS { .. } => {}
1056
0
            Inst::PrintI { reg } => {
1057
0
                reg.apply_uses(mapper);
1058
0
            }
1059
0
            Inst::PrintF { reg } => {
1060
0
                reg.apply_uses(mapper);
1061
0
            }
1062
663
            Inst::Finish { reg } => {
1063
663
                if let Some(reg) = reg {
1064
188
                    reg.apply_uses(mapper);
1065
475
                }
1066
            }
1067
            Inst::Spill { .. }
1068
            | Inst::SpillF { .. }
1069
            | Inst::Reload { .. }
1070
            | Inst::ReloadF { .. } => {
1071
0
                unreachable!("no need to fill in instructions inserted by regalloc")
1072
            }
1073
        }
1074
94.0k
    }
<minira::test_framework::Inst>::map_regs::<regalloc::reg_maps::VrangeRegUsageMapper>
Line
Count
Source
977
94.0k
    pub fn map_regs<RUM: RegUsageMapper>(&mut self, mapper: &RUM) {
978
94.0k
        match self {
979
0
            Inst::NopZ {} => {}
980
27.1k
            Inst::Imm { dst, imm: _ } => {
981
27.1k
                dst.apply_defs(mapper);
982
27.1k
            }
983
3.43k
            Inst::ImmF { dst, imm: _ } => {
984
3.43k
                dst.apply_defs(mapper);
985
3.43k
            }
986
18.6k
            Inst::Copy { dst, src } => {
987
18.6k
                dst.apply_defs(mapper);
988
18.6k
                src.apply_uses(mapper);
989
18.6k
            }
990
1.57k
            Inst::CopyF { dst, src } => {
991
1.57k
                dst.apply_defs(mapper);
992
1.57k
                src.apply_uses(mapper);
993
1.57k
            }
994
            Inst::BinOp {
995
                op: _,
996
563
                dst,
997
563
                src_left,
998
563
                src_right,
999
563
            } => {
1000
563
                dst.apply_defs(mapper);
1001
563
                src_left.apply_uses(mapper);
1002
563
                src_right.apply_uses(mapper);
1003
563
            }
1004
            Inst::BinOpM {
1005
                op: _,
1006
2.28k
                dst,
1007
2.28k
                src_right,
1008
2.28k
            } => {
1009
2.28k
                dst.apply_mods(mapper);
1010
2.28k
                src_right.apply_uses(mapper);
1011
2.28k
            }
1012
            Inst::BinOpF {
1013
                op: _,
1014
242
                dst,
1015
242
                src_left,
1016
242
                src_right,
1017
242
            } => {
1018
242
                dst.apply_defs(mapper);
1019
242
                src_left.apply_uses(mapper);
1020
242
                src_right.apply_uses(mapper);
1021
242
            }
1022
4.58k
            Inst::MakeRef { dst, src } => {
1023
4.58k
                dst.apply_defs(mapper);
1024
4.58k
                src.apply_uses(mapper);
1025
4.58k
            }
1026
1.98k
            Inst::UseRef { dst, src } => {
1027
1.98k
                dst.apply_defs(mapper);
1028
1.98k
                src.apply_uses(mapper);
1029
1.98k
            }
1030
11.8k
            Inst::Safepoint => {}
1031
1.32k
            Inst::Store { addr, src } => {
1032
1.32k
                addr.apply_uses(mapper);
1033
1.32k
                src.apply_uses(mapper);
1034
1.32k
            }
1035
2.10k
            Inst::StoreF { addr, src } => {
1036
2.10k
                addr.apply_uses(mapper);
1037
2.10k
                src.apply_uses(mapper);
1038
2.10k
            }
1039
724
            Inst::Load { dst, addr } => {
1040
724
                dst.apply_defs(mapper);
1041
724
                addr.apply_uses(mapper);
1042
724
            }
1043
1.21k
            Inst::LoadF { dst, addr } => {
1044
1.21k
                dst.apply_defs(mapper);
1045
1.21k
                addr.apply_uses(mapper);
1046
1.21k
            }
1047
10.9k
            Inst::Goto { .. } => {}
1048
            Inst::GotoCTF {
1049
4.71k
                cond,
1050
4.71k
                target_true: _,
1051
4.71k
                target_false: _,
1052
4.71k
            } => {
1053
4.71k
                cond.apply_uses(mapper);
1054
4.71k
            }
1055
0
            Inst::PrintS { .. } => {}
1056
0
            Inst::PrintI { reg } => {
1057
0
                reg.apply_uses(mapper);
1058
0
            }
1059
0
            Inst::PrintF { reg } => {
1060
0
                reg.apply_uses(mapper);
1061
0
            }
1062
663
            Inst::Finish { reg } => {
1063
663
                if let Some(reg) = reg {
1064
188
                    reg.apply_uses(mapper);
1065
475
                }
1066
            }
1067
            Inst::Spill { .. }
1068
            | Inst::SpillF { .. }
1069
            | Inst::Reload { .. }
1070
            | Inst::ReloadF { .. } => {
1071
0
                unreachable!("no need to fill in instructions inserted by regalloc")
1072
            }
1073
        }
1074
94.0k
    }
Unexecuted instantiation: <minira::test_framework::Inst>::map_regs::<regalloc::reg_maps::MentionRegUsageMapper>
1075
1076
108k
    pub fn is_control_flow(&self) -> bool {
1077
108k
        match self {
1078
21.8k
            Inst::Goto { .. } | Inst::GotoCTF { .. } | Inst::Finish { reg: _ } => true,
1079
86.4k
            _ => false,
1080
        }
1081
108k
    }
1082
1083
    /// Is this instruction a user instruction, or is it internal to regalloc?
1084
    pub fn is_user(&self) -> bool {
1085
        match self {
1086
            Inst::Spill { .. }
1087
            | Inst::SpillF { .. }
1088
            | Inst::Reload { .. }
1089
            | Inst::ReloadF { .. } => false,
1090
            _ => true,
1091
        }
1092
    }
1093
1094
    pub fn type_checks(&self, cx: &mut ValidatorContext) -> bool {
1095
        use RegClass::*;
1096
        // Always check uses before defs.
1097
        match self {
1098
            Inst::NopZ {} => true,
1099
            Inst::Imm { dst, imm: _ } => cx.check_reg_rc(dst, RegRef::Def, I32),
1100
            Inst::ImmF { dst, imm: _ } => cx.check_reg_rc(dst, RegRef::Def, F32),
1101
            // MakeRef and UseRef are like copy instructions; the typecheck only
1102
            // reasons about register classes, not reffyness, so the
1103
            // distinctions between the three are irrelevant here.
1104
            Inst::Copy { dst, src } | Inst::MakeRef { dst, src } | Inst::UseRef { dst, src } => {
1105
                cx.check_reg_rc(src, RegRef::Use, I32) && cx.check_reg_rc(dst, RegRef::Def, I32)
1106
            }
1107
            Inst::CopyF { dst, src } => {
1108
                cx.check_reg_rc(src, RegRef::Use, F32) && cx.check_reg_rc(dst, RegRef::Def, F32)
1109
            }
1110
            Inst::Load { dst, addr } => {
1111
                addr.type_checks(cx) && cx.check_reg_rc(dst, RegRef::Def, I32)
1112
            }
1113
            Inst::LoadF { dst, addr } => {
1114
                addr.type_checks(cx) && cx.check_reg_rc(dst, RegRef::Def, F32)
1115
            }
1116
            Inst::Store { addr, src } => {
1117
                cx.check_reg_rc(src, RegRef::Use, I32) && addr.type_checks(cx)
1118
            }
1119
            Inst::StoreF { addr, src } => {
1120
                cx.check_reg_rc(src, RegRef::Use, F32) && addr.type_checks(cx)
1121
            }
1122
            Inst::Goto { target } => target.type_checks(cx),
1123
            Inst::GotoCTF {
1124
                cond,
1125
                target_true,
1126
                target_false,
1127
            } => {
1128
                cx.check_reg_rc(cond, RegRef::Use, I32)
1129
                    && target_true.type_checks(cx)
1130
                    && target_false.type_checks(cx)
1131
            }
1132
            Inst::PrintS { .. } => true,
1133
            Inst::PrintI { reg } => cx.check_reg_rc(reg, RegRef::Use, I32),
1134
            Inst::PrintF { reg } => cx.check_reg_rc(reg, RegRef::Use, F32),
1135
            Inst::Finish { reg } => reg.map_or(true, |reg| cx.check_reg(reg, RegRef::Use)),
1136
            Inst::BinOp {
1137
                op: _,
1138
                dst,
1139
                src_left,
1140
                src_right,
1141
            } => {
1142
                cx.check_reg_rc(src_left, RegRef::Use, I32)
1143
                    && src_right.type_checks(cx)
1144
                    && cx.check_reg_rc(dst, RegRef::Def, I32)
1145
            }
1146
            Inst::BinOpM {
1147
                op: _,
1148
                dst,
1149
                src_right,
1150
            } => {
1151
                cx.check_reg_rc(dst, RegRef::Use, I32)
1152
                    && src_right.type_checks(cx)
1153
                    && cx.check_reg_rc(dst, RegRef::Def, I32)
1154
            }
1155
            Inst::BinOpF {
1156
                op: _,
1157
                dst,
1158
                src_left,
1159
                src_right,
1160
            } => {
1161
                cx.check_reg_rc(src_left, RegRef::Use, F32)
1162
                    && cx.check_reg_rc(src_right, RegRef::Use, F32)
1163
                    && cx.check_reg_rc(dst, RegRef::Def, F32)
1164
            }
1165
            Inst::Safepoint => true,
1166
1167
            // These are not user instructions.
1168
            Inst::Spill { .. }
1169
            | Inst::SpillF { .. }
1170
            | Inst::Reload { .. }
1171
            | Inst::ReloadF { .. } => {
1172
                panic!("unexpected spill/spillf/reload/reloadf in type_checks")
1173
            }
1174
        }
1175
    }
1176
}
1177
1178
//=============================================================================
1179
// The interpreter
1180
1181
#[derive(Copy, Clone)]
1182
pub enum Value {
1183
    U32(u32),
1184
    F32(f32),
1185
    Ref(u32),
1186
}
1187
1188
impl PartialEq for Value {
1189
0
    fn eq(&self, other: &Self) -> bool {
1190
0
        match self {
1191
0
            Value::U32(x) => match other {
1192
0
                Value::U32(y) => x == y,
1193
0
                _ => false,
1194
            },
1195
1196
0
            Value::F32(x) => match other {
1197
0
                Value::F32(y) => (x.is_nan() && y.is_nan()) || x == y,
1198
0
                _ => false,
1199
            },
1200
1201
0
            Value::Ref(x) => match other {
1202
0
                Value::Ref(y) => x == y,
1203
0
                _ => false,
1204
            },
1205
        }
1206
0
    }
1207
}
1208
1209
impl Value {
1210
0
    fn to_u32(self) -> u32 {
1211
0
        match self {
1212
0
            Value::U32(n) => n,
1213
0
            Value::F32(_) => panic!("Value::toU32: this is a F32"),
1214
0
            Value::Ref(_) => panic!("Value::toU32: this is a ref"),
1215
        }
1216
0
    }
1217
0
    fn to_f32(self) -> f32 {
1218
0
        match self {
1219
0
            Value::U32(_) => panic!("Value::toF32: this is a U32"),
1220
0
            Value::Ref(_) => panic!("Value::toF32: this is a ref"),
1221
0
            Value::F32(n) => n,
1222
0
        }
1223
0
    }
1224
0
    fn to_ref(self) -> u32 {
1225
0
        match self {
1226
0
            Value::Ref(n) => n,
1227
0
            _ => panic!("Value::to_ref: this is not a ref"),
1228
        }
1229
0
    }
1230
0
    fn cast_to_u32(self) -> u32 {
1231
0
        match self {
1232
0
            Value::U32(n) => n,
1233
0
            Value::F32(f) => f as u32,
1234
0
            Value::Ref(n) => n,
1235
        }
1236
0
    }
1237
0
    fn cast_to_f32(self) -> f32 {
1238
0
        match self {
1239
0
            Value::U32(n) => n as f32,
1240
0
            Value::F32(f) => f,
1241
0
            Value::Ref(n) => n as f32,
1242
        }
1243
0
    }
1244
}
1245
1246
impl fmt::Debug for Value {
1247
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1248
0
        match self {
1249
0
            Value::U32(n) => write!(fmt, "{}", n),
1250
0
            Value::F32(n) => write!(fmt, "{}", n),
1251
0
            Value::Ref(n) => write!(fmt, "@{}", n),
1252
        }
1253
0
    }
1254
}
1255
1256
#[derive(PartialEq)]
1257
pub enum RunStage {
1258
    BeforeRegalloc,
1259
    AfterRegalloc,
1260
}
1261
1262
struct IState<'a> {
1263
    func: &'a Func,
1264
    nia: InstIx,               // Program counter ("next instruction address")
1265
    vregs: Vec<Option<Value>>, // unlimited
1266
    rregs: Vec<Option<Value>>, // [0 .. maxRealRegs)
1267
    mem: Vec<Option<Value>>,   // [0 .. maxMem)
1268
    slots: Vec<Option<Value>>, // [0..] Spill slots, no upper limit
1269
    num_insts: usize,          // Stats: number of insns executed
1270
    num_spills: usize,         // Stats: .. of which are spills
1271
    num_reloads: usize,        // Stats: .. of which are reloads
1272
    run_stage: RunStage,
1273
    ret_value: Option<Value>,
1274
    stdout: String, // Everything that's printed out.
1275
}
1276
1277
type IResult<T> = Result<T, String>;
1278
1279
impl<'a> IState<'a> {
1280
    fn new(func: &'a Func, max_real_regs: usize, max_mem: usize, run_stage: RunStage) -> Self {
1281
        let mut state = IState {
1282
            func,
1283
            nia: func.blocks[func
1284
                .entry
1285
                .as_ref()
1286
                .expect("missing entry block")
1287
                .get_block_ix()]
1288
            .start,
1289
            vregs: Vec::new(),
1290
            rregs: Vec::new(),
1291
            mem: Vec::new(),
1292
            slots: Vec::new(),
1293
            num_insts: 0,
1294
            num_spills: 0,
1295
            num_reloads: 0,
1296
            run_stage,
1297
            ret_value: None,
1298
            stdout: String::new(),
1299
        };
1300
        state.rregs.resize(max_real_regs, None);
1301
        state.mem.resize(max_mem, None);
1302
        state
1303
    }
1304
1305
0
    fn get_real_reg(&self, rreg: RealReg) -> IResult<Value> {
1306
        // No automatic resizing.  If the rreg doesn't exist, just fail.
1307
0
        match self.rregs.get(rreg.get_index()) {
1308
0
            None => panic!("IState::get_real_reg: invalid rreg {:?}", rreg),
1309
0
            Some(None) => {
1310
0
                return Err(format!(
1311
0
                    "IState::get_real_reg: read of uninit rreg {:?} at nia {:?}",
1312
0
                    rreg, self.nia
1313
0
                ))?
1314
            }
1315
0
            Some(Some(val)) => Ok(*val),
1316
        }
1317
0
    }
1318
1319
0
    fn set_real_reg(&mut self, rreg: RealReg, val: Value) {
1320
        // No automatic resizing.  If the rreg doesn't exist, just fail.
1321
0
        match self.rregs.get_mut(rreg.get_index()) {
1322
0
            None => panic!("IState::setRealReg: invalid rreg {:?}", rreg),
1323
0
            Some(val_p) => *val_p = Some(val),
1324
0
        }
1325
0
    }
1326
1327
    fn get_virtual_reg(&self, vreg: VirtualReg) -> IResult<Value> {
1328
        debug_assert!(
1329
            self.run_stage != RunStage::AfterRegalloc,
1330
            "trying to get a vreg after regalloc"
1331
        );
1332
        // The vector might be too small.  But in that case we'd be
1333
        // reading the vreg uninitialised anyway, so just complain.
1334
        match self.vregs.get(vreg.get_index()) {
1335
            None | Some(None) => {
1336
                // entry either present or absent, but has never been written in both
1337
                // cases.
1338
                return Err(format!(
1339
                    "IState::get_virtual_reg: read of uninit vreg {:?}",
1340
                    vreg
1341
                ))?;
1342
            }
1343
            Some(Some(val)) => Ok(*val),
1344
        }
1345
    }
1346
1347
    fn set_virtual_reg(&mut self, vreg: VirtualReg, val: Value) {
1348
        debug_assert!(
1349
            self.run_stage != RunStage::AfterRegalloc,
1350
            "trying to set a vreg after regalloc"
1351
        );
1352
        // Auto-resize the vector if necessary
1353
        let ix = vreg.get_index();
1354
        if ix >= self.vregs.len() {
1355
            self.vregs.resize(ix + 1, None);
1356
        }
1357
        debug_assert!(ix < self.vregs.len());
1358
        self.vregs[ix] = Some(val);
1359
    }
1360
1361
0
    fn get_spill_slot(&self, slot: SpillSlot) -> Value {
1362
        // The vector might be too small.  But in that case we'd be
1363
        // reading the slot uninitialised anyway, so just complain.
1364
0
        match self.slots.get(slot.get_usize()) {
1365
0
            None |          // indexing error
1366
0
            Some(None) =>   // entry present, but has never been written
1367
0
                panic!("IState::getSpillSlot: read of uninit slot # {}",
1368
0
                       slot.get()),
1369
0
            Some(Some(val))
1370
0
                => *val
1371
0
        }
1372
0
    }
1373
1374
    fn set_spill_slot_u32(&mut self, slot: SpillSlot, val: Value) {
1375
        // Auto-resize the vector if necessary
1376
        let ix = slot.get_usize();
1377
        if ix >= self.slots.len() {
1378
            self.slots.resize(ix + 1, None);
1379
        }
1380
        debug_assert!(ix < self.slots.len());
1381
        debug_assert!(matches!(val, Value::Ref(_) | Value::U32(_)));
1382
        self.slots[ix] = Some(val);
1383
    }
1384
1385
0
    fn set_spill_slot_f32(&mut self, slot: SpillSlot, val: f32) {
1386
        // Auto-resize the vector if necessary
1387
0
        let ix = slot.get_usize();
1388
0
        if ix >= self.slots.len() {
1389
0
            self.slots.resize(ix + 1, None);
1390
0
        }
1391
        debug_assert!(ix < self.slots.len());
1392
0
        self.slots[ix] = Some(Value::F32(val));
1393
0
    }
1394
1395
0
    fn get_reg(&self, reg: Reg) -> IResult<Value> {
1396
0
        if reg.is_virtual() {
1397
0
            self.get_virtual_reg(reg.to_virtual_reg())
1398
        } else {
1399
0
            self.get_real_reg(reg.to_real_reg())
1400
        }
1401
0
    }
1402
1403
    fn set_reg_u32(&mut self, reg: Reg, val: u32) {
1404
        self.set_reg(reg, Value::U32(val))
1405
    }
1406
1407
    fn set_reg_f32(&mut self, reg: Reg, val: f32) {
1408
        self.set_reg(reg, Value::F32(val))
1409
    }
1410
1411
    fn set_reg_ref(&mut self, reg: Reg, val: u32) {
1412
        self.set_reg(reg, Value::Ref(val))
1413
    }
1414
1415
0
    fn set_reg(&mut self, reg: Reg, val: Value) {
1416
0
        if reg.is_virtual() {
1417
0
            self.set_virtual_reg(reg.to_virtual_reg(), val);
1418
0
        } else {
1419
0
            self.set_real_reg(reg.to_real_reg(), val);
1420
0
        }
1421
0
    }
1422
1423
0
    fn get_mem(&self, addr: u32) -> IResult<Value> {
1424
        // No auto resizing of the memory.
1425
0
        Ok(match self.mem.get(addr as usize) {
1426
0
            None => return Err(format!("IState::getMem: invalid addr {}", addr))?,
1427
0
            Some(None) => {
1428
0
                return Err(format!(
1429
0
                    "IState::getMem: read of uninit mem at addr {}",
1430
0
                    addr
1431
0
                ))?
1432
            }
1433
0
            Some(Some(val)) => *val,
1434
        })
1435
0
    }
1436
1437
0
    fn set_mem_u32(&mut self, addr: u32, val: u32) -> IResult<()> {
1438
0
        // No auto resizing of the memory
1439
0
        match self.mem.get_mut(addr as usize) {
1440
0
            None => return Err(format!("IState::set_mem_u32: invalid addr {}", addr))?,
1441
0
            Some(val_p) => *val_p = Some(Value::U32(val)),
1442
0
        }
1443
0
        Ok(())
1444
0
    }
1445
1446
0
    fn set_mem_f32(&mut self, addr: u32, val: f32) -> IResult<()> {
1447
0
        // No auto resizing of the memory
1448
0
        match self.mem.get_mut(addr as usize) {
1449
0
            None => return Err(format!("IState::set_mem_f32: invalid addr {}", addr))?,
1450
0
            Some(val_p) => *val_p = Some(Value::F32(val)),
1451
0
        }
1452
0
        Ok(())
1453
0
    }
1454
1455
    #[allow(non_snake_case)]
1456
0
    fn get_RI(&self, ri: &RI) -> IResult<u32> {
1457
0
        Ok(match ri {
1458
0
            RI::Reg { reg } => self.get_reg(*reg)?.to_u32(),
1459
0
            RI::Imm { imm } => *imm,
1460
        })
1461
0
    }
1462
1463
    #[allow(non_snake_case)]
1464
0
    fn get_AM(&self, am: &AM) -> IResult<u32> {
1465
        // Base + offset can overflow and wraparound, because why not?
1466
0
        Ok(match am {
1467
0
            AM::RI { base, offset } => self.get_reg(*base)?.to_u32().wrapping_add(*offset),
1468
0
            AM::RR { base, offset } => self
1469
0
                .get_reg(*base)?
1470
                .to_u32()
1471
0
                .wrapping_add(self.get_reg(*offset)?.to_u32()),
1472
        })
1473
0
    }
1474
1475
    // Move the interpreter one step forward
1476
0
    fn step(&mut self) -> IResult<bool> {
1477
0
        let mut done = false;
1478
0
1479
0
        let iix = self.nia;
1480
0
        self.nia = iix.plus(1);
1481
0
        self.num_insts += 1;
1482
0
1483
0
        let insn = &self.func.insns[iix];
1484
0
        match insn {
1485
0
            Inst::NopZ {} => {
1486
0
                self.num_insts -= 1;
1487
0
            }
1488
0
            Inst::Imm { dst, imm } => self.set_reg_u32(*dst, *imm),
1489
0
            Inst::ImmF { dst, imm } => self.set_reg_f32(*dst, *imm),
1490
0
            Inst::Copy { dst, src } => self.set_reg(*dst, self.get_reg(*src)?),
1491
0
            Inst::CopyF { dst, src } => self.set_reg_f32(*dst, self.get_reg(*src)?.to_f32()),
1492
            Inst::BinOp {
1493
0
                op,
1494
0
                dst,
1495
0
                src_left,
1496
0
                src_right,
1497
            } => {
1498
0
                let src_left_v = self.get_reg(*src_left)?.to_u32();
1499
0
                let src_right_v = self.get_RI(src_right)?;
1500
0
                let dst_v = op.calc(src_left_v, src_right_v)?;
1501
0
                self.set_reg_u32(*dst, dst_v);
1502
            }
1503
0
            Inst::BinOpM { op, dst, src_right } => {
1504
0
                let mut dst_v = self.get_reg(*dst)?.to_u32();
1505
0
                let src_right_v = self.get_RI(src_right)?;
1506
0
                dst_v = op.calc(dst_v, src_right_v)?;
1507
0
                self.set_reg_u32(*dst, dst_v);
1508
            }
1509
            Inst::BinOpF {
1510
0
                op,
1511
0
                dst,
1512
0
                src_left,
1513
0
                src_right,
1514
            } => {
1515
0
                let src_left_v = self.get_reg(*src_left)?.to_f32();
1516
0
                let src_right_v = self.get_reg(*src_right)?.to_f32();
1517
0
                let dst_v = op.calc(src_left_v, src_right_v)?;
1518
0
                self.set_reg_f32(*dst, dst_v);
1519
            }
1520
0
            Inst::MakeRef { dst, src } => {
1521
0
                let src_v = self.get_reg(*src)?.to_u32();
1522
0
                self.set_reg_ref(*dst, src_v);
1523
            }
1524
0
            Inst::UseRef { dst, src } => {
1525
0
                let src_v = self.get_reg(*src)?.to_ref();
1526
0
                self.set_reg_u32(*dst, src_v);
1527
            }
1528
0
            Inst::Safepoint => {}
1529
0
            Inst::Load { dst, addr } => {
1530
0
                let addr_v = self.get_AM(addr)?;
1531
0
                let dst_v = self.get_mem(addr_v)?.cast_to_u32();
1532
0
                self.set_reg_u32(*dst, dst_v);
1533
            }
1534
0
            Inst::LoadF { dst, addr } => {
1535
0
                let addr_v = self.get_AM(addr)?;
1536
0
                let dst_v = self.get_mem(addr_v)?.cast_to_f32();
1537
0
                self.set_reg_f32(*dst, dst_v);
1538
            }
1539
0
            Inst::Store { addr, src } => {
1540
0
                let addr_v = self.get_AM(addr)?;
1541
0
                let src_v = self.get_reg(*src)?.to_u32();
1542
0
                self.set_mem_u32(addr_v, src_v)?;
1543
            }
1544
0
            Inst::StoreF { addr, src } => {
1545
0
                let addr_v = self.get_AM(addr)?;
1546
0
                let src_v = self.get_reg(*src)?.to_f32();
1547
0
                self.set_mem_f32(addr_v, src_v)?;
1548
            }
1549
0
            Inst::Spill { dst, src } => {
1550
0
                let src_v = self.get_real_reg(*src)?;
1551
0
                self.set_spill_slot_u32(*dst, src_v);
1552
0
                self.num_spills += 1;
1553
            }
1554
0
            Inst::SpillF { dst, src } => {
1555
0
                let src_v = self.get_real_reg(*src)?.to_f32();
1556
0
                self.set_spill_slot_f32(*dst, src_v);
1557
0
                self.num_spills += 1;
1558
            }
1559
0
            Inst::Reload { dst, src } => {
1560
0
                let src_v = self.get_spill_slot(*src);
1561
0
                match src_v {
1562
0
                    Value::Ref(n) => self.set_reg_ref(dst.to_reg(), n),
1563
0
                    Value::U32(n) => self.set_reg_u32(dst.to_reg(), n),
1564
0
                    _ => panic!("must be a ref or u32"),
1565
                }
1566
0
                self.num_reloads += 1;
1567
            }
1568
0
            Inst::ReloadF { dst, src } => {
1569
0
                let src_v = self.get_spill_slot(*src).to_f32();
1570
0
                self.set_reg_f32(dst.to_reg(), src_v);
1571
0
                self.num_reloads += 1;
1572
0
            }
1573
0
            Inst::Goto { target } => self.nia = self.func.blocks[target.get_block_ix()].start,
1574
            Inst::GotoCTF {
1575
0
                cond,
1576
0
                target_true,
1577
0
                target_false,
1578
0
            } => {
1579
0
                let target = if self.get_reg(*cond)?.to_u32() != 0 {
1580
0
                    target_true
1581
                } else {
1582
0
                    target_false
1583
                };
1584
0
                self.nia = self.func.blocks[target.get_block_ix()].start;
1585
            }
1586
0
            Inst::PrintS { str } => {
1587
0
                self.stdout += str;
1588
0
                print!("{}", str);
1589
0
            }
1590
0
            Inst::PrintI { reg } => {
1591
0
                let str = format!("{:?}", self.get_reg(*reg)?.to_u32());
1592
0
                print!("{}", str);
1593
0
                self.stdout += &str;
1594
            }
1595
0
            Inst::PrintF { reg } => {
1596
0
                let str = format!("{:?}", self.get_reg(*reg)?.to_f32());
1597
0
                print!("{}", str);
1598
0
                self.stdout += &str;
1599
            }
1600
0
            Inst::Finish { reg } => {
1601
0
                self.ret_value = if let Some(reg) = *reg {
1602
0
                    Some(self.get_reg(reg)?)
1603
                } else {
1604
0
                    None
1605
                };
1606
0
                done = true;
1607
            }
1608
        }
1609
0
        Ok(done)
1610
0
    }
1611
}
1612
1613
/// Number of dynamic steps allowed in a test program. Useful to detect infinite
1614
/// loops during testing.
1615
const MAX_NUM_STEPS: u32 = 1000000;
1616
1617
#[derive(Debug)]
1618
pub struct RunResult {
1619
    /// Return value.
1620
    pub ret_value: Option<Value>,
1621
1622
    /// Number of dynamically executed steps.
1623
    pub num_steps: usize,
1624
1625
    /// Number of dynamically executed reload instructions.
1626
    pub num_reloads: usize,
1627
1628
    /// Everything that's been printed out.
1629
    pub stdout: String,
1630
}
1631
1632
0
pub fn run_func(
1633
0
    f: &Func,
1634
0
    who: &str,
1635
0
    reg_universe: &RealRegUniverse,
1636
0
    run_stage: RunStage,
1637
0
) -> Result<RunResult, String> {
1638
0
    println!("");
1639
0
    println!(
1640
0
        "Running stage '{}': Func: name='{}' entry='{:?}'",
1641
0
        who, f.name, f.entry
1642
0
    );
1643
0
1644
0
    if run_stage == RunStage::BeforeRegalloc {
1645
0
        if let Err(err) = validate(f, reg_universe) {
1646
0
            return Err(format!("validation error: {}", err));
1647
0
        }
1648
0
    }
1649
1650
0
    let mut istate = IState::new(
1651
0
        f,
1652
0
        reg_universe.regs.len(),
1653
0
        /* max_mem */ 1000,
1654
0
        run_stage,
1655
0
    );
1656
0
    let mut done = false;
1657
0
    let mut allowed_steps = MAX_NUM_STEPS;
1658
0
    while allowed_steps > 0 && !done {
1659
0
        done = istate.step()?;
1660
0
        allowed_steps -= 1;
1661
    }
1662
1663
0
    if allowed_steps == 0 {
1664
0
        return Err("too many dynamic steps. Maybe running an infinite loop?".into());
1665
0
    }
1666
0
1667
0
    println!(
1668
0
        "Running stage '{}': done.  {} insns, {} spills, {} reloads",
1669
0
        who, istate.num_insts, istate.num_spills, istate.num_reloads
1670
0
    );
1671
0
1672
0
    Ok(RunResult {
1673
0
        ret_value: istate.ret_value,
1674
0
        num_steps: istate.num_insts,
1675
0
        num_reloads: istate.num_reloads,
1676
0
        stdout: istate.stdout,
1677
0
    })
1678
0
}
1679
1680
//=============================================================================
1681
// Definition of Block and Func, and printing thereof.
1682
1683
21.8k
#[derive(Debug, Clone)]
1684
pub struct Block {
1685
    pub name: String,
1686
    pub start: InstIx,
1687
    pub len: u32,
1688
    pub estimated_execution_frequency: u16,
1689
}
1690
1691
impl Block {
1692
    pub fn new(name: String, start: InstIx, len: u32) -> Self {
1693
        Self {
1694
            name,
1695
            start,
1696
            len,
1697
            estimated_execution_frequency: 1,
1698
        }
1699
    }
1700
}
1701
1702
4.26k
#[derive(Debug, Clone)]
1703
pub struct Func {
1704
    pub name: String,
1705
    pub entry: Option<Label>,
1706
    pub num_virtual_regs: u32,
1707
    pub reftype_reg_start: Option<u32>, // all vregs >= this index are reftyped.
1708
    pub insns: TypedIxVec<InstIx, Inst>, // indexed by InstIx
1709
1710
    // Note that `blocks` must be in order of increasing `Block::start`
1711
    // fields.  Code that wants to traverse the blocks in some other order
1712
    // must represent the ordering some other way; rearranging Func::blocks is
1713
    // not allowed.
1714
    pub blocks: TypedIxVec<BlockIx, Block>, // indexed by BlockIx
1715
}
1716
1717
// Find a block Ix for a block name
1718
0
fn lookup(blocks: &TypedIxVec<BlockIx, Block>, name: String) -> BlockIx {
1719
0
    let mut bix = 0;
1720
0
    for b in blocks.iter() {
1721
0
        if b.name == name {
1722
0
            return BlockIx::new(bix);
1723
0
        }
1724
0
        bix += 1;
1725
    }
1726
0
    panic!("Func::lookup: can't resolve label name '{}'", name);
1727
0
}
1728
1729
impl Func {
1730
    pub fn new<'a>(name: &'a str) -> Self {
1731
        Func {
1732
            name: name.to_string(),
1733
            entry: None,
1734
            num_virtual_regs: 0,
1735
            reftype_reg_start: None,
1736
            insns: TypedIxVec::<InstIx, Inst>::new(),
1737
            blocks: TypedIxVec::<BlockIx, Block>::new(),
1738
        }
1739
    }
1740
1741
    pub fn set_entry(&mut self, entry: &str) {
1742
        self.entry = Some(Label::Unresolved {
1743
            name: entry.to_string(),
1744
        });
1745
    }
1746
1747
0
    pub fn print(&self, who: &str, mb_block_anns: &Option<TypedIxVec<BlockIx, Vec<String>>>) {
1748
0
        println!("");
1749
0
        println!(
1750
0
            "Func {}: name='{}' entry='{:?}' {{",
1751
0
            who, self.name, self.entry
1752
0
        );
1753
0
        let mut ix = 0;
1754
0
        for b in self.blocks.iter() {
1755
0
            if ix > 0 {
1756
0
                println!("");
1757
0
            }
1758
0
            println!("  {:?}:{}", BlockIx::new(ix), b.name);
1759
1760
0
            if let Some(anns_map) = mb_block_anns {
1761
0
                for ann in &anns_map[BlockIx::new(ix)] {
1762
0
                    println!("      ;; {}", ann);
1763
0
                }
1764
0
            }
1765
1766
0
            for i in b.start.get()..b.start.get() + b.len {
1767
0
                let ix = InstIx::new(i);
1768
0
                println!("      {:<3?}   {:?}", ix, self.insns[ix]);
1769
0
            }
1770
0
            ix += 1;
1771
        }
1772
0
        println!("}}");
1773
0
    }
1774
1775
    /// Prints the function in a way the parser can comprehend. This is used by
1776
    /// the fuzzer, but not otherwise, so allow dead code here.
1777
    #[allow(dead_code)]
1778
0
    pub fn render(&self, who: &str, fmt: &mut String) -> fmt::Result {
1779
        use std::fmt::Write;
1780
        use std::iter::FromIterator;
1781
1782
0
        let mut used_vregs = HashSet::new();
1783
0
        let mut used_rregs = HashSet::new();
1784
1785
0
        for b in self.blocks.iter() {
1786
0
            for i in b.start.get()..b.start.get() + b.len {
1787
0
                let iix = InstIx::new(i);
1788
0
1789
0
                // Get the use, def and mod sets for `self.insns[iix]`.  This is a bit
1790
0
                // awkward since we don't have the library's internal convenience
1791
0
                // functions available here.
1792
0
                let mut ru_vecs = RegUsageCollector::get_empty_reg_vecs_test_framework_only(false);
1793
0
                let mut ru_collector = RegUsageCollector::new(&mut ru_vecs);
1794
0
1795
0
                self.insns[iix].get_reg_usage(&mut ru_collector);
1796
0
                assert!(!ru_collector.reg_vecs.is_sanitized());
1797
1798
0
                let (used_vec, defined_vec, modified_vec) =
1799
0
                    ru_collector.get_use_def_mod_vecs_test_framework_only();
1800
0
                let used = Set::from_vec(used_vec);
1801
0
                let defined = Set::from_vec(defined_vec);
1802
0
                let modified = Set::from_vec(modified_vec);
1803
1804
0
                for &reg in defined.iter().chain(modified.iter()) {
1805
0
                    if reg.is_virtual() {
1806
0
                        used_vregs.insert(reg);
1807
0
                    } else {
1808
0
                        used_rregs.insert(reg);
1809
0
                    }
1810
                }
1811
0
                for &reg in used.iter() {
1812
0
                    if reg.is_virtual() {
1813
0
                        used_vregs.insert(reg);
1814
0
                    } else {
1815
0
                        used_rregs.insert(reg);
1816
0
                    }
1817
                }
1818
            }
1819
        }
1820
1821
0
        let mut used_vregs = Vec::from_iter(used_vregs.into_iter());
1822
0
        used_vregs.sort();
1823
0
        let mut used_rregs = Vec::from_iter(used_rregs.into_iter());
1824
0
        used_rregs.sort();
1825
1826
0
        writeln!(fmt, "; {}", who)?;
1827
0
        if let Some(start) = self.reftype_reg_start {
1828
0
            writeln!(fmt, "{} = {}", REFTYPE_START, start)?;
1829
0
        }
1830
0
        for vreg in used_vregs {
1831
0
            writeln!(fmt, "{:?} = {:?}", vreg, vreg.get_class())?;
1832
        }
1833
0
        for rreg in used_rregs {
1834
0
            writeln!(
1835
0
                fmt,
1836
0
                "{:?} = real {:?} {:?}",
1837
0
                rreg,
1838
0
                rreg.get_class(),
1839
0
                rreg.get_index()
1840
0
            )?;
1841
        }
1842
0
        writeln!(fmt, "")?;
1843
1844
0
        let mut ix = 0;
1845
0
        for b in self.blocks.iter() {
1846
0
            if ix > 0 {
1847
0
                writeln!(fmt, "")?;
1848
0
            }
1849
0
            writeln!(fmt, "{:?}:", BlockIx::new(ix))?;
1850
0
            for i in b.start.get()..b.start.get() + b.len {
1851
0
                let ix = InstIx::new(i);
1852
0
                writeln!(fmt, "    {:?}", self.insns[ix])?;
1853
            }
1854
0
            ix += 1;
1855
        }
1856
0
        writeln!(fmt, "")?;
1857
1858
0
        Ok(())
1859
0
    }
1860
1861
    // Get a new VirtualReg name
1862
    pub fn new_virtual_reg(&mut self, rc: RegClass) -> Reg {
1863
        let v = Reg::new_virtual(rc, self.num_virtual_regs);
1864
        self.num_virtual_regs += 1;
1865
        v
1866
    }
1867
1868
    // Add a block to the Func
1869
    pub fn block<'a>(&mut self, name: &'a str, insns: Vec<Inst>) {
1870
        let mut insns = TypedIxVec::from_vec(insns);
1871
        let start = self.insns.len();
1872
        let len = insns.len() as u32;
1873
        self.insns.append(&mut insns);
1874
        let b = Block::new(name.to_string(), InstIx::new(start), len);
1875
        self.blocks.push(b);
1876
    }
1877
1878
    // All blocks have been added.  Resolve labels and we're good to go.
1879
    /* .finish(): check
1880
          - all blocks nonempty
1881
          - all blocks end in i_finish, i_goto or i_goto_ctf
1882
          - no blocks have those insns before the end
1883
          - blocks are in increasing order of ::start fields
1884
          - all referenced blocks actually exist
1885
          - convert references to block numbers
1886
    */
1887
0
    pub fn finish(&mut self) {
1888
0
        for bix in BlockIx::new(0).dotdot(BlockIx::new(self.blocks.len())) {
1889
0
            let b = &self.blocks[bix];
1890
0
            if b.len == 0 {
1891
0
                panic!("Func::done: a block is empty");
1892
0
            }
1893
0
            if bix > BlockIx::new(0) && self.blocks[bix.minus(1)].start >= self.blocks[bix].start {
1894
0
                panic!("Func: blocks are not in increasing order of InstIx");
1895
0
            }
1896
0
            for i in 0..b.len {
1897
0
                let iix = b.start.plus(i);
1898
0
                if i == b.len - 1 && !self.insns[iix].is_control_flow() {
1899
0
                    panic!("Func: block must end in control flow insn");
1900
0
                }
1901
0
                if i != b.len - 1 && self.insns[iix].is_control_flow() {
1902
0
                    panic!("Func: block contains control flow insn not at end");
1903
0
                }
1904
            }
1905
        }
1906
1907
        // Resolve all labels
1908
0
        let blocks = &self.blocks;
1909
0
        for i in self.insns.iter_mut() {
1910
0
            resolve_inst(i, |name| lookup(blocks, name));
1911
0
        }
1912
0
        resolve_label(self.entry.as_mut().unwrap(), |name| lookup(blocks, name));
1913
0
    }
1914
1915
3.40k
    pub fn update_from_alloc(&mut self, result: regalloc::RegAllocResult<Func>) {
1916
3.40k
        self.insns = TypedIxVec::from_vec(result.insns);
1917
3.40k
        let num_blocks = self.blocks.len();
1918
3.40k
        let mut i = 0;
1919
16.3k
        for bix in self.blocks.range() {
1920
16.3k
            let block = &mut self.blocks[bix];
1921
16.3k
            block.start = result.target_map[bix];
1922
16.3k
            block.len = if i + 1 < num_blocks {
1923
12.9k
                result.target_map[BlockIx::new(i + 1)].get()
1924
            } else {
1925
3.40k
                self.insns.len()
1926
16.3k
            } - block.start.get();
1927
16.3k
            i += 1;
1928
        }
1929
3.40k
    }
1930
1931
4.26k
    pub fn get_stackmap_request(&self) -> Option<StackmapRequestInfo> {
1932
4.26k
        self.reftype_reg_start.and_then(|reftype_reg_start| {
1933
4.26k
            if reftype_reg_start == self.num_virtual_regs {
1934
0
                None
1935
            } else {
1936
4.26k
                let reftyped_vregs = (reftype_reg_start..self.num_virtual_regs)
1937
29.3k
                    .map(|index| Reg::new_virtual(RegClass::I32, index).to_virtual_reg())
1938
4.26k
                    .collect::<Vec<_>>();
1939
4.26k
                let mut safepoint_insns = vec![];
1940
123k
                for iix in self.insns.range() {
1941
123k
                    match self.insns[iix] {
1942
14.7k
                        Inst::Safepoint => {
1943
14.7k
                            safepoint_insns.push(iix);
1944
14.7k
                        }
1945
108k
                        _ => {}
1946
                    }
1947
                }
1948
                debug!(
1949
0
                    "SRI: reftyped_vregs = {:?}, safepoint_insns = {:?}",
1950
0
                    reftyped_vregs, safepoint_insns
1951
                );
1952
4.26k
                Some(StackmapRequestInfo {
1953
4.26k
                    reftype_class: RegClass::I32,
1954
4.26k
                    reftyped_vregs,
1955
4.26k
                    safepoint_insns,
1956
4.26k
                })
1957
            }
1958
4.26k
        })
1959
4.26k
    }
1960
}
1961
1962
0
fn resolve_label<F>(label: &mut Label, lookup: F)
1963
0
where
1964
0
    F: Fn(String) -> BlockIx,
1965
0
{
1966
0
    let resolved = match label {
1967
0
        Label::Unresolved { name } => Label::Resolved {
1968
0
            name: name.clone(),
1969
0
            bix: lookup(name.clone()),
1970
0
        },
1971
0
        Label::Resolved { .. } => panic!("resolveLabel: is already resolved!"),
1972
    };
1973
0
    *label = resolved;
1974
0
}
Unexecuted instantiation: minira::test_framework::resolve_label::<<minira::test_framework::Func>::finish::{closure#0}>
Unexecuted instantiation: minira::test_framework::resolve_label::<<minira::test_framework::Func>::finish::{closure#1}>
1975
1976
0
fn resolve_inst<F>(insn: &mut Inst, lookup: F)
1977
0
where
1978
0
    F: Copy + Fn(String) -> BlockIx,
1979
0
{
1980
0
    match insn {
1981
0
        Inst::Goto { ref mut target } => resolve_label(target, lookup),
1982
        Inst::GotoCTF {
1983
            cond: _,
1984
0
            ref mut target_true,
1985
0
            ref mut target_false,
1986
0
        } => {
1987
0
            resolve_label(target_true, lookup);
1988
0
            resolve_label(target_false, lookup);
1989
0
        }
1990
0
        _ => (),
1991
    }
1992
0
}
1993
1994
pub enum Stmt {
1995
    Vanilla {
1996
        insn: Inst,
1997
    },
1998
    IfThenElse {
1999
        cond: Reg,
2000
        stmts_t: Vec<Stmt>,
2001
        stmts_e: Vec<Stmt>,
2002
    },
2003
    RepeatUntil {
2004
        stmts: Vec<Stmt>,
2005
        cond: Reg,
2006
    },
2007
    WhileDo {
2008
        cond: Reg,
2009
        stmts: Vec<Stmt>,
2010
    },
2011
}
2012
2013
// Various handy wrappers, mostly wrappings of i_* functions
2014
pub fn s_if_then_else(cond: Reg, stmts_t: Vec<Stmt>, stmts_e: Vec<Stmt>) -> Stmt {
2015
    Stmt::IfThenElse {
2016
        cond,
2017
        stmts_t,
2018
        stmts_e,
2019
    }
2020
}
2021
pub fn s_if_then(cond: Reg, stmts_t: Vec<Stmt>) -> Stmt {
2022
    Stmt::IfThenElse {
2023
        cond,
2024
        stmts_t,
2025
        stmts_e: vec![],
2026
    }
2027
}
2028
pub fn s_repeat_until(stmts: Vec<Stmt>, cond: Reg) -> Stmt {
2029
    Stmt::RepeatUntil { stmts, cond }
2030
}
2031
pub fn s_while_do(cond: Reg, stmts: Vec<Stmt>) -> Stmt {
2032
    Stmt::WhileDo { cond, stmts }
2033
}
2034
2035
fn s_vanilla(insn: Inst) -> Stmt {
2036
    Stmt::Vanilla { insn }
2037
}
2038
2039
pub fn s_imm(dst: Reg, imm: u32) -> Stmt {
2040
    s_vanilla(i_imm(dst, imm))
2041
}
2042
pub fn s_immf(dst: Reg, imm: f32) -> Stmt {
2043
    s_vanilla(i_immf(dst, imm))
2044
}
2045
pub fn s_copy(dst: Reg, src: Reg) -> Stmt {
2046
    s_vanilla(i_copy(dst, src))
2047
}
2048
pub fn s_load(dst: Reg, addr: AM) -> Stmt {
2049
    s_vanilla(i_load(dst, addr))
2050
}
2051
pub fn s_loadf(dst: Reg, addr: AM) -> Stmt {
2052
    s_vanilla(i_loadf(dst, addr))
2053
}
2054
pub fn s_store(addr: AM, src: Reg) -> Stmt {
2055
    s_vanilla(i_store(addr, src))
2056
}
2057
pub fn s_storef(addr: AM, src: Reg) -> Stmt {
2058
    s_vanilla(i_storef(addr, src))
2059
}
2060
pub fn s_print_s<'a>(str: &'a str) -> Stmt {
2061
    s_vanilla(i_print_s(str))
2062
}
2063
pub fn s_print_i(reg: Reg) -> Stmt {
2064
    s_vanilla(i_print_i(reg))
2065
}
2066
pub fn s_print_f(reg: Reg) -> Stmt {
2067
    s_vanilla(i_print_f(reg))
2068
}
2069
2070
pub fn s_add(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2071
    s_vanilla(i_add(dst, src_left, src_right))
2072
}
2073
pub fn s_sub(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2074
    s_vanilla(i_sub(dst, src_left, src_right))
2075
}
2076
pub fn s_mul(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2077
    s_vanilla(i_mul(dst, src_left, src_right))
2078
}
2079
pub fn s_mod(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2080
    s_vanilla(i_mod(dst, src_left, src_right))
2081
}
2082
pub fn s_shr(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2083
    s_vanilla(i_shr(dst, src_left, src_right))
2084
}
2085
pub fn s_and(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2086
    s_vanilla(i_and(dst, src_left, src_right))
2087
}
2088
pub fn s_cmp_eq(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2089
    s_vanilla(i_cmp_eq(dst, src_left, src_right))
2090
}
2091
pub fn s_cmp_lt(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2092
    s_vanilla(i_cmp_lt(dst, src_left, src_right))
2093
}
2094
pub fn s_cmp_le(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2095
    s_vanilla(i_cmp_le(dst, src_left, src_right))
2096
}
2097
pub fn s_cmp_ge(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2098
    s_vanilla(i_cmp_ge(dst, src_left, src_right))
2099
}
2100
pub fn s_cmp_gt(dst: Reg, src_left: Reg, src_right: RI) -> Stmt {
2101
    s_vanilla(i_cmp_gt(dst, src_left, src_right))
2102
}
2103
2104
pub fn s_addm(dst: Reg, src_right: RI) -> Stmt {
2105
    s_vanilla(i_addm(dst, src_right))
2106
}
2107
//fn s_subm(dst: Reg, src_right: RI) -> Stmt {
2108
//  s_vanilla(i_subm(dst, src_right))
2109
//}
2110
2111
pub fn s_fadd(dst: Reg, src_left: Reg, src_right: Reg) -> Stmt {
2112
    s_vanilla(i_fadd(dst, src_left, src_right))
2113
}
2114
pub fn s_fsub(dst: Reg, src_left: Reg, src_right: Reg) -> Stmt {
2115
    s_vanilla(i_fsub(dst, src_left, src_right))
2116
}
2117
pub fn s_fmul(dst: Reg, src_left: Reg, src_right: Reg) -> Stmt {
2118
    s_vanilla(i_fmul(dst, src_left, src_right))
2119
}
2120
pub fn s_fdiv(dst: Reg, src_left: Reg, src_right: Reg) -> Stmt {
2121
    s_vanilla(i_fdiv(dst, src_left, src_right))
2122
}
2123
2124
//=============================================================================
2125
// The "blockifier".  This is just to make it easier to write test cases, by
2126
// allowing direct use of if-then-else, do-while and repeat-until.  It is
2127
// otherwise entirely unrelated to the register allocator proper.
2128
2129
pub struct Blockifier {
2130
    name: String,
2131
    blocks: Vec<Vec<Inst>>,
2132
    num_virtual_regs: u32,
2133
}
2134
2135
fn make_text_label_str(n: usize) -> String {
2136
    "L".to_string() + &n.to_string()
2137
}
2138
2139
impl Blockifier {
2140
    pub fn new<'a>(name: &'a str) -> Self {
2141
        Self {
2142
            name: name.to_string(),
2143
            blocks: vec![],
2144
            num_virtual_regs: 0,
2145
        }
2146
    }
2147
2148
    // Get a new VirtualReg name
2149
    pub fn new_virtual_reg(&mut self, rc: RegClass) -> Reg {
2150
        let v = Reg::new_virtual(rc, self.num_virtual_regs);
2151
        self.num_virtual_regs += 1;
2152
        v
2153
    }
2154
2155
    /// Recursive worker function, which flattens out the control flow, producing
2156
    /// a set of blocks.
2157
0
    fn blockify(&mut self, stmts: Vec<Stmt>) -> (usize, usize) {
2158
0
        let entry_block = self.blocks.len();
2159
0
        let mut cur_block = entry_block;
2160
0
        self.blocks.push(Vec::new());
2161
0
        for s in stmts {
2162
0
            match s {
2163
0
                Stmt::Vanilla { insn } => {
2164
0
                    self.blocks[cur_block].push(insn);
2165
0
                }
2166
                Stmt::IfThenElse {
2167
0
                    cond,
2168
0
                    stmts_t,
2169
0
                    stmts_e,
2170
0
                } => {
2171
0
                    let (t_ent, t_exit) = self.blockify(stmts_t);
2172
0
                    let (e_ent, e_exit) = self.blockify(stmts_e);
2173
0
                    let cont = self.blocks.len();
2174
0
                    self.blocks.push(Vec::new());
2175
0
                    self.blocks[t_exit].push(i_goto(&make_text_label_str(cont)));
2176
0
                    self.blocks[e_exit].push(i_goto(&make_text_label_str(cont)));
2177
0
                    self.blocks[cur_block].push(i_goto_ctf(
2178
0
                        cond,
2179
0
                        &make_text_label_str(t_ent),
2180
0
                        &make_text_label_str(e_ent),
2181
0
                    ));
2182
0
                    cur_block = cont;
2183
0
                }
2184
0
                Stmt::RepeatUntil { stmts, cond } => {
2185
0
                    let (s_ent, s_exit) = self.blockify(stmts);
2186
0
2187
0
                    // Don't create critical edges by creating the following loop
2188
0
                    // structure:
2189
0
                    //
2190
0
                    // current -> loop_header -> s_ent -> s_exit -> after_loop
2191
0
                    //            ^                       |
2192
0
                    //            |-------- loop_continue <
2193
0
2194
0
                    let loop_header = self.blocks.len();
2195
0
                    self.blocks.push(vec![i_goto(&make_text_label_str(s_ent))]);
2196
0
2197
0
                    self.blocks[cur_block].push(i_goto(&make_text_label_str(loop_header)));
2198
0
2199
0
                    let loop_continue = self.blocks.len();
2200
0
                    self.blocks
2201
0
                        .push(vec![i_goto(&make_text_label_str(loop_header))]);
2202
0
2203
0
                    let after_loop = self.blocks.len();
2204
0
                    self.blocks.push(Vec::new());
2205
0
2206
0
                    self.blocks[s_exit].push(i_goto_ctf(
2207
0
                        cond,
2208
0
                        &make_text_label_str(after_loop),
2209
0
                        &make_text_label_str(loop_continue),
2210
0
                    ));
2211
0
2212
0
                    cur_block = after_loop;
2213
0
                }
2214
0
                Stmt::WhileDo { cond, stmts } => {
2215
0
                    let condblock = self.blocks.len();
2216
0
                    self.blocks.push(Vec::new());
2217
0
                    self.blocks[cur_block].push(i_goto(&make_text_label_str(condblock)));
2218
0
                    let (s_ent, s_exit) = self.blockify(stmts);
2219
0
                    self.blocks[s_exit].push(i_goto(&make_text_label_str(condblock)));
2220
0
                    let cont = self.blocks.len();
2221
0
                    self.blocks.push(Vec::new());
2222
0
                    self.blocks[condblock].push(i_goto_ctf(
2223
0
                        cond,
2224
0
                        &make_text_label_str(s_ent),
2225
0
                        &make_text_label_str(cont),
2226
0
                    ));
2227
0
                    cur_block = cont;
2228
0
                }
2229
            }
2230
        }
2231
0
        (entry_block, cur_block)
2232
0
    }
2233
2234
    // The main external function.  Convert the given statements, into a Func.
2235
0
    pub fn finish(mut self, stmts: Vec<Stmt>, ret_value: Option<Reg>) -> Func {
2236
0
        let (ent_bno, exit_bno) = self.blockify(stmts);
2237
0
        self.blocks[exit_bno].push(i_finish(ret_value));
2238
0
2239
0
        // Convert (ent_bno, exit_bno, cleanedUp) into a Func
2240
0
        let mut func = Func::new(&self.name);
2241
0
        func.set_entry(&make_text_label_str(ent_bno));
2242
0
        func.num_virtual_regs = self.num_virtual_regs;
2243
0
        let mut n = 0;
2244
0
        for ivec in self.blocks {
2245
0
            func.block(&make_text_label_str(n), ivec);
2246
0
            n += 1;
2247
0
        }
2248
2249
0
        func.finish();
2250
0
        func
2251
0
    }
2252
}
2253
2254
// --------------------------------------------------
2255
// Implementation of `Function` trait for test cases.
2256
2257
impl regalloc::Function for Func {
2258
    type Inst = Inst;
2259
2260
33.0k
    fn insns(&self) -> &[Inst] {
2261
33.0k
        self.insns.elems()
2262
33.0k
    }
2263
2264
    fn insns_mut(&mut self) -> &mut [Inst] {
2265
        self.insns.elems_mut()
2266
    }
2267
2268
320k
    fn get_insn(&self, iix: InstIx) -> &Inst {
2269
320k
        &self.insns[iix]
2270
320k
    }
2271
2272
98.4k
    fn get_insn_mut(&mut self, iix: InstIx) -> &mut Inst {
2273
98.4k
        &mut self.insns[iix]
2274
98.4k
    }
2275
2276
18.5k
    fn entry_block(&self) -> BlockIx {
2277
18.5k
        BlockIx::new(0)
2278
18.5k
    }
2279
2280
58.4k
    fn blocks(&self) -> Range<BlockIx> {
2281
58.4k
        self.blocks.range()
2282
58.4k
    }
2283
2284
    /// Provide the range of instruction indices contained in each block.
2285
563k
    fn block_insns(&self, block: BlockIx) -> Range<InstIx> {
2286
563k
        Range::new(self.blocks[block].start, self.blocks[block].len as usize)
2287
563k
    }
2288
2289
    /// Get CFG successors: indexed by block, provide a list of successor blocks.
2290
38.2k
    fn block_succs(&self, block: BlockIx) -> Cow<[BlockIx]> {
2291
38.2k
        let last_insn = self.blocks[block].start.plus(self.blocks[block].len - 1);
2292
38.2k
        Cow::Owned(self.insns[last_insn].get_targets())
2293
38.2k
    }
2294
2295
16.7k
    fn is_ret(&self, insn: InstIx) -> bool {
2296
16.7k
        match &self.insns[insn] {
2297
682
            &Inst::Finish { .. } => true,
2298
16.0k
            _ => false,
2299
        }
2300
16.7k
    }
2301
2302
    /// Provide the defined, used, and modified registers for an instruction.
2303
328k
    fn get_regs(insn: &Self::Inst, collector: &mut RegUsageCollector) {
2304
328k
        insn.get_reg_usage(collector);
2305
328k
    }
2306
2307
    /// Map each register slot through a virt -> phys mapping indexed
2308
    /// by virtual register. The two separate maps provide the
2309
    /// mapping to use for uses (which semantically occur just prior
2310
    /// to the instruction's effect) and defs (which semantically occur
2311
    /// just after the instruction's effect). Regs that were "modified"
2312
    /// can use either map; the vreg should be the same in both.
2313
94.0k
    fn map_regs<RUM: RegUsageMapper>(insn: &mut Self::Inst, maps: &RUM) {
2314
94.0k
        insn.map_regs(maps);
2315
94.0k
    }
Unexecuted instantiation: minira::test_framework::i_print_f
2316
2317
    /// Allow the regalloc to query whether this is a move.
2318
127k
    fn is_move(&self, insn: &Self::Inst) -> Option<(Writable<Reg>, Reg)> {
2319
127k
        match insn {
2320
35.6k
            &Inst::Copy { dst, src } => Some((Writable::from_reg(dst), src)),
2321
91.9k
            _ => None,
2322
        }
2323
127k
    }
2324
2325
14.5k
    fn get_num_vregs(&self) -> usize {
2326
14.5k
        self.num_virtual_regs as usize
2327
14.5k
    }
2328
2329
    /// How many logical spill slots does the given regclass require?  E.g., on a
2330
    /// 64-bit machine, spill slots may nominally be 64-bit words, but a 128-bit
2331
    /// vector value will require two slots.  The regalloc will always align on
2332
    /// this size.
2333
4.89k
    fn get_spillslot_size(&self, _regclass: RegClass, _for_vreg: VirtualReg) -> u32 {
2334
4.89k
        // For our simple test ISA, every value occupies one spill slot.
2335
4.89k
        1
2336
4.89k
    }
2337
2338
    /// Generate a spill instruction for insertion into the instruction sequence.
2339
11.3k
    fn gen_spill(
2340
11.3k
        &self,
2341
11.3k
        to_slot: SpillSlot,
2342
11.3k
        from_reg: RealReg,
2343
11.3k
        _for_vreg: Option<VirtualReg>,
2344
11.3k
    ) -> Self::Inst {
2345
11.3k
        match from_reg.get_class() {
2346
11.2k
            RegClass::I32 => i_spill(to_slot, from_reg),
2347
102
            RegClass::F32 => i_spillf(to_slot, from_reg),
2348
0
            _ => panic!("Unused register class in test ISA was used"),
2349
        }
2350
11.3k
    }
2351
2352
    /// Generate a reload instruction for insertion into the instruction sequence.
2353
16.3k
    fn gen_reload(
2354
16.3k
        &self,
2355
16.3k
        to_reg: Writable<RealReg>,
2356
16.3k
        from_slot: SpillSlot,
2357
16.3k
        _for_vreg: Option<VirtualReg>,
2358
16.3k
    ) -> Self::Inst {
2359
16.3k
        match to_reg.to_reg().get_class() {
2360
16.0k
            RegClass::I32 => i_reload(to_reg.to_reg(), from_slot),
2361
288
            RegClass::F32 => i_reloadf(to_reg.to_reg(), from_slot),
2362
0
            _ => panic!("Unused register class in test ISA was used"),
2363
        }
2364
16.3k
    }
2365
2366
    /// Generate a register-to-register move for insertion into the instruction
2367
    /// sequence.
2368
0
    fn gen_move(
2369
0
        &self,
2370
0
        to_reg: Writable<RealReg>,
2371
0
        from_reg: RealReg,
2372
0
        _for_vreg: VirtualReg,
2373
0
    ) -> Self::Inst {
2374
0
        match to_reg.to_reg().get_class() {
2375
0
            RegClass::I32 => Inst::Copy {
2376
0
                src: from_reg.to_reg(),
2377
0
                dst: to_reg.to_reg().to_reg(),
2378
0
            },
2379
0
            RegClass::F32 => Inst::CopyF {
2380
0
                src: from_reg.to_reg(),
2381
0
                dst: to_reg.to_reg().to_reg(),
2382
0
            },
2383
0
            _ => unimplemented!("gen_move for non i32/f32"),
2384
        }
2385
0
    }
2386
2387
    /// Generate an instruction which is a no-op and has zero length.
2388
4.36k
    fn gen_zero_len_nop(&self) -> Self::Inst {
2389
4.36k
        Inst::NopZ {}
2390
4.36k
    }
2391
2392
    /// Try to alter an existing instruction to use a value directly in a
2393
    /// spillslot (accessing memory directly) instead of the given register. May
2394
    /// be useful on ISAs that have mem/reg ops, like x86.
2395
    ///
2396
    /// Note that this is not *quite* just fusing a load with the op; if the
2397
    /// value is def'd or modified, it should be written back to the spill slot
2398
    /// as well. In other words, it is just using the spillslot as if it were a
2399
    /// real register, for reads and/or writes.
2400
    fn maybe_direct_reload(
2401
        &self,
2402
        _insn: &Self::Inst,
2403
        _reg: VirtualReg,
2404
        _slot: SpillSlot,
2405
    ) -> Option<Self::Inst> {
2406
        // test ISA does not have register-memory ALU instruction forms.
2407
        None
2408
    }
2409
2410
3.64k
    fn func_liveins(&self) -> Set<RealReg> {
2411
3.64k
        Set::empty()
2412
3.64k
    }
2413
2414
3.45k
    fn func_liveouts(&self) -> Set<RealReg> {
2415
3.45k
        Set::empty()
2416
3.45k
    }
2417
}
2418
2419
/// Create a universe for testing, with nI32 `I32` class regs and nF32 `F32`
2420
/// class regs.
2421
4.26k
pub fn make_universe(num_i32: usize, num_f32: usize) -> RealRegUniverse {
2422
4.26k
    let total_regs = num_i32 + num_f32;
2423
4.26k
    if total_regs >= 256 {
2424
0
        panic!("make_universe: too many regs, cannot represent");
2425
4.26k
    }
2426
4.26k
2427
4.26k
    let mut regs = Vec::<(RealReg, String)>::new();
2428
4.26k
    let mut allocable_by_class = [None; NUM_REG_CLASSES];
2429
4.26k
    let mut index = 0u8;
2430
4.26k
2431
4.26k
    if num_i32 > 0 {
2432
4.26k
        let first = index as usize;
2433
17.0k
        for i in 0..num_i32 {
2434
17.0k
            let name = format!("R{}", i).to_string();
2435
17.0k
            let reg = Reg::new_real(RegClass::I32, /*enc=*/ 0, index).to_real_reg();
2436
17.0k
            regs.push((reg, name));
2437
17.0k
            index += 1;
2438
17.0k
        }
2439
4.26k
        let last = index as usize - 1;
2440
4.26k
        allocable_by_class[RegClass::I32.rc_to_usize()] = Some(RegClassInfo {
2441
4.26k
            first,
2442
4.26k
            last,
2443
4.26k
            suggested_scratch: Some(last),
2444
4.26k
        });
2445
0
    }
2446
2447
4.26k
    if num_f32 > 0 {
2448
4.26k
        let first = index as usize;
2449
17.0k
        for i in 0..num_f32 {
2450
17.0k
            let name = format!("F{}", i).to_string();
2451
17.0k
            let reg = Reg::new_real(RegClass::F32, /*enc=*/ 0, index).to_real_reg();
2452
17.0k
            regs.push((reg, name));
2453
17.0k
            index += 1;
2454
17.0k
        }
2455
4.26k
        let last = index as usize - 1;
2456
4.26k
        allocable_by_class[RegClass::F32.rc_to_usize()] = Some(RegClassInfo {
2457
4.26k
            first,
2458
4.26k
            last,
2459
4.26k
            suggested_scratch: Some(last),
2460
4.26k
        });
2461
0
    }
2462
2463
    debug_assert!(index as usize == total_regs);
2464
2465
4.26k
    let allocable = regs.len();
2466
4.26k
    let univ = RealRegUniverse {
2467
4.26k
        regs,
2468
4.26k
        // for this example, all regs are allocable
2469
4.26k
        allocable,
2470
4.26k
        allocable_by_class,
2471
4.26k
    };
2472
4.26k
    univ.check_is_sane();
2473
4.26k
2474
4.26k
    univ
2475
4.26k
}