Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/regalloc2-0.5.1/src/ion/liveranges.rs
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This file was initially derived from the files
3
 * `js/src/jit/BacktrackingAllocator.h` and
4
 * `js/src/jit/BacktrackingAllocator.cpp` in Mozilla Firefox, and was
5
 * originally licensed under the Mozilla Public License 2.0. We
6
 * subsequently relicensed it to Apache-2.0 WITH LLVM-exception (see
7
 * https://github.com/bytecodealliance/regalloc2/issues/7).
8
 *
9
 * Since the initial port, the design has been substantially evolved
10
 * and optimized.
11
 */
12
13
//! Live-range computation.
14
15
use super::{
16
    CodeRange, Env, InsertMovePrio, LiveBundle, LiveBundleIndex, LiveRange, LiveRangeFlag,
17
    LiveRangeIndex, LiveRangeKey, LiveRangeListEntry, LiveRangeSet, PRegData, PRegIndex, RegClass,
18
    SpillSetIndex, Use, VRegData, VRegIndex, SLOT_NONE,
19
};
20
use crate::indexset::IndexSet;
21
use crate::ion::data_structures::{
22
    BlockparamIn, BlockparamOut, FixedRegFixupLevel, MultiFixedRegFixup,
23
};
24
use crate::{
25
    Allocation, Block, Function, Inst, InstPosition, Operand, OperandConstraint, OperandKind,
26
    OperandPos, PReg, ProgPoint, RegAllocError, VReg,
27
};
28
use fxhash::{FxHashMap, FxHashSet};
29
use slice_group_by::GroupByMut;
30
use smallvec::{smallvec, SmallVec};
31
use std::collections::{HashSet, VecDeque};
32
33
/// A spill weight computed for a certain Use.
34
#[derive(Clone, Copy, Debug)]
35
pub struct SpillWeight(f32);
36
37
#[inline(always)]
38
2.86M
pub fn spill_weight_from_constraint(
39
2.86M
    constraint: OperandConstraint,
40
2.86M
    loop_depth: usize,
41
2.86M
    is_def: bool,
42
2.86M
) -> SpillWeight {
43
2.86M
    // A bonus of 1000 for one loop level, 4000 for two loop levels,
44
2.86M
    // 16000 for three loop levels, etc. Avoids exponentiation.
45
2.86M
    let loop_depth = std::cmp::min(10, loop_depth);
46
2.86M
    let hot_bonus: f32 = (0..loop_depth).fold(1000.0, |a, _| a * 4.0);
regalloc2::ion::liveranges::spill_weight_from_constraint::{closure#0}
Line
Count
Source
46
42.4k
    let hot_bonus: f32 = (0..loop_depth).fold(1000.0, |a, _| a * 4.0);
Unexecuted instantiation: regalloc2::ion::liveranges::spill_weight_from_constraint::{closure#0}
47
2.86M
    let def_bonus: f32 = if is_def { 2000.0 } else { 0.0 };
48
2.86M
    let constraint_bonus: f32 = match constraint {
49
43.2k
        OperandConstraint::Any => 1000.0,
50
2.71M
        OperandConstraint::Reg | OperandConstraint::FixedReg(_) => 2000.0,
51
100k
        _ => 0.0,
52
    };
53
2.86M
    SpillWeight(hot_bonus + def_bonus + constraint_bonus)
54
2.86M
}
55
56
impl SpillWeight {
57
    /// Convert a floating-point weight to a u16 that can be compactly
58
    /// stored in a `Use`. We simply take the top 16 bits of the f32; this
59
    /// is equivalent to the bfloat16 format
60
    /// (https://en.wikipedia.org/wiki/Bfloat16_floating-point_format).
61
2.15M
    pub fn to_bits(self) -> u16 {
62
2.15M
        (self.0.to_bits() >> 15) as u16
63
2.15M
    }
<regalloc2::ion::liveranges::SpillWeight>::to_bits
Line
Count
Source
61
2.15M
    pub fn to_bits(self) -> u16 {
62
2.15M
        (self.0.to_bits() >> 15) as u16
63
2.15M
    }
Unexecuted instantiation: <regalloc2::ion::liveranges::SpillWeight>::to_bits
64
65
    /// Convert a value that was returned from
66
    /// `SpillWeight::to_bits()` back into a `SpillWeight`. Note that
67
    /// some precision may be lost when round-tripping from a spill
68
    /// weight to packed bits and back.
69
537k
    pub fn from_bits(bits: u16) -> SpillWeight {
70
537k
        let x = f32::from_bits((bits as u32) << 15);
71
537k
        SpillWeight(x)
72
537k
    }
<regalloc2::ion::liveranges::SpillWeight>::from_bits
Line
Count
Source
69
537k
    pub fn from_bits(bits: u16) -> SpillWeight {
70
537k
        let x = f32::from_bits((bits as u32) << 15);
71
537k
        SpillWeight(x)
72
537k
    }
Unexecuted instantiation: <regalloc2::ion::liveranges::SpillWeight>::from_bits
73
74
    /// Get a zero spill weight.
75
875k
    pub fn zero() -> SpillWeight {
76
875k
        SpillWeight(0.0)
77
875k
    }
<regalloc2::ion::liveranges::SpillWeight>::zero
Line
Count
Source
75
875k
    pub fn zero() -> SpillWeight {
76
875k
        SpillWeight(0.0)
77
875k
    }
Unexecuted instantiation: <regalloc2::ion::liveranges::SpillWeight>::zero
78
79
    /// Convert to a raw floating-point value.
80
3.03M
    pub fn to_f32(self) -> f32 {
81
3.03M
        self.0
82
3.03M
    }
<regalloc2::ion::liveranges::SpillWeight>::to_f32
Line
Count
Source
80
3.03M
    pub fn to_f32(self) -> f32 {
81
3.03M
        self.0
82
3.03M
    }
Unexecuted instantiation: <regalloc2::ion::liveranges::SpillWeight>::to_f32
83
84
    /// Create a `SpillWeight` from a raw floating-point value.
85
3.05M
    pub fn from_f32(x: f32) -> SpillWeight {
86
3.05M
        SpillWeight(x)
87
3.05M
    }
<regalloc2::ion::liveranges::SpillWeight>::from_f32
Line
Count
Source
85
3.05M
    pub fn from_f32(x: f32) -> SpillWeight {
86
3.05M
        SpillWeight(x)
87
3.05M
    }
Unexecuted instantiation: <regalloc2::ion::liveranges::SpillWeight>::from_f32
88
89
703k
    pub fn to_int(self) -> u32 {
90
703k
        self.0 as u32
91
703k
    }
<regalloc2::ion::liveranges::SpillWeight>::to_int
Line
Count
Source
89
703k
    pub fn to_int(self) -> u32 {
90
703k
        self.0 as u32
91
703k
    }
Unexecuted instantiation: <regalloc2::ion::liveranges::SpillWeight>::to_int
92
}
93
94
impl std::ops::Add<SpillWeight> for SpillWeight {
95
    type Output = SpillWeight;
96
3.59M
    fn add(self, other: SpillWeight) -> Self {
97
3.59M
        SpillWeight(self.0 + other.0)
98
3.59M
    }
<regalloc2::ion::liveranges::SpillWeight as core::ops::arith::Add>::add
Line
Count
Source
96
3.59M
    fn add(self, other: SpillWeight) -> Self {
97
3.59M
        SpillWeight(self.0 + other.0)
98
3.59M
    }
Unexecuted instantiation: <regalloc2::ion::liveranges::SpillWeight as core::ops::arith::Add>::add
99
}
100
101
impl<'a, F: Function> Env<'a, F> {
102
139k
    pub fn create_pregs_and_vregs(&mut self) {
103
139k
        // Create PRegs from the env.
104
139k
        self.pregs.resize(
105
139k
            PReg::NUM_INDEX,
106
139k
            PRegData {
107
139k
                allocations: LiveRangeSet::new(),
108
139k
                is_stack: false,
109
139k
            },
110
139k
        );
111
139k
        for &preg in &self.env.fixed_stack_slots {
112
0
            self.pregs[preg.index()].is_stack = true;
113
0
        }
114
278k
        for class in 0..self.preferred_victim_by_class.len() {
115
278k
            self.preferred_victim_by_class[class] = self.env.non_preferred_regs_by_class[class]
116
278k
                .last()
117
278k
                .or(self.env.preferred_regs_by_class[class].last())
118
278k
                .cloned()
119
278k
                .unwrap_or(PReg::invalid());
120
278k
        }
121
        // Create VRegs from the vreg count.
122
19.7M
        for idx in 0..self.func.num_vregs() {
123
            // We'll fill in the real details when we see the def.
124
19.7M
            let reg = VReg::new(idx, RegClass::Int);
125
19.7M
            self.add_vreg(
126
19.7M
                reg,
127
19.7M
                VRegData {
128
19.7M
                    ranges: smallvec![],
129
19.7M
                    blockparam: Block::invalid(),
130
19.7M
                    is_ref: false,
131
19.7M
                    // We'll learn the RegClass as we scan the code.
132
19.7M
                    class: None,
133
                },
134
            );
135
        }
136
139k
        for v in self.func.reftype_vregs() {
137
0
            self.vregs[v.vreg()].is_ref = true;
138
0
        }
139
        // Create allocations too.
140
1.27M
        for inst in 0..self.func.num_insts() {
141
1.27M
            let start = self.allocs.len() as u32;
142
1.27M
            self.inst_alloc_offsets.push(start);
143
2.16M
            for _ in 0..self.func.inst_operands(Inst::new(inst)).len() {
144
2.16M
                self.allocs.push(Allocation::none());
145
2.16M
            }
146
        }
147
139k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::create_pregs_and_vregs
Line
Count
Source
102
139k
    pub fn create_pregs_and_vregs(&mut self) {
103
139k
        // Create PRegs from the env.
104
139k
        self.pregs.resize(
105
139k
            PReg::NUM_INDEX,
106
139k
            PRegData {
107
139k
                allocations: LiveRangeSet::new(),
108
139k
                is_stack: false,
109
139k
            },
110
139k
        );
111
139k
        for &preg in &self.env.fixed_stack_slots {
112
0
            self.pregs[preg.index()].is_stack = true;
113
0
        }
114
278k
        for class in 0..self.preferred_victim_by_class.len() {
115
278k
            self.preferred_victim_by_class[class] = self.env.non_preferred_regs_by_class[class]
116
278k
                .last()
117
278k
                .or(self.env.preferred_regs_by_class[class].last())
118
278k
                .cloned()
119
278k
                .unwrap_or(PReg::invalid());
120
278k
        }
121
        // Create VRegs from the vreg count.
122
19.7M
        for idx in 0..self.func.num_vregs() {
123
            // We'll fill in the real details when we see the def.
124
19.7M
            let reg = VReg::new(idx, RegClass::Int);
125
19.7M
            self.add_vreg(
126
19.7M
                reg,
127
19.7M
                VRegData {
128
19.7M
                    ranges: smallvec![],
129
19.7M
                    blockparam: Block::invalid(),
130
19.7M
                    is_ref: false,
131
19.7M
                    // We'll learn the RegClass as we scan the code.
132
19.7M
                    class: None,
133
                },
134
            );
135
        }
136
139k
        for v in self.func.reftype_vregs() {
137
0
            self.vregs[v.vreg()].is_ref = true;
138
0
        }
139
        // Create allocations too.
140
1.27M
        for inst in 0..self.func.num_insts() {
141
1.27M
            let start = self.allocs.len() as u32;
142
1.27M
            self.inst_alloc_offsets.push(start);
143
2.16M
            for _ in 0..self.func.inst_operands(Inst::new(inst)).len() {
144
2.16M
                self.allocs.push(Allocation::none());
145
2.16M
            }
146
        }
147
139k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::create_pregs_and_vregs
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::create_pregs_and_vregs
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::create_pregs_and_vregs
148
149
19.7M
    pub fn add_vreg(&mut self, reg: VReg, data: VRegData) -> VRegIndex {
150
19.7M
        let idx = self.vregs.len();
151
19.7M
        debug_assert_eq!(reg.vreg(), idx);
152
19.7M
        self.vregs.push(data);
153
19.7M
        VRegIndex::new(idx)
154
19.7M
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::add_vreg
Line
Count
Source
149
19.7M
    pub fn add_vreg(&mut self, reg: VReg, data: VRegData) -> VRegIndex {
150
19.7M
        let idx = self.vregs.len();
151
19.7M
        debug_assert_eq!(reg.vreg(), idx);
152
19.7M
        self.vregs.push(data);
153
19.7M
        VRegIndex::new(idx)
154
19.7M
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::add_vreg
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::add_vreg
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::add_vreg
155
156
1.34M
    pub fn create_bundle(&mut self) -> LiveBundleIndex {
157
1.34M
        let bundle = self.bundles.len();
158
1.34M
        self.bundles.push(LiveBundle {
159
1.34M
            allocation: Allocation::none(),
160
1.34M
            ranges: smallvec![],
161
1.34M
            spillset: SpillSetIndex::invalid(),
162
1.34M
            prio: 0,
163
1.34M
            spill_weight_and_props: 0,
164
1.34M
        });
165
1.34M
        LiveBundleIndex::new(bundle)
166
1.34M
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::create_bundle
Line
Count
Source
156
1.34M
    pub fn create_bundle(&mut self) -> LiveBundleIndex {
157
1.34M
        let bundle = self.bundles.len();
158
1.34M
        self.bundles.push(LiveBundle {
159
1.34M
            allocation: Allocation::none(),
160
1.34M
            ranges: smallvec![],
161
1.34M
            spillset: SpillSetIndex::invalid(),
162
1.34M
            prio: 0,
163
1.34M
            spill_weight_and_props: 0,
164
1.34M
        });
165
1.34M
        LiveBundleIndex::new(bundle)
166
1.34M
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::create_bundle
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::create_bundle
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::create_bundle
167
168
1.43M
    pub fn create_liverange(&mut self, range: CodeRange) -> LiveRangeIndex {
169
1.43M
        let idx = self.ranges.len();
170
1.43M
171
1.43M
        self.ranges.push(LiveRange {
172
1.43M
            range,
173
1.43M
            vreg: VRegIndex::invalid(),
174
1.43M
            bundle: LiveBundleIndex::invalid(),
175
1.43M
            uses_spill_weight_and_flags: 0,
176
1.43M
177
1.43M
            uses: smallvec![],
178
179
1.43M
            merged_into: LiveRangeIndex::invalid(),
180
1.43M
        });
181
1.43M
182
1.43M
        LiveRangeIndex::new(idx)
183
1.43M
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::create_liverange
Line
Count
Source
168
1.43M
    pub fn create_liverange(&mut self, range: CodeRange) -> LiveRangeIndex {
169
1.43M
        let idx = self.ranges.len();
170
1.43M
171
1.43M
        self.ranges.push(LiveRange {
172
1.43M
            range,
173
1.43M
            vreg: VRegIndex::invalid(),
174
1.43M
            bundle: LiveBundleIndex::invalid(),
175
1.43M
            uses_spill_weight_and_flags: 0,
176
1.43M
177
1.43M
            uses: smallvec![],
178
179
1.43M
            merged_into: LiveRangeIndex::invalid(),
180
1.43M
        });
181
1.43M
182
1.43M
        LiveRangeIndex::new(idx)
183
1.43M
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::create_liverange
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::create_liverange
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::create_liverange
184
185
    /// Mark `range` as live for the given `vreg`.
186
    ///
187
    /// Returns the liverange that contains the given range.
188
1.78M
    pub fn add_liverange_to_vreg(
189
1.78M
        &mut self,
190
1.78M
        vreg: VRegIndex,
191
1.78M
        mut range: CodeRange,
192
1.78M
    ) -> LiveRangeIndex {
193
1.78M
        trace!("add_liverange_to_vreg: vreg {:?} range {:?}", vreg, range);
194
195
        // Invariant: as we are building liveness information, we
196
        // *always* process instructions bottom-to-top, and as a
197
        // consequence, new liveranges are always created before any
198
        // existing liveranges for a given vreg. We assert this here,
199
        // then use it to avoid an O(n) merge step (which would lead
200
        // to O(n^2) liveness construction cost overall).
201
        //
202
        // We store liveranges in reverse order in the `.ranges`
203
        // array, then reverse them at the end of
204
        // `compute_liveness()`.
205
206
1.78M
        if !self.vregs[vreg.index()].ranges.is_empty() {
207
628k
            let last_range_index = self.vregs[vreg.index()].ranges.last().unwrap().index;
208
628k
            let last_range = self.ranges[last_range_index.index()].range;
209
628k
            if self.func.allow_multiple_vreg_defs() {
210
628k
                if last_range.contains(&range) {
211
                    // Special case (may occur when multiple defs of pinned
212
                    // physical regs occur): if this new range overlaps the
213
                    // existing range, return it.
214
0
                    return last_range_index;
215
628k
                }
216
628k
                // If this range's end falls in the middle of the last
217
628k
                // range, truncate it to be contiguous so we can merge
218
628k
                // below.
219
628k
                if range.to >= last_range.from && range.to <= last_range.to {
220
548k
                    range.to = last_range.from;
221
548k
                }
222
0
            }
223
628k
            debug_assert!(
224
0
                range.to <= last_range.from,
225
0
                "range {:?}, last_range {:?}",
226
                range,
227
                last_range
228
            );
229
1.15M
        }
230
231
1.78M
        if self.vregs[vreg.index()].ranges.is_empty()
232
628k
            || range.to
233
628k
                < self.ranges[self.vregs[vreg.index()]
234
628k
                    .ranges
235
628k
                    .last()
236
628k
                    .unwrap()
237
628k
                    .index
238
628k
                    .index()]
239
628k
                .range
240
628k
                .from
241
        {
242
            // Is not contiguous with previously-added (immediately
243
            // following) range; create a new range.
244
1.23M
            let lr = self.create_liverange(range);
245
1.23M
            self.ranges[lr.index()].vreg = vreg;
246
1.23M
            self.vregs[vreg.index()]
247
1.23M
                .ranges
248
1.23M
                .push(LiveRangeListEntry { range, index: lr });
249
1.23M
            lr
250
        } else {
251
            // Is contiguous with previously-added range; just extend
252
            // its range and return it.
253
548k
            let lr = self.vregs[vreg.index()].ranges.last().unwrap().index;
254
548k
            debug_assert!(range.to == self.ranges[lr.index()].range.from);
255
548k
            self.ranges[lr.index()].range.from = range.from;
256
548k
            lr
257
        }
258
1.78M
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::add_liverange_to_vreg
Line
Count
Source
188
1.78M
    pub fn add_liverange_to_vreg(
189
1.78M
        &mut self,
190
1.78M
        vreg: VRegIndex,
191
1.78M
        mut range: CodeRange,
192
1.78M
    ) -> LiveRangeIndex {
193
1.78M
        trace!("add_liverange_to_vreg: vreg {:?} range {:?}", vreg, range);
194
195
        // Invariant: as we are building liveness information, we
196
        // *always* process instructions bottom-to-top, and as a
197
        // consequence, new liveranges are always created before any
198
        // existing liveranges for a given vreg. We assert this here,
199
        // then use it to avoid an O(n) merge step (which would lead
200
        // to O(n^2) liveness construction cost overall).
201
        //
202
        // We store liveranges in reverse order in the `.ranges`
203
        // array, then reverse them at the end of
204
        // `compute_liveness()`.
205
206
1.78M
        if !self.vregs[vreg.index()].ranges.is_empty() {
207
628k
            let last_range_index = self.vregs[vreg.index()].ranges.last().unwrap().index;
208
628k
            let last_range = self.ranges[last_range_index.index()].range;
209
628k
            if self.func.allow_multiple_vreg_defs() {
210
628k
                if last_range.contains(&range) {
211
                    // Special case (may occur when multiple defs of pinned
212
                    // physical regs occur): if this new range overlaps the
213
                    // existing range, return it.
214
0
                    return last_range_index;
215
628k
                }
216
628k
                // If this range's end falls in the middle of the last
217
628k
                // range, truncate it to be contiguous so we can merge
218
628k
                // below.
219
628k
                if range.to >= last_range.from && range.to <= last_range.to {
220
548k
                    range.to = last_range.from;
221
548k
                }
222
0
            }
223
628k
            debug_assert!(
224
0
                range.to <= last_range.from,
225
0
                "range {:?}, last_range {:?}",
226
                range,
227
                last_range
228
            );
229
1.15M
        }
230
231
1.78M
        if self.vregs[vreg.index()].ranges.is_empty()
232
628k
            || range.to
233
628k
                < self.ranges[self.vregs[vreg.index()]
234
628k
                    .ranges
235
628k
                    .last()
236
628k
                    .unwrap()
237
628k
                    .index
238
628k
                    .index()]
239
628k
                .range
240
628k
                .from
241
        {
242
            // Is not contiguous with previously-added (immediately
243
            // following) range; create a new range.
244
1.23M
            let lr = self.create_liverange(range);
245
1.23M
            self.ranges[lr.index()].vreg = vreg;
246
1.23M
            self.vregs[vreg.index()]
247
1.23M
                .ranges
248
1.23M
                .push(LiveRangeListEntry { range, index: lr });
249
1.23M
            lr
250
        } else {
251
            // Is contiguous with previously-added range; just extend
252
            // its range and return it.
253
548k
            let lr = self.vregs[vreg.index()].ranges.last().unwrap().index;
254
548k
            debug_assert!(range.to == self.ranges[lr.index()].range.from);
255
548k
            self.ranges[lr.index()].range.from = range.from;
256
548k
            lr
257
        }
258
1.78M
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::add_liverange_to_vreg
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::add_liverange_to_vreg
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::add_liverange_to_vreg
259
260
2.15M
    pub fn insert_use_into_liverange(&mut self, into: LiveRangeIndex, mut u: Use) {
261
2.15M
        let operand = u.operand;
262
2.15M
        let constraint = operand.constraint();
263
2.15M
        let block = self.cfginfo.insn_block[u.pos.inst().index()];
264
2.15M
        let loop_depth = self.cfginfo.approx_loop_depth[block.index()] as usize;
265
2.15M
        let weight = spill_weight_from_constraint(
266
2.15M
            constraint,
267
2.15M
            loop_depth,
268
2.15M
            operand.kind() != OperandKind::Use,
269
2.15M
        );
270
2.15M
        u.weight = weight.to_bits();
271
2.15M
272
2.15M
        trace!(
273
0
            "insert use {:?} into lr {:?} with weight {:?}",
274
            u,
275
            into,
276
            weight,
277
        );
278
279
        // N.B.: we do *not* update `requirement` on the range,
280
        // because those will be computed during the multi-fixed-reg
281
        // fixup pass later (after all uses are inserted).
282
283
2.15M
        self.ranges[into.index()].uses.push(u);
284
2.15M
285
2.15M
        // Update stats.
286
2.15M
        let range_weight = self.ranges[into.index()].uses_spill_weight() + weight;
287
2.15M
        self.ranges[into.index()].set_uses_spill_weight(range_weight);
288
2.15M
        trace!(
289
0
            "  -> now range has weight {:?}",
290
0
            self.ranges[into.index()].uses_spill_weight(),
291
        );
292
2.15M
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::insert_use_into_liverange
Line
Count
Source
260
2.15M
    pub fn insert_use_into_liverange(&mut self, into: LiveRangeIndex, mut u: Use) {
261
2.15M
        let operand = u.operand;
262
2.15M
        let constraint = operand.constraint();
263
2.15M
        let block = self.cfginfo.insn_block[u.pos.inst().index()];
264
2.15M
        let loop_depth = self.cfginfo.approx_loop_depth[block.index()] as usize;
265
2.15M
        let weight = spill_weight_from_constraint(
266
2.15M
            constraint,
267
2.15M
            loop_depth,
268
2.15M
            operand.kind() != OperandKind::Use,
269
2.15M
        );
270
2.15M
        u.weight = weight.to_bits();
271
2.15M
272
2.15M
        trace!(
273
0
            "insert use {:?} into lr {:?} with weight {:?}",
274
            u,
275
            into,
276
            weight,
277
        );
278
279
        // N.B.: we do *not* update `requirement` on the range,
280
        // because those will be computed during the multi-fixed-reg
281
        // fixup pass later (after all uses are inserted).
282
283
2.15M
        self.ranges[into.index()].uses.push(u);
284
2.15M
285
2.15M
        // Update stats.
286
2.15M
        let range_weight = self.ranges[into.index()].uses_spill_weight() + weight;
287
2.15M
        self.ranges[into.index()].set_uses_spill_weight(range_weight);
288
2.15M
        trace!(
289
0
            "  -> now range has weight {:?}",
290
0
            self.ranges[into.index()].uses_spill_weight(),
291
        );
292
2.15M
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::insert_use_into_liverange
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::insert_use_into_liverange
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::insert_use_into_liverange
293
294
0
    pub fn find_vreg_liverange_for_pos(
295
0
        &self,
296
0
        vreg: VRegIndex,
297
0
        pos: ProgPoint,
298
0
    ) -> Option<LiveRangeIndex> {
299
0
        for entry in &self.vregs[vreg.index()].ranges {
300
0
            if entry.range.contains_point(pos) {
301
0
                return Some(entry.index);
302
0
            }
303
        }
304
0
        None
305
0
    }
306
307
2.61M
    pub fn add_liverange_to_preg(&mut self, range: CodeRange, reg: PReg) {
308
2.61M
        trace!("adding liverange to preg: {:?} to {}", range, reg);
309
2.61M
        let preg_idx = PRegIndex::new(reg.index());
310
2.61M
        self.pregs[preg_idx.index()]
311
2.61M
            .allocations
312
2.61M
            .btree
313
2.61M
            .insert(LiveRangeKey::from_range(&range), LiveRangeIndex::invalid());
314
2.61M
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::add_liverange_to_preg
Line
Count
Source
307
2.61M
    pub fn add_liverange_to_preg(&mut self, range: CodeRange, reg: PReg) {
308
2.61M
        trace!("adding liverange to preg: {:?} to {}", range, reg);
309
2.61M
        let preg_idx = PRegIndex::new(reg.index());
310
2.61M
        self.pregs[preg_idx.index()]
311
2.61M
            .allocations
312
2.61M
            .btree
313
2.61M
            .insert(LiveRangeKey::from_range(&range), LiveRangeIndex::invalid());
314
2.61M
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::add_liverange_to_preg
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::add_liverange_to_preg
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::add_liverange_to_preg
315
316
735k
    pub fn is_live_in(&mut self, block: Block, vreg: VRegIndex) -> bool {
317
735k
        self.liveins[block.index()].get(vreg.index())
318
735k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::is_live_in
Line
Count
Source
316
735k
    pub fn is_live_in(&mut self, block: Block, vreg: VRegIndex) -> bool {
317
735k
        self.liveins[block.index()].get(vreg.index())
318
735k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::is_live_in
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::is_live_in
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::is_live_in
319
320
139k
    pub fn compute_liveness(&mut self) -> Result<(), RegAllocError> {
321
139k
        // Create initial LiveIn and LiveOut bitsets.
322
336k
        for _ in 0..self.func.num_blocks() {
323
336k
            self.liveins.push(IndexSet::new());
324
336k
            self.liveouts.push(IndexSet::new());
325
336k
        }
326
327
        // Run a worklist algorithm to precisely compute liveins and
328
        // liveouts.
329
139k
        let mut workqueue = VecDeque::new();
330
139k
        let mut workqueue_set = FxHashSet::default();
331
        // Initialize workqueue with postorder traversal.
332
336k
        for &block in &self.cfginfo.postorder[..] {
333
336k
            workqueue.push_back(block);
334
336k
            workqueue_set.insert(block);
335
336k
        }
336
337
478k
        while !workqueue.is_empty() {
338
339k
            let block = workqueue.pop_front().unwrap();
339
339k
            workqueue_set.remove(&block);
340
339k
            let insns = self.func.block_insns(block);
341
339k
342
339k
            trace!("computing liveins for block{}", block.index());
343
344
339k
            self.stats.livein_iterations += 1;
345
339k
346
339k
            let mut live = self.liveouts[block.index()].clone();
347
339k
            trace!(" -> initial liveout set: {:?}", live);
348
349
            // Include outgoing blockparams in the initial live set.
350
339k
            if self.func.is_branch(insns.last()) {
351
207k
                for i in 0..self.func.block_succs(block).len() {
352
207k
                    for &param in self.func.branch_blockparams(block, insns.last(), i) {
353
384
                        live.set(param.vreg(), true);
354
384
                        self.observe_vreg_class(param);
355
384
                    }
356
                }
357
161k
            }
358
359
1.28M
            for inst in insns.rev().iter() {
360
1.28M
                if let Some((src, dst)) = self.func.is_move(inst) {
361
2.88k
                    live.set(dst.vreg().vreg(), false);
362
2.88k
                    live.set(src.vreg().vreg(), true);
363
2.88k
                    self.observe_vreg_class(src.vreg());
364
2.88k
                    self.observe_vreg_class(dst.vreg());
365
1.27M
                }
366
367
3.84M
                for pos in &[OperandPos::Late, OperandPos::Early] {
368
4.36M
                    for op in self.func.inst_operands(inst) {
369
4.36M
                        if op.as_fixed_nonallocatable().is_some() {
370
9.87k
                            continue;
371
4.35M
                        }
372
4.35M
                        if op.pos() == *pos {
373
2.17M
                            let was_live = live.get(op.vreg().vreg());
374
2.17M
                            trace!("op {:?} was_live = {}", op, was_live);
375
2.17M
                            match op.kind() {
376
1.01M
                                OperandKind::Use | OperandKind::Mod => {
377
1.01M
                                    live.set(op.vreg().vreg(), true);
378
1.01M
                                }
379
1.16M
                                OperandKind::Def => {
380
1.16M
                                    live.set(op.vreg().vreg(), false);
381
1.16M
                                }
382
                            }
383
2.17M
                            self.observe_vreg_class(op.vreg());
384
2.17M
                        }
385
                    }
386
                }
387
            }
388
510k
            for &blockparam in self.func.block_params(block) {
389
510k
                live.set(blockparam.vreg(), false);
390
510k
                self.observe_vreg_class(blockparam);
391
510k
            }
392
393
339k
            for &pred in self.func.block_preds(block) {
394
207k
                if self.liveouts[pred.index()].union_with(&live) {
395
43.0k
                    if !workqueue_set.contains(&pred) {
396
2.50k
                        workqueue_set.insert(pred);
397
2.50k
                        workqueue.push_back(pred);
398
40.5k
                    }
399
164k
                }
400
            }
401
402
339k
            trace!("computed liveins at block{}: {:?}", block.index(), live);
403
339k
            self.liveins[block.index()] = live;
404
        }
405
406
        // Check that there are no liveins to the entry block, except
407
        // for pinned vregs. (The client should create a virtual
408
        // instruction that defines any other liveins if necessary.)
409
139k
        for livein in self.liveins[self.func.entry_block().index()].iter() {
410
0
            let livein = self.vreg(VRegIndex::new(livein));
411
0
            if self.func.is_pinned_vreg(livein).is_none() {
412
0
                trace!("non-pinned-vreg livein to entry block: {}", livein);
413
0
                return Err(RegAllocError::EntryLivein);
414
0
            }
415
        }
416
417
139k
        Ok(())
418
139k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::compute_liveness
Line
Count
Source
320
139k
    pub fn compute_liveness(&mut self) -> Result<(), RegAllocError> {
321
139k
        // Create initial LiveIn and LiveOut bitsets.
322
336k
        for _ in 0..self.func.num_blocks() {
323
336k
            self.liveins.push(IndexSet::new());
324
336k
            self.liveouts.push(IndexSet::new());
325
336k
        }
326
327
        // Run a worklist algorithm to precisely compute liveins and
328
        // liveouts.
329
139k
        let mut workqueue = VecDeque::new();
330
139k
        let mut workqueue_set = FxHashSet::default();
331
        // Initialize workqueue with postorder traversal.
332
336k
        for &block in &self.cfginfo.postorder[..] {
333
336k
            workqueue.push_back(block);
334
336k
            workqueue_set.insert(block);
335
336k
        }
336
337
478k
        while !workqueue.is_empty() {
338
339k
            let block = workqueue.pop_front().unwrap();
339
339k
            workqueue_set.remove(&block);
340
339k
            let insns = self.func.block_insns(block);
341
339k
342
339k
            trace!("computing liveins for block{}", block.index());
343
344
339k
            self.stats.livein_iterations += 1;
345
339k
346
339k
            let mut live = self.liveouts[block.index()].clone();
347
339k
            trace!(" -> initial liveout set: {:?}", live);
348
349
            // Include outgoing blockparams in the initial live set.
350
339k
            if self.func.is_branch(insns.last()) {
351
207k
                for i in 0..self.func.block_succs(block).len() {
352
207k
                    for &param in self.func.branch_blockparams(block, insns.last(), i) {
353
384
                        live.set(param.vreg(), true);
354
384
                        self.observe_vreg_class(param);
355
384
                    }
356
                }
357
161k
            }
358
359
1.28M
            for inst in insns.rev().iter() {
360
1.28M
                if let Some((src, dst)) = self.func.is_move(inst) {
361
2.88k
                    live.set(dst.vreg().vreg(), false);
362
2.88k
                    live.set(src.vreg().vreg(), true);
363
2.88k
                    self.observe_vreg_class(src.vreg());
364
2.88k
                    self.observe_vreg_class(dst.vreg());
365
1.27M
                }
366
367
3.84M
                for pos in &[OperandPos::Late, OperandPos::Early] {
368
4.36M
                    for op in self.func.inst_operands(inst) {
369
4.36M
                        if op.as_fixed_nonallocatable().is_some() {
370
9.87k
                            continue;
371
4.35M
                        }
372
4.35M
                        if op.pos() == *pos {
373
2.17M
                            let was_live = live.get(op.vreg().vreg());
374
2.17M
                            trace!("op {:?} was_live = {}", op, was_live);
375
2.17M
                            match op.kind() {
376
1.01M
                                OperandKind::Use | OperandKind::Mod => {
377
1.01M
                                    live.set(op.vreg().vreg(), true);
378
1.01M
                                }
379
1.16M
                                OperandKind::Def => {
380
1.16M
                                    live.set(op.vreg().vreg(), false);
381
1.16M
                                }
382
                            }
383
2.17M
                            self.observe_vreg_class(op.vreg());
384
2.17M
                        }
385
                    }
386
                }
387
            }
388
510k
            for &blockparam in self.func.block_params(block) {
389
510k
                live.set(blockparam.vreg(), false);
390
510k
                self.observe_vreg_class(blockparam);
391
510k
            }
392
393
339k
            for &pred in self.func.block_preds(block) {
394
207k
                if self.liveouts[pred.index()].union_with(&live) {
395
43.0k
                    if !workqueue_set.contains(&pred) {
396
2.50k
                        workqueue_set.insert(pred);
397
2.50k
                        workqueue.push_back(pred);
398
40.5k
                    }
399
164k
                }
400
            }
401
402
339k
            trace!("computed liveins at block{}: {:?}", block.index(), live);
403
339k
            self.liveins[block.index()] = live;
404
        }
405
406
        // Check that there are no liveins to the entry block, except
407
        // for pinned vregs. (The client should create a virtual
408
        // instruction that defines any other liveins if necessary.)
409
139k
        for livein in self.liveins[self.func.entry_block().index()].iter() {
410
0
            let livein = self.vreg(VRegIndex::new(livein));
411
0
            if self.func.is_pinned_vreg(livein).is_none() {
412
0
                trace!("non-pinned-vreg livein to entry block: {}", livein);
413
0
                return Err(RegAllocError::EntryLivein);
414
0
            }
415
        }
416
417
139k
        Ok(())
418
139k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::compute_liveness
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::compute_liveness
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::compute_liveness
419
420
139k
    pub fn build_liveranges(&mut self) {
421
139k
        for &vreg in self.func.reftype_vregs() {
422
0
            self.safepoints_per_vreg.insert(vreg.vreg(), HashSet::new());
423
0
        }
424
425
        // Create Uses and Defs referring to VRegs, and place the Uses
426
        // in LiveRanges.
427
        //
428
        // We already computed precise liveouts and liveins for every
429
        // block above, so we don't need to run an iterative algorithm
430
        // here; instead, every block's computation is purely local,
431
        // from end to start.
432
433
        // Track current LiveRange for each vreg.
434
        //
435
        // Invariant: a stale range may be present here; ranges are
436
        // only valid if `live.get(vreg)` is true.
437
139k
        let mut vreg_ranges: Vec<LiveRangeIndex> =
438
139k
            vec![LiveRangeIndex::invalid(); self.func.num_vregs()];
439
440
336k
        for i in (0..self.func.num_blocks()).rev() {
441
336k
            let block = Block::new(i);
442
336k
            let insns = self.func.block_insns(block);
443
336k
444
336k
            self.stats.livein_blocks += 1;
445
336k
446
336k
            // Init our local live-in set.
447
336k
            let mut live = self.liveouts[block.index()].clone();
448
336k
449
336k
            // If the last instruction is a branch (rather than
450
336k
            // return), create blockparam_out entries.
451
336k
            if self.func.is_branch(insns.last()) {
452
204k
                for (i, &succ) in self.func.block_succs(block).iter().enumerate() {
453
204k
                    let blockparams_in = self.func.block_params(succ);
454
204k
                    let blockparams_out = self.func.branch_blockparams(block, insns.last(), i);
455
330
                    for (&blockparam_in, &blockparam_out) in
456
204k
                        blockparams_in.iter().zip(blockparams_out)
457
330
                    {
458
330
                        let blockparam_out = VRegIndex::new(blockparam_out.vreg());
459
330
                        let blockparam_in = VRegIndex::new(blockparam_in.vreg());
460
330
                        self.blockparam_outs.push(BlockparamOut {
461
330
                            to_vreg: blockparam_in,
462
330
                            to_block: succ,
463
330
                            from_block: block,
464
330
                            from_vreg: blockparam_out,
465
330
                        });
466
330
467
330
                        // Include outgoing blockparams in the initial live set.
468
330
                        live.set(blockparam_out.index(), true);
469
330
                    }
470
                }
471
161k
            }
472
473
            // Initially, registers are assumed live for the whole block.
474
336k
            for vreg in live.iter() {
475
119k
                let range = CodeRange {
476
119k
                    from: self.cfginfo.block_entry[block.index()],
477
119k
                    to: self.cfginfo.block_exit[block.index()].next(),
478
119k
                };
479
119k
                trace!(
480
0
                    "vreg {:?} live at end of block --> create range {:?}",
481
0
                    VRegIndex::new(vreg),
482
                    range
483
                );
484
119k
                let lr = self.add_liverange_to_vreg(VRegIndex::new(vreg), range);
485
119k
                vreg_ranges[vreg] = lr;
486
            }
487
488
            // Create vreg data for blockparams.
489
510k
            for &param in self.func.block_params(block) {
490
510k
                self.vregs[param.vreg()].blockparam = block;
491
510k
            }
492
493
            // For each instruction, in reverse order, process
494
            // operands and clobbers.
495
1.27M
            for inst in insns.rev().iter() {
496
                // Mark clobbers with CodeRanges on PRegs.
497
2.56M
                for clobber in self.func.inst_clobbers(inst) {
498
2.56M
                    // Clobber range is at After point only: an
499
2.56M
                    // instruction can still take an input in a reg
500
2.56M
                    // that it later clobbers. (In other words, the
501
2.56M
                    // clobber is like a normal def that never gets
502
2.56M
                    // used.)
503
2.56M
                    let range = CodeRange {
504
2.56M
                        from: ProgPoint::after(inst),
505
2.56M
                        to: ProgPoint::before(inst.next()),
506
2.56M
                    };
507
2.56M
                    self.add_liverange_to_preg(range, clobber);
508
2.56M
                }
509
510
                // Does the instruction have any input-reusing
511
                // outputs? This is important below to establish
512
                // proper interference wrt other inputs. We note the
513
                // *vreg* that is reused, not the index.
514
1.27M
                let mut reused_input = None;
515
2.14M
                for op in self.func.inst_operands(inst) {
516
2.14M
                    if let OperandConstraint::Reuse(i) = op.constraint() {
517
100k
                        debug_assert!(self.func.inst_operands(inst)[i]
518
0
                            .as_fixed_nonallocatable()
519
0
                            .is_none());
520
100k
                        reused_input = Some(self.func.inst_operands(inst)[i].vreg());
521
100k
                        break;
522
2.04M
                    }
523
                }
524
525
                // If this is a move, handle specially.
526
1.27M
                if let Some((src, dst)) = self.func.is_move(inst) {
527
                    // We can completely skip the move if it is
528
                    // trivial (vreg to same vreg).
529
2.85k
                    if src.vreg() != dst.vreg() {
530
2.85k
                        trace!(" -> move inst{}: src {} -> dst {}", inst.index(), src, dst);
531
532
2.85k
                        debug_assert_eq!(src.class(), dst.class());
533
2.85k
                        debug_assert_eq!(src.kind(), OperandKind::Use);
534
2.85k
                        debug_assert_eq!(src.pos(), OperandPos::Early);
535
2.85k
                        debug_assert_eq!(dst.kind(), OperandKind::Def);
536
2.85k
                        debug_assert_eq!(dst.pos(), OperandPos::Late);
537
538
2.85k
                        let src_pinned = self.func.is_pinned_vreg(src.vreg());
539
2.85k
                        let dst_pinned = self.func.is_pinned_vreg(dst.vreg());
540
2.85k
541
2.85k
                        match (src_pinned, dst_pinned) {
542
                            // If both src and dest are pinned, emit
543
                            // the move right here, right now.
544
0
                            (Some(src_preg), Some(dst_preg)) => {
545
0
                                // Update LRs.
546
0
                                if !live.get(src.vreg().vreg()) {
547
0
                                    let lr = self.add_liverange_to_vreg(
548
0
                                        VRegIndex::new(src.vreg().vreg()),
549
0
                                        CodeRange {
550
0
                                            from: self.cfginfo.block_entry[block.index()],
551
0
                                            to: ProgPoint::after(inst),
552
0
                                        },
553
0
                                    );
554
0
                                    live.set(src.vreg().vreg(), true);
555
0
                                    vreg_ranges[src.vreg().vreg()] = lr;
556
0
                                }
557
0
                                if live.get(dst.vreg().vreg()) {
558
0
                                    let lr = vreg_ranges[dst.vreg().vreg()];
559
0
                                    self.ranges[lr.index()].range.from = ProgPoint::after(inst);
560
0
                                    live.set(dst.vreg().vreg(), false);
561
0
                                } else {
562
0
                                    self.add_liverange_to_vreg(
563
0
                                        VRegIndex::new(dst.vreg().vreg()),
564
0
                                        CodeRange {
565
0
                                            from: ProgPoint::after(inst),
566
0
                                            to: ProgPoint::before(inst.next()),
567
0
                                        },
568
0
                                    );
569
0
                                }
570
571
0
                                self.insert_move(
572
0
                                    ProgPoint::before(inst),
573
0
                                    InsertMovePrio::MultiFixedRegInitial,
574
0
                                    Allocation::reg(src_preg),
575
0
                                    Allocation::reg(dst_preg),
576
0
                                    dst.vreg(),
577
0
                                );
578
                            }
579
580
                            // If exactly one of source and dest (but
581
                            // not both) is a pinned-vreg, convert
582
                            // this into a ghost use on the other vreg
583
                            // with a FixedReg constraint.
584
0
                            (Some(preg), None) | (None, Some(preg)) => {
585
0
                                trace!(
586
0
                                    " -> exactly one of src/dst is pinned; converting to ghost use"
587
                                );
588
0
                                let (vreg, pinned_vreg, kind, pos, progpoint) =
589
0
                                    if src_pinned.is_some() {
590
                                        // Source is pinned: this is a def on the dst with a pinned preg.
591
0
                                        (
592
0
                                            dst.vreg(),
593
0
                                            src.vreg(),
594
0
                                            OperandKind::Def,
595
0
                                            OperandPos::Late,
596
0
                                            ProgPoint::before(inst),
597
0
                                        )
598
                                    } else {
599
                                        // Dest is pinned: this is a use on the src with a pinned preg.
600
0
                                        (
601
0
                                            src.vreg(),
602
0
                                            dst.vreg(),
603
0
                                            OperandKind::Use,
604
0
                                            OperandPos::Early,
605
0
                                            ProgPoint::after(inst),
606
0
                                        )
607
                                    };
608
0
                                let constraint = OperandConstraint::FixedReg(preg);
609
0
                                let operand = Operand::new(vreg, constraint, kind, pos);
610
0
611
0
                                trace!(
612
0
                                    concat!(
613
0
                                        " -> preg {:?} vreg {:?} kind {:?} ",
614
0
                                        "pos {:?} progpoint {:?} constraint {:?} operand {:?}"
615
0
                                    ),
616
                                    preg,
617
                                    vreg,
618
                                    kind,
619
                                    pos,
620
                                    progpoint,
621
                                    constraint,
622
                                    operand
623
                                );
624
625
                                // Get the LR for the vreg; if none, create one.
626
0
                                let mut lr = vreg_ranges[vreg.vreg()];
627
0
                                if !live.get(vreg.vreg()) {
628
0
                                    let from = match kind {
629
0
                                        OperandKind::Use => self.cfginfo.block_entry[block.index()],
630
0
                                        OperandKind::Def => progpoint,
631
0
                                        _ => unreachable!(),
632
                                    };
633
0
                                    let to = progpoint.next();
634
0
                                    lr = self.add_liverange_to_vreg(
635
0
                                        VRegIndex::new(vreg.vreg()),
636
0
                                        CodeRange { from, to },
637
0
                                    );
638
0
                                    trace!("   -> dead; created LR");
639
0
                                }
640
0
                                trace!("  -> LR {:?}", lr);
641
642
0
                                self.insert_use_into_liverange(
643
0
                                    lr,
644
0
                                    Use::new(operand, progpoint, SLOT_NONE),
645
0
                                );
646
0
647
0
                                if kind == OperandKind::Def {
648
0
                                    live.set(vreg.vreg(), false);
649
0
                                    if self.ranges[lr.index()].range.from
650
0
                                        == self.cfginfo.block_entry[block.index()]
651
0
                                    {
652
0
                                        self.ranges[lr.index()].range.from = progpoint;
653
0
                                    }
654
0
                                    self.ranges[lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
655
0
                                } else {
656
0
                                    live.set(vreg.vreg(), true);
657
0
                                    vreg_ranges[vreg.vreg()] = lr;
658
0
                                }
659
660
                                // Handle liveness of the other vreg. Note
661
                                // that this is somewhat special. For the
662
                                // destination case, we want the pinned
663
                                // vreg's LR to start just *after* the
664
                                // operand we inserted above, because
665
                                // otherwise it would overlap, and
666
                                // interfere, and prevent allocation. For
667
                                // the source case, we want to "poke a
668
                                // hole" in the LR: if it's live going
669
                                // downward, end it just after the operand
670
                                // and restart it before; if it isn't
671
                                // (this is the last use), start it
672
                                // before.
673
0
                                if kind == OperandKind::Def {
674
0
                                    trace!(" -> src on pinned vreg {:?}", pinned_vreg);
675
                                    // The *other* vreg is a def, so the pinned-vreg
676
                                    // mention is a use. If already live,
677
                                    // end the existing LR just *after*
678
                                    // the `progpoint` defined above and
679
                                    // start a new one just *before* the
680
                                    // `progpoint` defined above,
681
                                    // preserving the start. If not, start
682
                                    // a new one live back to the top of
683
                                    // the block, starting just before
684
                                    // `progpoint`.
685
0
                                    if live.get(pinned_vreg.vreg()) {
686
0
                                        let pinned_lr = vreg_ranges[pinned_vreg.vreg()];
687
0
                                        let orig_start = self.ranges[pinned_lr.index()].range.from;
688
0
                                        // Following instruction start
689
0
                                        // (so we don't transition in
690
0
                                        // middle of inst).
691
0
                                        let new_start = ProgPoint::before(progpoint.inst().next());
692
0
                                        trace!(
693
0
                                            " -> live with LR {:?}; truncating to start at {:?}",
694
                                            pinned_lr,
695
                                            new_start,
696
                                        );
697
0
                                        self.ranges[pinned_lr.index()].range.from = new_start;
698
0
699
0
                                        let new_lr = self.add_liverange_to_vreg(
700
0
                                            VRegIndex::new(pinned_vreg.vreg()),
701
0
                                            CodeRange {
702
0
                                                from: orig_start,
703
0
                                                to: progpoint,
704
0
                                            },
705
0
                                        );
706
0
                                        vreg_ranges[pinned_vreg.vreg()] = new_lr;
707
0
                                        trace!(" -> created LR {:?} with remaining range from {:?} to {:?}", new_lr, orig_start, progpoint);
708
709
                                        // Add an edit right now to indicate that at
710
                                        // this program point, the given
711
                                        // preg is now known as that vreg,
712
                                        // not the preg, but immediately
713
                                        // after, it is known as the preg
714
                                        // again. This is used by the
715
                                        // checker.
716
0
                                        self.insert_move(
717
0
                                            ProgPoint::after(inst),
718
0
                                            InsertMovePrio::Regular,
719
0
                                            Allocation::reg(preg),
720
0
                                            Allocation::reg(preg),
721
0
                                            dst.vreg(),
722
0
                                        );
723
0
                                        self.insert_move(
724
0
                                            ProgPoint::before(inst.next()),
725
0
                                            InsertMovePrio::MultiFixedRegInitial,
726
0
                                            Allocation::reg(preg),
727
0
                                            Allocation::reg(preg),
728
0
                                            src.vreg(),
729
0
                                        );
730
                                    } else {
731
0
                                        if inst > self.cfginfo.block_entry[block.index()].inst() {
732
0
                                            let new_lr = self.add_liverange_to_vreg(
733
0
                                                VRegIndex::new(pinned_vreg.vreg()),
734
0
                                                CodeRange {
735
0
                                                    from: self.cfginfo.block_entry[block.index()],
736
0
                                                    to: progpoint,
737
0
                                                },
738
0
                                            );
739
0
                                            vreg_ranges[pinned_vreg.vreg()] = new_lr;
740
0
                                            live.set(pinned_vreg.vreg(), true);
741
0
                                            trace!(" -> was not live; created new LR {:?}", new_lr);
742
0
                                        }
743
744
                                        // Add an edit right now to indicate that at
745
                                        // this program point, the given
746
                                        // preg is now known as that vreg,
747
                                        // not the preg. This is used by
748
                                        // the checker.
749
0
                                        self.insert_move(
750
0
                                            ProgPoint::after(inst),
751
0
                                            InsertMovePrio::BlockParam,
752
0
                                            Allocation::reg(preg),
753
0
                                            Allocation::reg(preg),
754
0
                                            dst.vreg(),
755
0
                                        );
756
                                    }
757
                                } else {
758
0
                                    trace!(" -> dst on pinned vreg {:?}", pinned_vreg);
759
                                    // The *other* vreg is a use, so the pinned-vreg
760
                                    // mention is a def. Truncate its LR
761
                                    // just *after* the `progpoint`
762
                                    // defined above.
763
0
                                    if live.get(pinned_vreg.vreg()) {
764
0
                                        let pinned_lr = vreg_ranges[pinned_vreg.vreg()];
765
0
                                        self.ranges[pinned_lr.index()].range.from =
766
0
                                            progpoint.next();
767
0
                                        trace!(
768
0
                                            " -> was live with LR {:?}; truncated start to {:?}",
769
0
                                            pinned_lr,
770
0
                                            progpoint.next()
771
                                        );
772
0
                                        live.set(pinned_vreg.vreg(), false);
773
0
774
0
                                        // Add a no-op edit right now to indicate that
775
0
                                        // at this program point, the
776
0
                                        // given preg is now known as that
777
0
                                        // preg, not the vreg. This is
778
0
                                        // used by the checker.
779
0
                                        self.insert_move(
780
0
                                            ProgPoint::before(inst.next()),
781
0
                                            InsertMovePrio::PostRegular,
782
0
                                            Allocation::reg(preg),
783
0
                                            Allocation::reg(preg),
784
0
                                            dst.vreg(),
785
0
                                        );
786
0
                                    }
787
                                    // Otherwise, if dead, no need to create
788
                                    // a dummy LR -- there is no
789
                                    // reservation to make (the other vreg
790
                                    // will land in the reg with the
791
                                    // fixed-reg operand constraint, but
792
                                    // it's a dead move anyway).
793
                                }
794
                            }
795
796
                            // Ordinary move between two non-pinned vregs.
797
                            (None, None) => {
798
                                // Redefine src and dst operands to have
799
                                // positions of After and Before respectively
800
                                // (see note below), and to have Any
801
                                // constraints if they were originally Reg.
802
2.85k
                                let src_constraint = match src.constraint() {
803
2.85k
                                    OperandConstraint::Reg => OperandConstraint::Any,
804
0
                                    x => x,
805
                                };
806
2.85k
                                let dst_constraint = match dst.constraint() {
807
2.85k
                                    OperandConstraint::Reg => OperandConstraint::Any,
808
0
                                    x => x,
809
                                };
810
2.85k
                                let src = Operand::new(
811
2.85k
                                    src.vreg(),
812
2.85k
                                    src_constraint,
813
2.85k
                                    OperandKind::Use,
814
2.85k
                                    OperandPos::Late,
815
2.85k
                                );
816
2.85k
                                let dst = Operand::new(
817
2.85k
                                    dst.vreg(),
818
2.85k
                                    dst_constraint,
819
2.85k
                                    OperandKind::Def,
820
2.85k
                                    OperandPos::Early,
821
2.85k
                                );
822
2.85k
823
2.85k
                                if self.annotations_enabled {
824
0
                                    self.annotate(
825
0
                                        ProgPoint::after(inst),
826
0
                                        format!(
827
0
                                            " prog-move v{} ({:?}) -> v{} ({:?})",
828
0
                                            src.vreg().vreg(),
829
0
                                            src_constraint,
830
0
                                            dst.vreg().vreg(),
831
0
                                            dst_constraint,
832
0
                                        ),
833
0
                                    );
834
2.85k
                                }
835
836
                                // N.B.: in order to integrate with the move
837
                                // resolution that joins LRs in general, we
838
                                // conceptually treat the move as happening
839
                                // between the move inst's After and the next
840
                                // inst's Before. Thus the src LR goes up to
841
                                // (exclusive) next-inst-pre, and the dst LR
842
                                // starts at next-inst-pre. We have to take
843
                                // care in our move insertion to handle this
844
                                // like other inter-inst moves, i.e., at
845
                                // `Regular` priority, so it properly happens
846
                                // in parallel with other inter-LR moves.
847
                                //
848
                                // Why the progpoint between move and next
849
                                // inst, and not the progpoint between prev
850
                                // inst and move? Because a move can be the
851
                                // first inst in a block, but cannot be the
852
                                // last; so the following progpoint is always
853
                                // within the same block, while the previous
854
                                // one may be an inter-block point (and the
855
                                // After of the prev inst in a different
856
                                // block).
857
858
                                // Handle the def w.r.t. liveranges: trim the
859
                                // start of the range and mark it dead at this
860
                                // point in our backward scan.
861
2.85k
                                let pos = ProgPoint::before(inst.next());
862
2.85k
                                let mut dst_lr = vreg_ranges[dst.vreg().vreg()];
863
2.85k
                                if !live.get(dst.vreg().vreg()) {
864
730
                                    let from = pos;
865
730
                                    let to = pos.next();
866
730
                                    dst_lr = self.add_liverange_to_vreg(
867
730
                                        VRegIndex::new(dst.vreg().vreg()),
868
730
                                        CodeRange { from, to },
869
730
                                    );
870
730
                                    trace!(" -> invalid LR for def; created {:?}", dst_lr);
871
2.12k
                                }
872
2.85k
                                trace!(" -> has existing LR {:?}", dst_lr);
873
                                // Trim the LR to start here.
874
2.85k
                                if self.ranges[dst_lr.index()].range.from
875
2.85k
                                    == self.cfginfo.block_entry[block.index()]
876
                                {
877
2.12k
                                    trace!(" -> started at block start; trimming to {:?}", pos);
878
2.12k
                                    self.ranges[dst_lr.index()].range.from = pos;
879
730
                                }
880
2.85k
                                self.ranges[dst_lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
881
2.85k
                                live.set(dst.vreg().vreg(), false);
882
2.85k
                                vreg_ranges[dst.vreg().vreg()] = LiveRangeIndex::invalid();
883
2.85k
884
2.85k
                                // Handle the use w.r.t. liveranges: make it live
885
2.85k
                                // and create an initial LR back to the start of
886
2.85k
                                // the block.
887
2.85k
                                let pos = ProgPoint::after(inst);
888
2.85k
                                let src_lr = if !live.get(src.vreg().vreg()) {
889
2.85k
                                    let range = CodeRange {
890
2.85k
                                        from: self.cfginfo.block_entry[block.index()],
891
2.85k
                                        to: pos.next(),
892
2.85k
                                    };
893
2.85k
                                    let src_lr = self.add_liverange_to_vreg(
894
2.85k
                                        VRegIndex::new(src.vreg().vreg()),
895
2.85k
                                        range,
896
2.85k
                                    );
897
2.85k
                                    vreg_ranges[src.vreg().vreg()] = src_lr;
898
2.85k
                                    src_lr
899
                                } else {
900
0
                                    vreg_ranges[src.vreg().vreg()]
901
                                };
902
903
2.85k
                                trace!(" -> src LR {:?}", src_lr);
904
905
                                // Add to live-set.
906
2.85k
                                let src_is_dead_after_move = !live.get(src.vreg().vreg());
907
2.85k
                                live.set(src.vreg().vreg(), true);
908
2.85k
909
2.85k
                                // Add to program-moves lists.
910
2.85k
                                self.prog_move_srcs.push((
911
2.85k
                                    (VRegIndex::new(src.vreg().vreg()), inst),
912
2.85k
                                    Allocation::none(),
913
2.85k
                                ));
914
2.85k
                                self.prog_move_dsts.push((
915
2.85k
                                    (VRegIndex::new(dst.vreg().vreg()), inst.next()),
916
2.85k
                                    Allocation::none(),
917
2.85k
                                ));
918
2.85k
                                self.stats.prog_moves += 1;
919
2.85k
                                if src_is_dead_after_move {
920
2.85k
                                    self.stats.prog_moves_dead_src += 1;
921
2.85k
                                    self.prog_move_merges.push((src_lr, dst_lr));
922
2.85k
                                }
923
                            }
924
                        }
925
0
                    }
926
927
2.85k
                    continue;
928
1.27M
                }
929
1.27M
930
1.27M
                // Preprocess defs and uses. Specifically, if there
931
1.27M
                // are any fixed-reg-constrained defs at Late position
932
1.27M
                // and fixed-reg-constrained uses at Early position
933
1.27M
                // with the same preg, we need to (i) add a fixup move
934
1.27M
                // for the use, (ii) rewrite the use to have an Any
935
1.27M
                // constraint, and (ii) move the def to Early position
936
1.27M
                // to reserve the register for the whole instruction.
937
1.27M
                let mut operand_rewrites: FxHashMap<usize, Operand> = FxHashMap::default();
938
1.27M
                let mut late_def_fixed: SmallVec<[PReg; 8]> = smallvec![];
939
2.16M
                for &operand in self.func.inst_operands(inst) {
940
2.16M
                    if let OperandConstraint::FixedReg(preg) = operand.constraint() {
941
713k
                        match operand.pos() {
942
                            OperandPos::Late => {
943
                                // See note in fuzzing/func.rs: we
944
                                // can't allow this, because there
945
                                // would be no way to move a value
946
                                // into place for a late use *after*
947
                                // the early point (i.e. in the middle
948
                                // of the instruction).
949
494k
                                assert!(
950
494k
                                    operand.kind() == OperandKind::Def,
951
494k
                                    "Invalid operand: fixed constraint on Use/Mod at Late point"
952
494k
                                );
953
954
494k
                                late_def_fixed.push(preg);
955
                            }
956
219k
                            _ => {}
957
                        }
958
1.44M
                    }
959
                }
960
2.16M
                for (i, &operand) in self.func.inst_operands(inst).iter().enumerate() {
961
2.16M
                    if operand.as_fixed_nonallocatable().is_some() {
962
4.93k
                        continue;
963
2.15M
                    }
964
2.15M
                    if let OperandConstraint::FixedReg(preg) = operand.constraint() {
965
708k
                        match operand.pos() {
966
214k
                            OperandPos::Early if live.get(operand.vreg().vreg()) => {
967
43.6k
                                assert!(operand.kind() == OperandKind::Use,
968
43.6k
                                            "Invalid operand: fixed constraint on Def/Mod at Early position");
969
970
                                // If we have a constraint at the
971
                                // Early point for a fixed preg, and
972
                                // this preg is also constrained with
973
                                // a *separate* def at Late or is
974
                                // clobbered, and *if* the vreg is
975
                                // live downward, we have to use the
976
                                // multi-fixed-reg mechanism for a
977
                                // fixup and rewrite here without the
978
                                // constraint. See #53.
979
                                //
980
                                // We adjust the def liverange and Use
981
                                // to an "early" position to reserve
982
                                // the register, it still must not be
983
                                // used by some other vreg at the
984
                                // use-site.
985
                                //
986
                                // Note that we handle multiple
987
                                // conflicting constraints for the
988
                                // same vreg in a separate pass (see
989
                                // `fixup_multi_fixed_vregs` below).
990
43.6k
                                if late_def_fixed.contains(&preg)
991
43.3k
                                    || self.func.inst_clobbers(inst).contains(preg)
992
                                {
993
43.2k
                                    log::trace!(
994
0
                                        concat!(
995
0
                                            "-> operand {:?} is fixed to preg {:?}, ",
996
0
                                            "is downward live, and there is also a ",
997
0
                                            "def or clobber at this preg"
998
0
                                        ),
999
                                        operand,
1000
                                        preg
1001
                                    );
1002
43.2k
                                    let pos = ProgPoint::before(inst);
1003
43.2k
                                    self.multi_fixed_reg_fixups.push(MultiFixedRegFixup {
1004
43.2k
                                        pos,
1005
43.2k
                                        from_slot: i as u8,
1006
43.2k
                                        to_slot: i as u8,
1007
43.2k
                                        to_preg: PRegIndex::new(preg.index()),
1008
43.2k
                                        vreg: VRegIndex::new(operand.vreg().vreg()),
1009
43.2k
                                        level: FixedRegFixupLevel::Initial,
1010
43.2k
                                    });
1011
43.2k
1012
43.2k
                                    // We need to insert a reservation
1013
43.2k
                                    // at the before-point to reserve
1014
43.2k
                                    // the reg for the use too.
1015
43.2k
                                    let range = CodeRange::singleton(pos);
1016
43.2k
                                    self.add_liverange_to_preg(range, preg);
1017
43.2k
1018
43.2k
                                    // Remove the fixed-preg
1019
43.2k
                                    // constraint from the Use.
1020
43.2k
                                    operand_rewrites.insert(
1021
43.2k
                                        i,
1022
43.2k
                                        Operand::new(
1023
43.2k
                                            operand.vreg(),
1024
43.2k
                                            OperandConstraint::Any,
1025
43.2k
                                            operand.kind(),
1026
43.2k
                                            operand.pos(),
1027
43.2k
                                        ),
1028
43.2k
                                    );
1029
446
                                }
1030
                            }
1031
664k
                            _ => {}
1032
                        }
1033
1.44M
                    }
1034
                }
1035
1036
                // Process defs and uses.
1037
3.81M
                for &cur_pos in &[InstPosition::After, InstPosition::Before] {
1038
4.32M
                    for i in 0..self.func.inst_operands(inst).len() {
1039
                        // don't borrow `self`
1040
4.32M
                        let operand = operand_rewrites
1041
4.32M
                            .get(&i)
1042
4.32M
                            .cloned()
1043
4.32M
                            .unwrap_or(self.func.inst_operands(inst)[i]);
1044
4.32M
                        let pos = match (operand.kind(), operand.pos()) {
1045
0
                            (OperandKind::Mod, _) => ProgPoint::before(inst),
1046
224k
                            (OperandKind::Def, OperandPos::Early) => ProgPoint::before(inst),
1047
2.07M
                            (OperandKind::Def, OperandPos::Late) => ProgPoint::after(inst),
1048
0
                            (OperandKind::Use, OperandPos::Late) => ProgPoint::after(inst),
1049
                            // If there are any reused inputs in this
1050
                            // instruction, and this is *not* the
1051
                            // reused vreg, force `pos` to
1052
                            // `After`. This ensures that we correctly
1053
                            // account for the interference between
1054
                            // the other inputs and the
1055
                            // input-that-is-reused/output.
1056
                            (OperandKind::Use, OperandPos::Early)
1057
2.02M
                                if reused_input.is_some()
1058
253k
                                    && reused_input.unwrap() != operand.vreg() =>
1059
51.8k
                            {
1060
51.8k
                                ProgPoint::after(inst)
1061
                            }
1062
1.97M
                            (OperandKind::Use, OperandPos::Early) => ProgPoint::before(inst),
1063
                        };
1064
1065
4.32M
                        if pos.pos() != cur_pos {
1066
2.16M
                            continue;
1067
2.16M
                        }
1068
2.16M
1069
2.16M
                        trace!(
1070
0
                            "processing inst{} operand at {:?}: {:?}",
1071
0
                            inst.index(),
1072
                            pos,
1073
                            operand
1074
                        );
1075
1076
                        // If this is a "fixed non-allocatable
1077
                        // register" operand, set the alloc
1078
                        // immediately and then ignore the operand
1079
                        // hereafter.
1080
2.16M
                        if let Some(preg) = operand.as_fixed_nonallocatable() {
1081
4.93k
                            self.set_alloc(inst, i, Allocation::reg(preg));
1082
4.93k
                            continue;
1083
2.15M
                        }
1084
2.15M
1085
2.15M
                        match operand.kind() {
1086
                            OperandKind::Def | OperandKind::Mod => {
1087
1.15M
                                trace!("Def of {} at {:?}", operand.vreg(), pos);
1088
1089
                                // Get or create the LiveRange.
1090
1.15M
                                let mut lr = vreg_ranges[operand.vreg().vreg()];
1091
1.15M
                                trace!(" -> has existing LR {:?}", lr);
1092
                                // If there was no liverange (dead def), create a trivial one.
1093
1.15M
                                if !live.get(operand.vreg().vreg()) {
1094
468k
                                    let from = match operand.kind() {
1095
468k
                                        OperandKind::Def => pos,
1096
0
                                        OperandKind::Mod => self.cfginfo.block_entry[block.index()],
1097
0
                                        _ => unreachable!(),
1098
                                    };
1099
                                    // We want to we want to span
1100
                                    // until Before of the next
1101
                                    // inst. This ensures that early
1102
                                    // defs used for temps on an
1103
                                    // instruction are reserved across
1104
                                    // the whole instruction.
1105
468k
                                    let to = ProgPoint::before(pos.inst().next());
1106
468k
                                    lr = self.add_liverange_to_vreg(
1107
468k
                                        VRegIndex::new(operand.vreg().vreg()),
1108
468k
                                        CodeRange { from, to },
1109
468k
                                    );
1110
468k
                                    trace!(" -> invalid; created {:?}", lr);
1111
468k
                                    vreg_ranges[operand.vreg().vreg()] = lr;
1112
468k
                                    live.set(operand.vreg().vreg(), true);
1113
682k
                                }
1114
                                // Create the use in the LiveRange.
1115
1.15M
                                self.insert_use_into_liverange(lr, Use::new(operand, pos, i as u8));
1116
1.15M
                                // If def (not mod), this reg is now dead,
1117
1.15M
                                // scanning backward; make it so.
1118
1.15M
                                if operand.kind() == OperandKind::Def {
1119
                                    // Trim the range for this vreg to start
1120
                                    // at `pos` if it previously ended at the
1121
                                    // start of this block (i.e. was not
1122
                                    // merged into some larger LiveRange due
1123
                                    // to out-of-order blocks).
1124
1.15M
                                    if self.ranges[lr.index()].range.from
1125
1.15M
                                        == self.cfginfo.block_entry[block.index()]
1126
                                    {
1127
684k
                                        trace!(" -> started at block start; trimming to {:?}", pos);
1128
684k
                                        self.ranges[lr.index()].range.from = pos;
1129
466k
                                    }
1130
1131
1.15M
                                    self.ranges[lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
1132
1.15M
1133
1.15M
                                    // Remove from live-set.
1134
1.15M
                                    live.set(operand.vreg().vreg(), false);
1135
1.15M
                                    vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid();
1136
0
                                }
1137
                            }
1138
                            OperandKind::Use => {
1139
                                // Create/extend the LiveRange if it
1140
                                // doesn't already exist, and add the use
1141
                                // to the range.
1142
1.00M
                                let mut lr = vreg_ranges[operand.vreg().vreg()];
1143
1.00M
                                if !live.get(operand.vreg().vreg()) {
1144
680k
                                    let range = CodeRange {
1145
680k
                                        from: self.cfginfo.block_entry[block.index()],
1146
680k
                                        to: pos.next(),
1147
680k
                                    };
1148
680k
                                    lr = self.add_liverange_to_vreg(
1149
680k
                                        VRegIndex::new(operand.vreg().vreg()),
1150
680k
                                        range,
1151
680k
                                    );
1152
680k
                                    vreg_ranges[operand.vreg().vreg()] = lr;
1153
680k
                                }
1154
1.00M
                                debug_assert!(lr.is_valid());
1155
1156
1.00M
                                trace!("Use of {:?} at {:?} -> {:?}", operand, pos, lr,);
1157
1158
1.00M
                                self.insert_use_into_liverange(lr, Use::new(operand, pos, i as u8));
1159
1.00M
1160
1.00M
                                // Add to live-set.
1161
1.00M
                                live.set(operand.vreg().vreg(), true);
1162
                            }
1163
                        }
1164
                    }
1165
                }
1166
1167
1.27M
                if self.func.requires_refs_on_stack(inst) {
1168
166k
                    trace!("inst{} is safepoint", inst.index());
1169
166k
                    self.safepoints.push(inst);
1170
342k
                    for vreg in live.iter() {
1171
342k
                        if let Some(safepoints) = self.safepoints_per_vreg.get_mut(&vreg) {
1172
0
                            trace!("vreg v{} live at safepoint inst{}", vreg, inst.index());
1173
0
                            safepoints.insert(inst);
1174
342k
                        }
1175
                    }
1176
1.10M
                }
1177
            }
1178
1179
            // Block parameters define vregs at the very beginning of
1180
            // the block. Remove their live vregs from the live set
1181
            // here.
1182
510k
            for vreg in self.func.block_params(block) {
1183
510k
                if live.get(vreg.vreg()) {
1184
208
                    live.set(vreg.vreg(), false);
1185
510k
                } else {
1186
510k
                    // Create trivial liverange if blockparam is dead.
1187
510k
                    let start = self.cfginfo.block_entry[block.index()];
1188
510k
                    self.add_liverange_to_vreg(
1189
510k
                        VRegIndex::new(vreg.vreg()),
1190
510k
                        CodeRange {
1191
510k
                            from: start,
1192
510k
                            to: start.next(),
1193
510k
                        },
1194
510k
                    );
1195
510k
                }
1196
                // add `blockparam_ins` entries.
1197
510k
                let vreg_idx = VRegIndex::new(vreg.vreg());
1198
510k
                for &pred in self.func.block_preds(block) {
1199
330
                    self.blockparam_ins.push(BlockparamIn {
1200
330
                        to_vreg: vreg_idx,
1201
330
                        to_block: block,
1202
330
                        from_block: pred,
1203
330
                    });
1204
330
                }
1205
            }
1206
        }
1207
1208
139k
        self.safepoints.sort_unstable();
1209
1210
        // Make ranges in each vreg and uses in each range appear in
1211
        // sorted order. We built them in reverse order above, so this
1212
        // is a simple reversal, *not* a full sort.
1213
        //
1214
        // The ordering invariant is always maintained for uses and
1215
        // always for ranges in bundles (which are initialized later),
1216
        // but not always for ranges in vregs; those are sorted only
1217
        // when needed, here and then again at the end of allocation
1218
        // when resolving moves.
1219
1220
19.8M
        for vreg in &mut self.vregs {
1221
19.7M
            vreg.ranges.reverse();
1222
19.7M
            let mut last = None;
1223
20.9M
            for entry in &mut vreg.ranges {
1224
                // Ranges may have been truncated above at defs. We
1225
                // need to update with the final range here.
1226
1.23M
                entry.range = self.ranges[entry.index.index()].range;
1227
1.23M
                // Assert in-order and non-overlapping.
1228
1.23M
                debug_assert!(last.is_none() || last.unwrap() <= entry.range.from);
1229
1.23M
                last = Some(entry.range.to);
1230
            }
1231
        }
1232
1233
1.23M
        for range in 0..self.ranges.len() {
1234
1.23M
            self.ranges[range].uses.reverse();
1235
1.23M
            debug_assert!(self.ranges[range]
1236
0
                .uses
1237
0
                .windows(2)
1238
0
                .all(|win| win[0].pos <= win[1].pos));
1239
        }
1240
1241
        // Insert safepoint virtual stack uses, if needed.
1242
139k
        for &vreg in self.func.reftype_vregs() {
1243
0
            if self.func.is_pinned_vreg(vreg).is_some() {
1244
0
                continue;
1245
0
            }
1246
0
            let vreg = VRegIndex::new(vreg.vreg());
1247
0
            let mut inserted = false;
1248
0
            let mut safepoint_idx = 0;
1249
0
            for range_idx in 0..self.vregs[vreg.index()].ranges.len() {
1250
0
                let LiveRangeListEntry { range, index } =
1251
0
                    self.vregs[vreg.index()].ranges[range_idx];
1252
0
                while safepoint_idx < self.safepoints.len()
1253
0
                    && ProgPoint::before(self.safepoints[safepoint_idx]) < range.from
1254
0
                {
1255
0
                    safepoint_idx += 1;
1256
0
                }
1257
0
                while safepoint_idx < self.safepoints.len()
1258
0
                    && range.contains_point(ProgPoint::before(self.safepoints[safepoint_idx]))
1259
                {
1260
                    // Create a virtual use.
1261
0
                    let pos = ProgPoint::before(self.safepoints[safepoint_idx]);
1262
0
                    let operand = Operand::new(
1263
0
                        self.vreg(vreg),
1264
0
                        OperandConstraint::Stack,
1265
0
                        OperandKind::Use,
1266
0
                        OperandPos::Early,
1267
0
                    );
1268
0
1269
0
                    trace!(
1270
0
                        "Safepoint-induced stack use of {:?} at {:?} -> {:?}",
1271
                        operand,
1272
                        pos,
1273
                        index,
1274
                    );
1275
1276
0
                    self.insert_use_into_liverange(index, Use::new(operand, pos, SLOT_NONE));
1277
0
                    safepoint_idx += 1;
1278
0
1279
0
                    inserted = true;
1280
                }
1281
1282
0
                if inserted {
1283
0
                    self.ranges[index.index()]
1284
0
                        .uses
1285
0
                        .sort_unstable_by_key(|u| u.pos);
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#0}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#0}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#0}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::build_liveranges::{closure#0}
1286
0
                }
1287
1288
0
                if safepoint_idx >= self.safepoints.len() {
1289
0
                    break;
1290
0
                }
1291
            }
1292
        }
1293
1294
139k
        self.blockparam_ins.sort_unstable_by_key(|x| x.key());
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#1}
Line
Count
Source
1294
1.29k
        self.blockparam_ins.sort_unstable_by_key(|x| x.key());
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#1}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#1}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::build_liveranges::{closure#1}
1295
139k
        self.blockparam_outs.sort_unstable_by_key(|x| x.key());
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#2}
Line
Count
Source
1295
1.42k
        self.blockparam_outs.sort_unstable_by_key(|x| x.key());
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#2}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#2}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::build_liveranges::{closure#2}
1296
139k
        self.prog_move_srcs.sort_unstable_by_key(|(pos, _)| *pos);
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#3}
Line
Count
Source
1296
4.39k
        self.prog_move_srcs.sort_unstable_by_key(|(pos, _)| *pos);
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#3}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#3}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::build_liveranges::{closure#3}
1297
139k
        self.prog_move_dsts.sort_unstable_by_key(|(pos, _)| *pos);
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#4}
Line
Count
Source
1297
4.39k
        self.prog_move_dsts.sort_unstable_by_key(|(pos, _)| *pos);
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#4}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::build_liveranges::{closure#4}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::build_liveranges::{closure#4}
1298
139k
1299
139k
        trace!("prog_move_srcs = {:?}", self.prog_move_srcs);
1300
139k
        trace!("prog_move_dsts = {:?}", self.prog_move_dsts);
1301
1302
139k
        self.stats.initial_liverange_count = self.ranges.len();
1303
139k
        self.stats.blockparam_ins_count = self.blockparam_ins.len();
1304
139k
        self.stats.blockparam_outs_count = self.blockparam_outs.len();
1305
139k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::build_liveranges
Line
Count
Source
420
139k
    pub fn build_liveranges(&mut self) {
421
139k
        for &vreg in self.func.reftype_vregs() {
422
0
            self.safepoints_per_vreg.insert(vreg.vreg(), HashSet::new());
423
0
        }
424
425
        // Create Uses and Defs referring to VRegs, and place the Uses
426
        // in LiveRanges.
427
        //
428
        // We already computed precise liveouts and liveins for every
429
        // block above, so we don't need to run an iterative algorithm
430
        // here; instead, every block's computation is purely local,
431
        // from end to start.
432
433
        // Track current LiveRange for each vreg.
434
        //
435
        // Invariant: a stale range may be present here; ranges are
436
        // only valid if `live.get(vreg)` is true.
437
139k
        let mut vreg_ranges: Vec<LiveRangeIndex> =
438
139k
            vec![LiveRangeIndex::invalid(); self.func.num_vregs()];
439
440
336k
        for i in (0..self.func.num_blocks()).rev() {
441
336k
            let block = Block::new(i);
442
336k
            let insns = self.func.block_insns(block);
443
336k
444
336k
            self.stats.livein_blocks += 1;
445
336k
446
336k
            // Init our local live-in set.
447
336k
            let mut live = self.liveouts[block.index()].clone();
448
336k
449
336k
            // If the last instruction is a branch (rather than
450
336k
            // return), create blockparam_out entries.
451
336k
            if self.func.is_branch(insns.last()) {
452
204k
                for (i, &succ) in self.func.block_succs(block).iter().enumerate() {
453
204k
                    let blockparams_in = self.func.block_params(succ);
454
204k
                    let blockparams_out = self.func.branch_blockparams(block, insns.last(), i);
455
330
                    for (&blockparam_in, &blockparam_out) in
456
204k
                        blockparams_in.iter().zip(blockparams_out)
457
330
                    {
458
330
                        let blockparam_out = VRegIndex::new(blockparam_out.vreg());
459
330
                        let blockparam_in = VRegIndex::new(blockparam_in.vreg());
460
330
                        self.blockparam_outs.push(BlockparamOut {
461
330
                            to_vreg: blockparam_in,
462
330
                            to_block: succ,
463
330
                            from_block: block,
464
330
                            from_vreg: blockparam_out,
465
330
                        });
466
330
467
330
                        // Include outgoing blockparams in the initial live set.
468
330
                        live.set(blockparam_out.index(), true);
469
330
                    }
470
                }
471
161k
            }
472
473
            // Initially, registers are assumed live for the whole block.
474
336k
            for vreg in live.iter() {
475
119k
                let range = CodeRange {
476
119k
                    from: self.cfginfo.block_entry[block.index()],
477
119k
                    to: self.cfginfo.block_exit[block.index()].next(),
478
119k
                };
479
119k
                trace!(
480
0
                    "vreg {:?} live at end of block --> create range {:?}",
481
0
                    VRegIndex::new(vreg),
482
                    range
483
                );
484
119k
                let lr = self.add_liverange_to_vreg(VRegIndex::new(vreg), range);
485
119k
                vreg_ranges[vreg] = lr;
486
            }
487
488
            // Create vreg data for blockparams.
489
510k
            for &param in self.func.block_params(block) {
490
510k
                self.vregs[param.vreg()].blockparam = block;
491
510k
            }
492
493
            // For each instruction, in reverse order, process
494
            // operands and clobbers.
495
1.27M
            for inst in insns.rev().iter() {
496
                // Mark clobbers with CodeRanges on PRegs.
497
2.56M
                for clobber in self.func.inst_clobbers(inst) {
498
2.56M
                    // Clobber range is at After point only: an
499
2.56M
                    // instruction can still take an input in a reg
500
2.56M
                    // that it later clobbers. (In other words, the
501
2.56M
                    // clobber is like a normal def that never gets
502
2.56M
                    // used.)
503
2.56M
                    let range = CodeRange {
504
2.56M
                        from: ProgPoint::after(inst),
505
2.56M
                        to: ProgPoint::before(inst.next()),
506
2.56M
                    };
507
2.56M
                    self.add_liverange_to_preg(range, clobber);
508
2.56M
                }
509
510
                // Does the instruction have any input-reusing
511
                // outputs? This is important below to establish
512
                // proper interference wrt other inputs. We note the
513
                // *vreg* that is reused, not the index.
514
1.27M
                let mut reused_input = None;
515
2.14M
                for op in self.func.inst_operands(inst) {
516
2.14M
                    if let OperandConstraint::Reuse(i) = op.constraint() {
517
100k
                        debug_assert!(self.func.inst_operands(inst)[i]
518
0
                            .as_fixed_nonallocatable()
519
0
                            .is_none());
520
100k
                        reused_input = Some(self.func.inst_operands(inst)[i].vreg());
521
100k
                        break;
522
2.04M
                    }
523
                }
524
525
                // If this is a move, handle specially.
526
1.27M
                if let Some((src, dst)) = self.func.is_move(inst) {
527
                    // We can completely skip the move if it is
528
                    // trivial (vreg to same vreg).
529
2.85k
                    if src.vreg() != dst.vreg() {
530
2.85k
                        trace!(" -> move inst{}: src {} -> dst {}", inst.index(), src, dst);
531
532
2.85k
                        debug_assert_eq!(src.class(), dst.class());
533
2.85k
                        debug_assert_eq!(src.kind(), OperandKind::Use);
534
2.85k
                        debug_assert_eq!(src.pos(), OperandPos::Early);
535
2.85k
                        debug_assert_eq!(dst.kind(), OperandKind::Def);
536
2.85k
                        debug_assert_eq!(dst.pos(), OperandPos::Late);
537
538
2.85k
                        let src_pinned = self.func.is_pinned_vreg(src.vreg());
539
2.85k
                        let dst_pinned = self.func.is_pinned_vreg(dst.vreg());
540
2.85k
541
2.85k
                        match (src_pinned, dst_pinned) {
542
                            // If both src and dest are pinned, emit
543
                            // the move right here, right now.
544
0
                            (Some(src_preg), Some(dst_preg)) => {
545
0
                                // Update LRs.
546
0
                                if !live.get(src.vreg().vreg()) {
547
0
                                    let lr = self.add_liverange_to_vreg(
548
0
                                        VRegIndex::new(src.vreg().vreg()),
549
0
                                        CodeRange {
550
0
                                            from: self.cfginfo.block_entry[block.index()],
551
0
                                            to: ProgPoint::after(inst),
552
0
                                        },
553
0
                                    );
554
0
                                    live.set(src.vreg().vreg(), true);
555
0
                                    vreg_ranges[src.vreg().vreg()] = lr;
556
0
                                }
557
0
                                if live.get(dst.vreg().vreg()) {
558
0
                                    let lr = vreg_ranges[dst.vreg().vreg()];
559
0
                                    self.ranges[lr.index()].range.from = ProgPoint::after(inst);
560
0
                                    live.set(dst.vreg().vreg(), false);
561
0
                                } else {
562
0
                                    self.add_liverange_to_vreg(
563
0
                                        VRegIndex::new(dst.vreg().vreg()),
564
0
                                        CodeRange {
565
0
                                            from: ProgPoint::after(inst),
566
0
                                            to: ProgPoint::before(inst.next()),
567
0
                                        },
568
0
                                    );
569
0
                                }
570
571
0
                                self.insert_move(
572
0
                                    ProgPoint::before(inst),
573
0
                                    InsertMovePrio::MultiFixedRegInitial,
574
0
                                    Allocation::reg(src_preg),
575
0
                                    Allocation::reg(dst_preg),
576
0
                                    dst.vreg(),
577
0
                                );
578
                            }
579
580
                            // If exactly one of source and dest (but
581
                            // not both) is a pinned-vreg, convert
582
                            // this into a ghost use on the other vreg
583
                            // with a FixedReg constraint.
584
0
                            (Some(preg), None) | (None, Some(preg)) => {
585
0
                                trace!(
586
0
                                    " -> exactly one of src/dst is pinned; converting to ghost use"
587
                                );
588
0
                                let (vreg, pinned_vreg, kind, pos, progpoint) =
589
0
                                    if src_pinned.is_some() {
590
                                        // Source is pinned: this is a def on the dst with a pinned preg.
591
0
                                        (
592
0
                                            dst.vreg(),
593
0
                                            src.vreg(),
594
0
                                            OperandKind::Def,
595
0
                                            OperandPos::Late,
596
0
                                            ProgPoint::before(inst),
597
0
                                        )
598
                                    } else {
599
                                        // Dest is pinned: this is a use on the src with a pinned preg.
600
0
                                        (
601
0
                                            src.vreg(),
602
0
                                            dst.vreg(),
603
0
                                            OperandKind::Use,
604
0
                                            OperandPos::Early,
605
0
                                            ProgPoint::after(inst),
606
0
                                        )
607
                                    };
608
0
                                let constraint = OperandConstraint::FixedReg(preg);
609
0
                                let operand = Operand::new(vreg, constraint, kind, pos);
610
0
611
0
                                trace!(
612
0
                                    concat!(
613
0
                                        " -> preg {:?} vreg {:?} kind {:?} ",
614
0
                                        "pos {:?} progpoint {:?} constraint {:?} operand {:?}"
615
0
                                    ),
616
                                    preg,
617
                                    vreg,
618
                                    kind,
619
                                    pos,
620
                                    progpoint,
621
                                    constraint,
622
                                    operand
623
                                );
624
625
                                // Get the LR for the vreg; if none, create one.
626
0
                                let mut lr = vreg_ranges[vreg.vreg()];
627
0
                                if !live.get(vreg.vreg()) {
628
0
                                    let from = match kind {
629
0
                                        OperandKind::Use => self.cfginfo.block_entry[block.index()],
630
0
                                        OperandKind::Def => progpoint,
631
0
                                        _ => unreachable!(),
632
                                    };
633
0
                                    let to = progpoint.next();
634
0
                                    lr = self.add_liverange_to_vreg(
635
0
                                        VRegIndex::new(vreg.vreg()),
636
0
                                        CodeRange { from, to },
637
0
                                    );
638
0
                                    trace!("   -> dead; created LR");
639
0
                                }
640
0
                                trace!("  -> LR {:?}", lr);
641
642
0
                                self.insert_use_into_liverange(
643
0
                                    lr,
644
0
                                    Use::new(operand, progpoint, SLOT_NONE),
645
0
                                );
646
0
647
0
                                if kind == OperandKind::Def {
648
0
                                    live.set(vreg.vreg(), false);
649
0
                                    if self.ranges[lr.index()].range.from
650
0
                                        == self.cfginfo.block_entry[block.index()]
651
0
                                    {
652
0
                                        self.ranges[lr.index()].range.from = progpoint;
653
0
                                    }
654
0
                                    self.ranges[lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
655
0
                                } else {
656
0
                                    live.set(vreg.vreg(), true);
657
0
                                    vreg_ranges[vreg.vreg()] = lr;
658
0
                                }
659
660
                                // Handle liveness of the other vreg. Note
661
                                // that this is somewhat special. For the
662
                                // destination case, we want the pinned
663
                                // vreg's LR to start just *after* the
664
                                // operand we inserted above, because
665
                                // otherwise it would overlap, and
666
                                // interfere, and prevent allocation. For
667
                                // the source case, we want to "poke a
668
                                // hole" in the LR: if it's live going
669
                                // downward, end it just after the operand
670
                                // and restart it before; if it isn't
671
                                // (this is the last use), start it
672
                                // before.
673
0
                                if kind == OperandKind::Def {
674
0
                                    trace!(" -> src on pinned vreg {:?}", pinned_vreg);
675
                                    // The *other* vreg is a def, so the pinned-vreg
676
                                    // mention is a use. If already live,
677
                                    // end the existing LR just *after*
678
                                    // the `progpoint` defined above and
679
                                    // start a new one just *before* the
680
                                    // `progpoint` defined above,
681
                                    // preserving the start. If not, start
682
                                    // a new one live back to the top of
683
                                    // the block, starting just before
684
                                    // `progpoint`.
685
0
                                    if live.get(pinned_vreg.vreg()) {
686
0
                                        let pinned_lr = vreg_ranges[pinned_vreg.vreg()];
687
0
                                        let orig_start = self.ranges[pinned_lr.index()].range.from;
688
0
                                        // Following instruction start
689
0
                                        // (so we don't transition in
690
0
                                        // middle of inst).
691
0
                                        let new_start = ProgPoint::before(progpoint.inst().next());
692
0
                                        trace!(
693
0
                                            " -> live with LR {:?}; truncating to start at {:?}",
694
                                            pinned_lr,
695
                                            new_start,
696
                                        );
697
0
                                        self.ranges[pinned_lr.index()].range.from = new_start;
698
0
699
0
                                        let new_lr = self.add_liverange_to_vreg(
700
0
                                            VRegIndex::new(pinned_vreg.vreg()),
701
0
                                            CodeRange {
702
0
                                                from: orig_start,
703
0
                                                to: progpoint,
704
0
                                            },
705
0
                                        );
706
0
                                        vreg_ranges[pinned_vreg.vreg()] = new_lr;
707
0
                                        trace!(" -> created LR {:?} with remaining range from {:?} to {:?}", new_lr, orig_start, progpoint);
708
709
                                        // Add an edit right now to indicate that at
710
                                        // this program point, the given
711
                                        // preg is now known as that vreg,
712
                                        // not the preg, but immediately
713
                                        // after, it is known as the preg
714
                                        // again. This is used by the
715
                                        // checker.
716
0
                                        self.insert_move(
717
0
                                            ProgPoint::after(inst),
718
0
                                            InsertMovePrio::Regular,
719
0
                                            Allocation::reg(preg),
720
0
                                            Allocation::reg(preg),
721
0
                                            dst.vreg(),
722
0
                                        );
723
0
                                        self.insert_move(
724
0
                                            ProgPoint::before(inst.next()),
725
0
                                            InsertMovePrio::MultiFixedRegInitial,
726
0
                                            Allocation::reg(preg),
727
0
                                            Allocation::reg(preg),
728
0
                                            src.vreg(),
729
0
                                        );
730
                                    } else {
731
0
                                        if inst > self.cfginfo.block_entry[block.index()].inst() {
732
0
                                            let new_lr = self.add_liverange_to_vreg(
733
0
                                                VRegIndex::new(pinned_vreg.vreg()),
734
0
                                                CodeRange {
735
0
                                                    from: self.cfginfo.block_entry[block.index()],
736
0
                                                    to: progpoint,
737
0
                                                },
738
0
                                            );
739
0
                                            vreg_ranges[pinned_vreg.vreg()] = new_lr;
740
0
                                            live.set(pinned_vreg.vreg(), true);
741
0
                                            trace!(" -> was not live; created new LR {:?}", new_lr);
742
0
                                        }
743
744
                                        // Add an edit right now to indicate that at
745
                                        // this program point, the given
746
                                        // preg is now known as that vreg,
747
                                        // not the preg. This is used by
748
                                        // the checker.
749
0
                                        self.insert_move(
750
0
                                            ProgPoint::after(inst),
751
0
                                            InsertMovePrio::BlockParam,
752
0
                                            Allocation::reg(preg),
753
0
                                            Allocation::reg(preg),
754
0
                                            dst.vreg(),
755
0
                                        );
756
                                    }
757
                                } else {
758
0
                                    trace!(" -> dst on pinned vreg {:?}", pinned_vreg);
759
                                    // The *other* vreg is a use, so the pinned-vreg
760
                                    // mention is a def. Truncate its LR
761
                                    // just *after* the `progpoint`
762
                                    // defined above.
763
0
                                    if live.get(pinned_vreg.vreg()) {
764
0
                                        let pinned_lr = vreg_ranges[pinned_vreg.vreg()];
765
0
                                        self.ranges[pinned_lr.index()].range.from =
766
0
                                            progpoint.next();
767
0
                                        trace!(
768
0
                                            " -> was live with LR {:?}; truncated start to {:?}",
769
0
                                            pinned_lr,
770
0
                                            progpoint.next()
771
                                        );
772
0
                                        live.set(pinned_vreg.vreg(), false);
773
0
774
0
                                        // Add a no-op edit right now to indicate that
775
0
                                        // at this program point, the
776
0
                                        // given preg is now known as that
777
0
                                        // preg, not the vreg. This is
778
0
                                        // used by the checker.
779
0
                                        self.insert_move(
780
0
                                            ProgPoint::before(inst.next()),
781
0
                                            InsertMovePrio::PostRegular,
782
0
                                            Allocation::reg(preg),
783
0
                                            Allocation::reg(preg),
784
0
                                            dst.vreg(),
785
0
                                        );
786
0
                                    }
787
                                    // Otherwise, if dead, no need to create
788
                                    // a dummy LR -- there is no
789
                                    // reservation to make (the other vreg
790
                                    // will land in the reg with the
791
                                    // fixed-reg operand constraint, but
792
                                    // it's a dead move anyway).
793
                                }
794
                            }
795
796
                            // Ordinary move between two non-pinned vregs.
797
                            (None, None) => {
798
                                // Redefine src and dst operands to have
799
                                // positions of After and Before respectively
800
                                // (see note below), and to have Any
801
                                // constraints if they were originally Reg.
802
2.85k
                                let src_constraint = match src.constraint() {
803
2.85k
                                    OperandConstraint::Reg => OperandConstraint::Any,
804
0
                                    x => x,
805
                                };
806
2.85k
                                let dst_constraint = match dst.constraint() {
807
2.85k
                                    OperandConstraint::Reg => OperandConstraint::Any,
808
0
                                    x => x,
809
                                };
810
2.85k
                                let src = Operand::new(
811
2.85k
                                    src.vreg(),
812
2.85k
                                    src_constraint,
813
2.85k
                                    OperandKind::Use,
814
2.85k
                                    OperandPos::Late,
815
2.85k
                                );
816
2.85k
                                let dst = Operand::new(
817
2.85k
                                    dst.vreg(),
818
2.85k
                                    dst_constraint,
819
2.85k
                                    OperandKind::Def,
820
2.85k
                                    OperandPos::Early,
821
2.85k
                                );
822
2.85k
823
2.85k
                                if self.annotations_enabled {
824
0
                                    self.annotate(
825
0
                                        ProgPoint::after(inst),
826
0
                                        format!(
827
0
                                            " prog-move v{} ({:?}) -> v{} ({:?})",
828
0
                                            src.vreg().vreg(),
829
0
                                            src_constraint,
830
0
                                            dst.vreg().vreg(),
831
0
                                            dst_constraint,
832
0
                                        ),
833
0
                                    );
834
2.85k
                                }
835
836
                                // N.B.: in order to integrate with the move
837
                                // resolution that joins LRs in general, we
838
                                // conceptually treat the move as happening
839
                                // between the move inst's After and the next
840
                                // inst's Before. Thus the src LR goes up to
841
                                // (exclusive) next-inst-pre, and the dst LR
842
                                // starts at next-inst-pre. We have to take
843
                                // care in our move insertion to handle this
844
                                // like other inter-inst moves, i.e., at
845
                                // `Regular` priority, so it properly happens
846
                                // in parallel with other inter-LR moves.
847
                                //
848
                                // Why the progpoint between move and next
849
                                // inst, and not the progpoint between prev
850
                                // inst and move? Because a move can be the
851
                                // first inst in a block, but cannot be the
852
                                // last; so the following progpoint is always
853
                                // within the same block, while the previous
854
                                // one may be an inter-block point (and the
855
                                // After of the prev inst in a different
856
                                // block).
857
858
                                // Handle the def w.r.t. liveranges: trim the
859
                                // start of the range and mark it dead at this
860
                                // point in our backward scan.
861
2.85k
                                let pos = ProgPoint::before(inst.next());
862
2.85k
                                let mut dst_lr = vreg_ranges[dst.vreg().vreg()];
863
2.85k
                                if !live.get(dst.vreg().vreg()) {
864
730
                                    let from = pos;
865
730
                                    let to = pos.next();
866
730
                                    dst_lr = self.add_liverange_to_vreg(
867
730
                                        VRegIndex::new(dst.vreg().vreg()),
868
730
                                        CodeRange { from, to },
869
730
                                    );
870
730
                                    trace!(" -> invalid LR for def; created {:?}", dst_lr);
871
2.12k
                                }
872
2.85k
                                trace!(" -> has existing LR {:?}", dst_lr);
873
                                // Trim the LR to start here.
874
2.85k
                                if self.ranges[dst_lr.index()].range.from
875
2.85k
                                    == self.cfginfo.block_entry[block.index()]
876
                                {
877
2.12k
                                    trace!(" -> started at block start; trimming to {:?}", pos);
878
2.12k
                                    self.ranges[dst_lr.index()].range.from = pos;
879
730
                                }
880
2.85k
                                self.ranges[dst_lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
881
2.85k
                                live.set(dst.vreg().vreg(), false);
882
2.85k
                                vreg_ranges[dst.vreg().vreg()] = LiveRangeIndex::invalid();
883
2.85k
884
2.85k
                                // Handle the use w.r.t. liveranges: make it live
885
2.85k
                                // and create an initial LR back to the start of
886
2.85k
                                // the block.
887
2.85k
                                let pos = ProgPoint::after(inst);
888
2.85k
                                let src_lr = if !live.get(src.vreg().vreg()) {
889
2.85k
                                    let range = CodeRange {
890
2.85k
                                        from: self.cfginfo.block_entry[block.index()],
891
2.85k
                                        to: pos.next(),
892
2.85k
                                    };
893
2.85k
                                    let src_lr = self.add_liverange_to_vreg(
894
2.85k
                                        VRegIndex::new(src.vreg().vreg()),
895
2.85k
                                        range,
896
2.85k
                                    );
897
2.85k
                                    vreg_ranges[src.vreg().vreg()] = src_lr;
898
2.85k
                                    src_lr
899
                                } else {
900
0
                                    vreg_ranges[src.vreg().vreg()]
901
                                };
902
903
2.85k
                                trace!(" -> src LR {:?}", src_lr);
904
905
                                // Add to live-set.
906
2.85k
                                let src_is_dead_after_move = !live.get(src.vreg().vreg());
907
2.85k
                                live.set(src.vreg().vreg(), true);
908
2.85k
909
2.85k
                                // Add to program-moves lists.
910
2.85k
                                self.prog_move_srcs.push((
911
2.85k
                                    (VRegIndex::new(src.vreg().vreg()), inst),
912
2.85k
                                    Allocation::none(),
913
2.85k
                                ));
914
2.85k
                                self.prog_move_dsts.push((
915
2.85k
                                    (VRegIndex::new(dst.vreg().vreg()), inst.next()),
916
2.85k
                                    Allocation::none(),
917
2.85k
                                ));
918
2.85k
                                self.stats.prog_moves += 1;
919
2.85k
                                if src_is_dead_after_move {
920
2.85k
                                    self.stats.prog_moves_dead_src += 1;
921
2.85k
                                    self.prog_move_merges.push((src_lr, dst_lr));
922
2.85k
                                }
923
                            }
924
                        }
925
0
                    }
926
927
2.85k
                    continue;
928
1.27M
                }
929
1.27M
930
1.27M
                // Preprocess defs and uses. Specifically, if there
931
1.27M
                // are any fixed-reg-constrained defs at Late position
932
1.27M
                // and fixed-reg-constrained uses at Early position
933
1.27M
                // with the same preg, we need to (i) add a fixup move
934
1.27M
                // for the use, (ii) rewrite the use to have an Any
935
1.27M
                // constraint, and (ii) move the def to Early position
936
1.27M
                // to reserve the register for the whole instruction.
937
1.27M
                let mut operand_rewrites: FxHashMap<usize, Operand> = FxHashMap::default();
938
1.27M
                let mut late_def_fixed: SmallVec<[PReg; 8]> = smallvec![];
939
2.16M
                for &operand in self.func.inst_operands(inst) {
940
2.16M
                    if let OperandConstraint::FixedReg(preg) = operand.constraint() {
941
713k
                        match operand.pos() {
942
                            OperandPos::Late => {
943
                                // See note in fuzzing/func.rs: we
944
                                // can't allow this, because there
945
                                // would be no way to move a value
946
                                // into place for a late use *after*
947
                                // the early point (i.e. in the middle
948
                                // of the instruction).
949
494k
                                assert!(
950
494k
                                    operand.kind() == OperandKind::Def,
951
494k
                                    "Invalid operand: fixed constraint on Use/Mod at Late point"
952
494k
                                );
953
954
494k
                                late_def_fixed.push(preg);
955
                            }
956
219k
                            _ => {}
957
                        }
958
1.44M
                    }
959
                }
960
2.16M
                for (i, &operand) in self.func.inst_operands(inst).iter().enumerate() {
961
2.16M
                    if operand.as_fixed_nonallocatable().is_some() {
962
4.93k
                        continue;
963
2.15M
                    }
964
2.15M
                    if let OperandConstraint::FixedReg(preg) = operand.constraint() {
965
708k
                        match operand.pos() {
966
214k
                            OperandPos::Early if live.get(operand.vreg().vreg()) => {
967
43.6k
                                assert!(operand.kind() == OperandKind::Use,
968
43.6k
                                            "Invalid operand: fixed constraint on Def/Mod at Early position");
969
970
                                // If we have a constraint at the
971
                                // Early point for a fixed preg, and
972
                                // this preg is also constrained with
973
                                // a *separate* def at Late or is
974
                                // clobbered, and *if* the vreg is
975
                                // live downward, we have to use the
976
                                // multi-fixed-reg mechanism for a
977
                                // fixup and rewrite here without the
978
                                // constraint. See #53.
979
                                //
980
                                // We adjust the def liverange and Use
981
                                // to an "early" position to reserve
982
                                // the register, it still must not be
983
                                // used by some other vreg at the
984
                                // use-site.
985
                                //
986
                                // Note that we handle multiple
987
                                // conflicting constraints for the
988
                                // same vreg in a separate pass (see
989
                                // `fixup_multi_fixed_vregs` below).
990
43.6k
                                if late_def_fixed.contains(&preg)
991
43.3k
                                    || self.func.inst_clobbers(inst).contains(preg)
992
                                {
993
43.2k
                                    log::trace!(
994
0
                                        concat!(
995
0
                                            "-> operand {:?} is fixed to preg {:?}, ",
996
0
                                            "is downward live, and there is also a ",
997
0
                                            "def or clobber at this preg"
998
0
                                        ),
999
                                        operand,
1000
                                        preg
1001
                                    );
1002
43.2k
                                    let pos = ProgPoint::before(inst);
1003
43.2k
                                    self.multi_fixed_reg_fixups.push(MultiFixedRegFixup {
1004
43.2k
                                        pos,
1005
43.2k
                                        from_slot: i as u8,
1006
43.2k
                                        to_slot: i as u8,
1007
43.2k
                                        to_preg: PRegIndex::new(preg.index()),
1008
43.2k
                                        vreg: VRegIndex::new(operand.vreg().vreg()),
1009
43.2k
                                        level: FixedRegFixupLevel::Initial,
1010
43.2k
                                    });
1011
43.2k
1012
43.2k
                                    // We need to insert a reservation
1013
43.2k
                                    // at the before-point to reserve
1014
43.2k
                                    // the reg for the use too.
1015
43.2k
                                    let range = CodeRange::singleton(pos);
1016
43.2k
                                    self.add_liverange_to_preg(range, preg);
1017
43.2k
1018
43.2k
                                    // Remove the fixed-preg
1019
43.2k
                                    // constraint from the Use.
1020
43.2k
                                    operand_rewrites.insert(
1021
43.2k
                                        i,
1022
43.2k
                                        Operand::new(
1023
43.2k
                                            operand.vreg(),
1024
43.2k
                                            OperandConstraint::Any,
1025
43.2k
                                            operand.kind(),
1026
43.2k
                                            operand.pos(),
1027
43.2k
                                        ),
1028
43.2k
                                    );
1029
446
                                }
1030
                            }
1031
664k
                            _ => {}
1032
                        }
1033
1.44M
                    }
1034
                }
1035
1036
                // Process defs and uses.
1037
3.81M
                for &cur_pos in &[InstPosition::After, InstPosition::Before] {
1038
4.32M
                    for i in 0..self.func.inst_operands(inst).len() {
1039
                        // don't borrow `self`
1040
4.32M
                        let operand = operand_rewrites
1041
4.32M
                            .get(&i)
1042
4.32M
                            .cloned()
1043
4.32M
                            .unwrap_or(self.func.inst_operands(inst)[i]);
1044
4.32M
                        let pos = match (operand.kind(), operand.pos()) {
1045
0
                            (OperandKind::Mod, _) => ProgPoint::before(inst),
1046
224k
                            (OperandKind::Def, OperandPos::Early) => ProgPoint::before(inst),
1047
2.07M
                            (OperandKind::Def, OperandPos::Late) => ProgPoint::after(inst),
1048
0
                            (OperandKind::Use, OperandPos::Late) => ProgPoint::after(inst),
1049
                            // If there are any reused inputs in this
1050
                            // instruction, and this is *not* the
1051
                            // reused vreg, force `pos` to
1052
                            // `After`. This ensures that we correctly
1053
                            // account for the interference between
1054
                            // the other inputs and the
1055
                            // input-that-is-reused/output.
1056
                            (OperandKind::Use, OperandPos::Early)
1057
2.02M
                                if reused_input.is_some()
1058
253k
                                    && reused_input.unwrap() != operand.vreg() =>
1059
51.8k
                            {
1060
51.8k
                                ProgPoint::after(inst)
1061
                            }
1062
1.97M
                            (OperandKind::Use, OperandPos::Early) => ProgPoint::before(inst),
1063
                        };
1064
1065
4.32M
                        if pos.pos() != cur_pos {
1066
2.16M
                            continue;
1067
2.16M
                        }
1068
2.16M
1069
2.16M
                        trace!(
1070
0
                            "processing inst{} operand at {:?}: {:?}",
1071
0
                            inst.index(),
1072
                            pos,
1073
                            operand
1074
                        );
1075
1076
                        // If this is a "fixed non-allocatable
1077
                        // register" operand, set the alloc
1078
                        // immediately and then ignore the operand
1079
                        // hereafter.
1080
2.16M
                        if let Some(preg) = operand.as_fixed_nonallocatable() {
1081
4.93k
                            self.set_alloc(inst, i, Allocation::reg(preg));
1082
4.93k
                            continue;
1083
2.15M
                        }
1084
2.15M
1085
2.15M
                        match operand.kind() {
1086
                            OperandKind::Def | OperandKind::Mod => {
1087
1.15M
                                trace!("Def of {} at {:?}", operand.vreg(), pos);
1088
1089
                                // Get or create the LiveRange.
1090
1.15M
                                let mut lr = vreg_ranges[operand.vreg().vreg()];
1091
1.15M
                                trace!(" -> has existing LR {:?}", lr);
1092
                                // If there was no liverange (dead def), create a trivial one.
1093
1.15M
                                if !live.get(operand.vreg().vreg()) {
1094
468k
                                    let from = match operand.kind() {
1095
468k
                                        OperandKind::Def => pos,
1096
0
                                        OperandKind::Mod => self.cfginfo.block_entry[block.index()],
1097
0
                                        _ => unreachable!(),
1098
                                    };
1099
                                    // We want to we want to span
1100
                                    // until Before of the next
1101
                                    // inst. This ensures that early
1102
                                    // defs used for temps on an
1103
                                    // instruction are reserved across
1104
                                    // the whole instruction.
1105
468k
                                    let to = ProgPoint::before(pos.inst().next());
1106
468k
                                    lr = self.add_liverange_to_vreg(
1107
468k
                                        VRegIndex::new(operand.vreg().vreg()),
1108
468k
                                        CodeRange { from, to },
1109
468k
                                    );
1110
468k
                                    trace!(" -> invalid; created {:?}", lr);
1111
468k
                                    vreg_ranges[operand.vreg().vreg()] = lr;
1112
468k
                                    live.set(operand.vreg().vreg(), true);
1113
682k
                                }
1114
                                // Create the use in the LiveRange.
1115
1.15M
                                self.insert_use_into_liverange(lr, Use::new(operand, pos, i as u8));
1116
1.15M
                                // If def (not mod), this reg is now dead,
1117
1.15M
                                // scanning backward; make it so.
1118
1.15M
                                if operand.kind() == OperandKind::Def {
1119
                                    // Trim the range for this vreg to start
1120
                                    // at `pos` if it previously ended at the
1121
                                    // start of this block (i.e. was not
1122
                                    // merged into some larger LiveRange due
1123
                                    // to out-of-order blocks).
1124
1.15M
                                    if self.ranges[lr.index()].range.from
1125
1.15M
                                        == self.cfginfo.block_entry[block.index()]
1126
                                    {
1127
684k
                                        trace!(" -> started at block start; trimming to {:?}", pos);
1128
684k
                                        self.ranges[lr.index()].range.from = pos;
1129
466k
                                    }
1130
1131
1.15M
                                    self.ranges[lr.index()].set_flag(LiveRangeFlag::StartsAtDef);
1132
1.15M
1133
1.15M
                                    // Remove from live-set.
1134
1.15M
                                    live.set(operand.vreg().vreg(), false);
1135
1.15M
                                    vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid();
1136
0
                                }
1137
                            }
1138
                            OperandKind::Use => {
1139
                                // Create/extend the LiveRange if it
1140
                                // doesn't already exist, and add the use
1141
                                // to the range.
1142
1.00M
                                let mut lr = vreg_ranges[operand.vreg().vreg()];
1143
1.00M
                                if !live.get(operand.vreg().vreg()) {
1144
680k
                                    let range = CodeRange {
1145
680k
                                        from: self.cfginfo.block_entry[block.index()],
1146
680k
                                        to: pos.next(),
1147
680k
                                    };
1148
680k
                                    lr = self.add_liverange_to_vreg(
1149
680k
                                        VRegIndex::new(operand.vreg().vreg()),
1150
680k
                                        range,
1151
680k
                                    );
1152
680k
                                    vreg_ranges[operand.vreg().vreg()] = lr;
1153
680k
                                }
1154
1.00M
                                debug_assert!(lr.is_valid());
1155
1156
1.00M
                                trace!("Use of {:?} at {:?} -> {:?}", operand, pos, lr,);
1157
1158
1.00M
                                self.insert_use_into_liverange(lr, Use::new(operand, pos, i as u8));
1159
1.00M
1160
1.00M
                                // Add to live-set.
1161
1.00M
                                live.set(operand.vreg().vreg(), true);
1162
                            }
1163
                        }
1164
                    }
1165
                }
1166
1167
1.27M
                if self.func.requires_refs_on_stack(inst) {
1168
166k
                    trace!("inst{} is safepoint", inst.index());
1169
166k
                    self.safepoints.push(inst);
1170
342k
                    for vreg in live.iter() {
1171
342k
                        if let Some(safepoints) = self.safepoints_per_vreg.get_mut(&vreg) {
1172
0
                            trace!("vreg v{} live at safepoint inst{}", vreg, inst.index());
1173
0
                            safepoints.insert(inst);
1174
342k
                        }
1175
                    }
1176
1.10M
                }
1177
            }
1178
1179
            // Block parameters define vregs at the very beginning of
1180
            // the block. Remove their live vregs from the live set
1181
            // here.
1182
510k
            for vreg in self.func.block_params(block) {
1183
510k
                if live.get(vreg.vreg()) {
1184
208
                    live.set(vreg.vreg(), false);
1185
510k
                } else {
1186
510k
                    // Create trivial liverange if blockparam is dead.
1187
510k
                    let start = self.cfginfo.block_entry[block.index()];
1188
510k
                    self.add_liverange_to_vreg(
1189
510k
                        VRegIndex::new(vreg.vreg()),
1190
510k
                        CodeRange {
1191
510k
                            from: start,
1192
510k
                            to: start.next(),
1193
510k
                        },
1194
510k
                    );
1195
510k
                }
1196
                // add `blockparam_ins` entries.
1197
510k
                let vreg_idx = VRegIndex::new(vreg.vreg());
1198
510k
                for &pred in self.func.block_preds(block) {
1199
330
                    self.blockparam_ins.push(BlockparamIn {
1200
330
                        to_vreg: vreg_idx,
1201
330
                        to_block: block,
1202
330
                        from_block: pred,
1203
330
                    });
1204
330
                }
1205
            }
1206
        }
1207
1208
139k
        self.safepoints.sort_unstable();
1209
1210
        // Make ranges in each vreg and uses in each range appear in
1211
        // sorted order. We built them in reverse order above, so this
1212
        // is a simple reversal, *not* a full sort.
1213
        //
1214
        // The ordering invariant is always maintained for uses and
1215
        // always for ranges in bundles (which are initialized later),
1216
        // but not always for ranges in vregs; those are sorted only
1217
        // when needed, here and then again at the end of allocation
1218
        // when resolving moves.
1219
1220
19.8M
        for vreg in &mut self.vregs {
1221
19.7M
            vreg.ranges.reverse();
1222
19.7M
            let mut last = None;
1223
20.9M
            for entry in &mut vreg.ranges {
1224
                // Ranges may have been truncated above at defs. We
1225
                // need to update with the final range here.
1226
1.23M
                entry.range = self.ranges[entry.index.index()].range;
1227
1.23M
                // Assert in-order and non-overlapping.
1228
1.23M
                debug_assert!(last.is_none() || last.unwrap() <= entry.range.from);
1229
1.23M
                last = Some(entry.range.to);
1230
            }
1231
        }
1232
1233
1.23M
        for range in 0..self.ranges.len() {
1234
1.23M
            self.ranges[range].uses.reverse();
1235
1.23M
            debug_assert!(self.ranges[range]
1236
0
                .uses
1237
0
                .windows(2)
1238
0
                .all(|win| win[0].pos <= win[1].pos));
1239
        }
1240
1241
        // Insert safepoint virtual stack uses, if needed.
1242
139k
        for &vreg in self.func.reftype_vregs() {
1243
0
            if self.func.is_pinned_vreg(vreg).is_some() {
1244
0
                continue;
1245
0
            }
1246
0
            let vreg = VRegIndex::new(vreg.vreg());
1247
0
            let mut inserted = false;
1248
0
            let mut safepoint_idx = 0;
1249
0
            for range_idx in 0..self.vregs[vreg.index()].ranges.len() {
1250
0
                let LiveRangeListEntry { range, index } =
1251
0
                    self.vregs[vreg.index()].ranges[range_idx];
1252
0
                while safepoint_idx < self.safepoints.len()
1253
0
                    && ProgPoint::before(self.safepoints[safepoint_idx]) < range.from
1254
0
                {
1255
0
                    safepoint_idx += 1;
1256
0
                }
1257
0
                while safepoint_idx < self.safepoints.len()
1258
0
                    && range.contains_point(ProgPoint::before(self.safepoints[safepoint_idx]))
1259
                {
1260
                    // Create a virtual use.
1261
0
                    let pos = ProgPoint::before(self.safepoints[safepoint_idx]);
1262
0
                    let operand = Operand::new(
1263
0
                        self.vreg(vreg),
1264
0
                        OperandConstraint::Stack,
1265
0
                        OperandKind::Use,
1266
0
                        OperandPos::Early,
1267
0
                    );
1268
0
1269
0
                    trace!(
1270
0
                        "Safepoint-induced stack use of {:?} at {:?} -> {:?}",
1271
                        operand,
1272
                        pos,
1273
                        index,
1274
                    );
1275
1276
0
                    self.insert_use_into_liverange(index, Use::new(operand, pos, SLOT_NONE));
1277
0
                    safepoint_idx += 1;
1278
0
1279
0
                    inserted = true;
1280
                }
1281
1282
0
                if inserted {
1283
0
                    self.ranges[index.index()]
1284
0
                        .uses
1285
0
                        .sort_unstable_by_key(|u| u.pos);
1286
0
                }
1287
1288
0
                if safepoint_idx >= self.safepoints.len() {
1289
0
                    break;
1290
0
                }
1291
            }
1292
        }
1293
1294
139k
        self.blockparam_ins.sort_unstable_by_key(|x| x.key());
1295
139k
        self.blockparam_outs.sort_unstable_by_key(|x| x.key());
1296
139k
        self.prog_move_srcs.sort_unstable_by_key(|(pos, _)| *pos);
1297
139k
        self.prog_move_dsts.sort_unstable_by_key(|(pos, _)| *pos);
1298
139k
1299
139k
        trace!("prog_move_srcs = {:?}", self.prog_move_srcs);
1300
139k
        trace!("prog_move_dsts = {:?}", self.prog_move_dsts);
1301
1302
139k
        self.stats.initial_liverange_count = self.ranges.len();
1303
139k
        self.stats.blockparam_ins_count = self.blockparam_ins.len();
1304
139k
        self.stats.blockparam_outs_count = self.blockparam_outs.len();
1305
139k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::build_liveranges
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::build_liveranges
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::build_liveranges
1306
1307
139k
    pub fn fixup_multi_fixed_vregs(&mut self) {
1308
        // Do a fixed-reg cleanup pass: if there are any LiveRanges with
1309
        // multiple uses (or defs) at the same ProgPoint and there is
1310
        // more than one FixedReg constraint at that ProgPoint, we
1311
        // need to record all but one of them in a special fixup list
1312
        // and handle them later; otherwise, bundle-splitting to
1313
        // create minimal bundles becomes much more complex (we would
1314
        // have to split the multiple uses at the same progpoint into
1315
        // different bundles, which breaks invariants related to
1316
        // disjoint ranges and bundles).
1317
139k
        let mut extra_clobbers: SmallVec<[(PReg, ProgPoint); 8]> = smallvec![];
1318
19.7M
        for vreg in 0..self.vregs.len() {
1319
19.7M
            for range_idx in 0..self.vregs[vreg].ranges.len() {
1320
1.23M
                let entry = self.vregs[vreg].ranges[range_idx];
1321
1.23M
                let range = entry.index;
1322
1.23M
                trace!(
1323
0
                    "multi-fixed-reg cleanup: vreg {:?} range {:?}",
1324
0
                    VRegIndex::new(vreg),
1325
                    range,
1326
                );
1327
1328
                // Find groups of uses that occur in at the same program point.
1329
2.11M
                for uses in self.ranges[range.index()]
1330
1.23M
                    .uses
1331
1.99M
                    .linear_group_by_key_mut(|u| u.pos)
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::fixup_multi_fixed_vregs::{closure#0}
Line
Count
Source
1331
1.99M
                    .linear_group_by_key_mut(|u| u.pos)
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::fixup_multi_fixed_vregs::{closure#0}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::fixup_multi_fixed_vregs::{closure#0}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::fixup_multi_fixed_vregs::{closure#0}
1332
                {
1333
2.11M
                    if uses.len() < 2 {
1334
2.06M
                        continue;
1335
46.3k
                    }
1336
46.3k
1337
46.3k
                    // Search for conflicting constraints in the uses.
1338
46.3k
                    let mut requires_reg = false;
1339
46.3k
                    let mut num_fixed_reg = 0;
1340
46.3k
                    let mut num_fixed_stack = 0;
1341
46.3k
                    let mut first_reg_slot = None;
1342
46.3k
                    let mut first_stack_slot = None;
1343
92.6k
                    for u in uses.iter() {
1344
92.6k
                        match u.operand.constraint() {
1345
10
                            OperandConstraint::Any => {
1346
10
                                first_reg_slot.get_or_insert(u.slot);
1347
10
                                first_stack_slot.get_or_insert(u.slot);
1348
10
                            }
1349
92.5k
                            OperandConstraint::Reg | OperandConstraint::Reuse(_) => {
1350
92.5k
                                first_reg_slot.get_or_insert(u.slot);
1351
92.5k
                                requires_reg = true;
1352
92.5k
                            }
1353
44
                            OperandConstraint::FixedReg(preg) => {
1354
44
                                if self.pregs[preg.index()].is_stack {
1355
0
                                    num_fixed_stack += 1;
1356
0
                                    first_stack_slot.get_or_insert(u.slot);
1357
44
                                } else {
1358
44
                                    requires_reg = true;
1359
44
                                    num_fixed_reg += 1;
1360
44
                                    first_reg_slot.get_or_insert(u.slot);
1361
44
                                }
1362
                            }
1363
                            // Maybe this could be supported in this future...
1364
0
                            OperandConstraint::Stack => panic!(
1365
0
                                "multiple uses of vreg with a Stack constraint are not supported"
1366
0
                            ),
1367
                        }
1368
                    }
1369
1370
                    // Fast path if there are no conflicts.
1371
46.3k
                    if num_fixed_reg + num_fixed_stack <= 1
1372
46.3k
                        && !(requires_reg && num_fixed_stack != 0)
1373
                    {
1374
46.3k
                        continue;
1375
2
                    }
1376
1377
                    // We pick one constraint (in order: FixedReg, Reg, FixedStack)
1378
                    // and then rewrite any incompatible constraints to Any.
1379
                    // This allows register allocation to succeed and we will
1380
                    // later insert moves to satisfy the rewritten constraints.
1381
2
                    let source_slot = if requires_reg {
1382
2
                        first_reg_slot.unwrap()
1383
                    } else {
1384
0
                        first_stack_slot.unwrap()
1385
                    };
1386
2
                    let mut first_preg = None;
1387
4
                    for u in uses.iter_mut() {
1388
4
                        if let OperandConstraint::FixedReg(preg) = u.operand.constraint() {
1389
4
                            let vreg_idx = VRegIndex::new(u.operand.vreg().vreg());
1390
4
                            let preg_idx = PRegIndex::new(preg.index());
1391
4
                            trace!(
1392
0
                                "at pos {:?}, vreg {:?} has fixed constraint to preg {:?}",
1393
                                u.pos,
1394
                                vreg_idx,
1395
                                preg_idx
1396
                            );
1397
1398
                            // FixedStack is incompatible if there are any
1399
                            // Reg/FixedReg constraints. FixedReg is
1400
                            // incompatible if there already is a different
1401
                            // FixedReg constraint. If either condition is true,
1402
                            // we edit the constraint below; otherwise, we can
1403
                            // skip this edit.
1404
4
                            if !(requires_reg && self.pregs[preg.index()].is_stack)
1405
4
                                && *first_preg.get_or_insert(preg) == preg
1406
                            {
1407
2
                                continue;
1408
2
                            }
1409
2
1410
2
                            trace!(" -> duplicate; switching to constraint Any");
1411
2
                            self.multi_fixed_reg_fixups.push(MultiFixedRegFixup {
1412
2
                                pos: u.pos,
1413
2
                                from_slot: source_slot,
1414
2
                                to_slot: u.slot,
1415
2
                                to_preg: preg_idx,
1416
2
                                vreg: vreg_idx,
1417
2
                                level: FixedRegFixupLevel::Secondary,
1418
2
                            });
1419
2
                            u.operand = Operand::new(
1420
2
                                u.operand.vreg(),
1421
2
                                OperandConstraint::Any,
1422
2
                                u.operand.kind(),
1423
2
                                u.operand.pos(),
1424
2
                            );
1425
2
                            trace!(" -> extra clobber {} at inst{}", preg, u.pos.inst().index());
1426
2
                            extra_clobbers.push((preg, u.pos));
1427
0
                        }
1428
                    }
1429
                }
1430
1431
1.23M
                for &(clobber, pos) in &extra_clobbers {
1432
2
                    let range = CodeRange {
1433
2
                        from: pos,
1434
2
                        to: pos.next(),
1435
2
                    };
1436
2
                    self.add_liverange_to_preg(range, clobber);
1437
2
                }
1438
1439
1.23M
                extra_clobbers.clear();
1440
            }
1441
        }
1442
139k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::fixup_multi_fixed_vregs
Line
Count
Source
1307
139k
    pub fn fixup_multi_fixed_vregs(&mut self) {
1308
        // Do a fixed-reg cleanup pass: if there are any LiveRanges with
1309
        // multiple uses (or defs) at the same ProgPoint and there is
1310
        // more than one FixedReg constraint at that ProgPoint, we
1311
        // need to record all but one of them in a special fixup list
1312
        // and handle them later; otherwise, bundle-splitting to
1313
        // create minimal bundles becomes much more complex (we would
1314
        // have to split the multiple uses at the same progpoint into
1315
        // different bundles, which breaks invariants related to
1316
        // disjoint ranges and bundles).
1317
139k
        let mut extra_clobbers: SmallVec<[(PReg, ProgPoint); 8]> = smallvec![];
1318
19.7M
        for vreg in 0..self.vregs.len() {
1319
19.7M
            for range_idx in 0..self.vregs[vreg].ranges.len() {
1320
1.23M
                let entry = self.vregs[vreg].ranges[range_idx];
1321
1.23M
                let range = entry.index;
1322
1.23M
                trace!(
1323
0
                    "multi-fixed-reg cleanup: vreg {:?} range {:?}",
1324
0
                    VRegIndex::new(vreg),
1325
                    range,
1326
                );
1327
1328
                // Find groups of uses that occur in at the same program point.
1329
2.11M
                for uses in self.ranges[range.index()]
1330
1.23M
                    .uses
1331
1.23M
                    .linear_group_by_key_mut(|u| u.pos)
1332
                {
1333
2.11M
                    if uses.len() < 2 {
1334
2.06M
                        continue;
1335
46.3k
                    }
1336
46.3k
1337
46.3k
                    // Search for conflicting constraints in the uses.
1338
46.3k
                    let mut requires_reg = false;
1339
46.3k
                    let mut num_fixed_reg = 0;
1340
46.3k
                    let mut num_fixed_stack = 0;
1341
46.3k
                    let mut first_reg_slot = None;
1342
46.3k
                    let mut first_stack_slot = None;
1343
92.6k
                    for u in uses.iter() {
1344
92.6k
                        match u.operand.constraint() {
1345
10
                            OperandConstraint::Any => {
1346
10
                                first_reg_slot.get_or_insert(u.slot);
1347
10
                                first_stack_slot.get_or_insert(u.slot);
1348
10
                            }
1349
92.5k
                            OperandConstraint::Reg | OperandConstraint::Reuse(_) => {
1350
92.5k
                                first_reg_slot.get_or_insert(u.slot);
1351
92.5k
                                requires_reg = true;
1352
92.5k
                            }
1353
44
                            OperandConstraint::FixedReg(preg) => {
1354
44
                                if self.pregs[preg.index()].is_stack {
1355
0
                                    num_fixed_stack += 1;
1356
0
                                    first_stack_slot.get_or_insert(u.slot);
1357
44
                                } else {
1358
44
                                    requires_reg = true;
1359
44
                                    num_fixed_reg += 1;
1360
44
                                    first_reg_slot.get_or_insert(u.slot);
1361
44
                                }
1362
                            }
1363
                            // Maybe this could be supported in this future...
1364
0
                            OperandConstraint::Stack => panic!(
1365
0
                                "multiple uses of vreg with a Stack constraint are not supported"
1366
0
                            ),
1367
                        }
1368
                    }
1369
1370
                    // Fast path if there are no conflicts.
1371
46.3k
                    if num_fixed_reg + num_fixed_stack <= 1
1372
46.3k
                        && !(requires_reg && num_fixed_stack != 0)
1373
                    {
1374
46.3k
                        continue;
1375
2
                    }
1376
1377
                    // We pick one constraint (in order: FixedReg, Reg, FixedStack)
1378
                    // and then rewrite any incompatible constraints to Any.
1379
                    // This allows register allocation to succeed and we will
1380
                    // later insert moves to satisfy the rewritten constraints.
1381
2
                    let source_slot = if requires_reg {
1382
2
                        first_reg_slot.unwrap()
1383
                    } else {
1384
0
                        first_stack_slot.unwrap()
1385
                    };
1386
2
                    let mut first_preg = None;
1387
4
                    for u in uses.iter_mut() {
1388
4
                        if let OperandConstraint::FixedReg(preg) = u.operand.constraint() {
1389
4
                            let vreg_idx = VRegIndex::new(u.operand.vreg().vreg());
1390
4
                            let preg_idx = PRegIndex::new(preg.index());
1391
4
                            trace!(
1392
0
                                "at pos {:?}, vreg {:?} has fixed constraint to preg {:?}",
1393
                                u.pos,
1394
                                vreg_idx,
1395
                                preg_idx
1396
                            );
1397
1398
                            // FixedStack is incompatible if there are any
1399
                            // Reg/FixedReg constraints. FixedReg is
1400
                            // incompatible if there already is a different
1401
                            // FixedReg constraint. If either condition is true,
1402
                            // we edit the constraint below; otherwise, we can
1403
                            // skip this edit.
1404
4
                            if !(requires_reg && self.pregs[preg.index()].is_stack)
1405
4
                                && *first_preg.get_or_insert(preg) == preg
1406
                            {
1407
2
                                continue;
1408
2
                            }
1409
2
1410
2
                            trace!(" -> duplicate; switching to constraint Any");
1411
2
                            self.multi_fixed_reg_fixups.push(MultiFixedRegFixup {
1412
2
                                pos: u.pos,
1413
2
                                from_slot: source_slot,
1414
2
                                to_slot: u.slot,
1415
2
                                to_preg: preg_idx,
1416
2
                                vreg: vreg_idx,
1417
2
                                level: FixedRegFixupLevel::Secondary,
1418
2
                            });
1419
2
                            u.operand = Operand::new(
1420
2
                                u.operand.vreg(),
1421
2
                                OperandConstraint::Any,
1422
2
                                u.operand.kind(),
1423
2
                                u.operand.pos(),
1424
2
                            );
1425
2
                            trace!(" -> extra clobber {} at inst{}", preg, u.pos.inst().index());
1426
2
                            extra_clobbers.push((preg, u.pos));
1427
0
                        }
1428
                    }
1429
                }
1430
1431
1.23M
                for &(clobber, pos) in &extra_clobbers {
1432
2
                    let range = CodeRange {
1433
2
                        from: pos,
1434
2
                        to: pos.next(),
1435
2
                    };
1436
2
                    self.add_liverange_to_preg(range, clobber);
1437
2
                }
1438
1439
1.23M
                extra_clobbers.clear();
1440
            }
1441
        }
1442
139k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::fixup_multi_fixed_vregs
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::fixup_multi_fixed_vregs
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::fixup_multi_fixed_vregs
1443
}