Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/regalloc2-0.5.1/src/ion/spill.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
//! Spillslot allocation.
14
15
use super::{
16
    AllocRegResult, Env, LiveRangeKey, LiveRangeSet, PReg, PRegIndex, RegTraversalIter,
17
    SpillSetIndex, SpillSlotData, SpillSlotIndex, SpillSlotList,
18
};
19
use crate::{Allocation, Function, SpillSlot};
20
use smallvec::smallvec;
21
22
impl<'a, F: Function> Env<'a, F> {
23
139k
    pub fn try_allocating_regs_for_spilled_bundles(&mut self) {
24
139k
        trace!("allocating regs for spilled bundles");
25
139k
        for i in 0..self.spilled_bundles.len() {
26
70.4k
            let bundle = self.spilled_bundles[i]; // don't borrow self
27
70.4k
28
70.4k
            if self.bundles[bundle.index()].ranges.is_empty() {
29
0
                continue;
30
70.4k
            }
31
70.4k
32
70.4k
            let class = self.spillsets[self.bundles[bundle.index()].spillset.index()].class;
33
70.4k
            let hint = self.spillsets[self.bundles[bundle.index()].spillset.index()].reg_hint;
34
70.4k
35
70.4k
            // This may be an empty-range bundle whose ranges are not
36
70.4k
            // sorted; sort all range-lists again here.
37
70.4k
            self.bundles[bundle.index()]
38
70.4k
                .ranges
39
564k
                .sort_unstable_by_key(|entry| entry.range.from);
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::try_allocating_regs_for_spilled_bundles::{closure#0}
Line
Count
Source
39
564k
                .sort_unstable_by_key(|entry| entry.range.from);
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::try_allocating_regs_for_spilled_bundles::{closure#0}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::try_allocating_regs_for_spilled_bundles::{closure#0}
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::try_allocating_regs_for_spilled_bundles::{closure#0}
40
70.4k
41
70.4k
            let mut success = false;
42
70.4k
            self.stats.spill_bundle_reg_probes += 1;
43
500k
            for preg in
44
70.4k
                RegTraversalIter::new(self.env, class, hint, PReg::invalid(), bundle.index(), None)
45
            {
46
500k
                trace!("trying bundle {:?} to preg {:?}", bundle, preg);
47
500k
                let preg_idx = PRegIndex::new(preg.index());
48
500k
                if let AllocRegResult::Allocated(_) =
49
500k
                    self.try_to_allocate_bundle_to_reg(bundle, preg_idx, None)
50
                {
51
58.0k
                    self.stats.spill_bundle_reg_success += 1;
52
58.0k
                    success = true;
53
58.0k
                    break;
54
442k
                }
55
            }
56
70.4k
            if !success {
57
12.4k
                trace!(
58
0
                    "spilling bundle {:?}: marking spillset {:?} as required",
59
0
                    bundle,
60
0
                    self.bundles[bundle.index()].spillset
61
                );
62
12.4k
                self.spillsets[self.bundles[bundle.index()].spillset.index()].required = true;
63
58.0k
            }
64
        }
65
139k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::try_allocating_regs_for_spilled_bundles
Line
Count
Source
23
139k
    pub fn try_allocating_regs_for_spilled_bundles(&mut self) {
24
139k
        trace!("allocating regs for spilled bundles");
25
139k
        for i in 0..self.spilled_bundles.len() {
26
70.4k
            let bundle = self.spilled_bundles[i]; // don't borrow self
27
70.4k
28
70.4k
            if self.bundles[bundle.index()].ranges.is_empty() {
29
0
                continue;
30
70.4k
            }
31
70.4k
32
70.4k
            let class = self.spillsets[self.bundles[bundle.index()].spillset.index()].class;
33
70.4k
            let hint = self.spillsets[self.bundles[bundle.index()].spillset.index()].reg_hint;
34
70.4k
35
70.4k
            // This may be an empty-range bundle whose ranges are not
36
70.4k
            // sorted; sort all range-lists again here.
37
70.4k
            self.bundles[bundle.index()]
38
70.4k
                .ranges
39
70.4k
                .sort_unstable_by_key(|entry| entry.range.from);
40
70.4k
41
70.4k
            let mut success = false;
42
70.4k
            self.stats.spill_bundle_reg_probes += 1;
43
500k
            for preg in
44
70.4k
                RegTraversalIter::new(self.env, class, hint, PReg::invalid(), bundle.index(), None)
45
            {
46
500k
                trace!("trying bundle {:?} to preg {:?}", bundle, preg);
47
500k
                let preg_idx = PRegIndex::new(preg.index());
48
500k
                if let AllocRegResult::Allocated(_) =
49
500k
                    self.try_to_allocate_bundle_to_reg(bundle, preg_idx, None)
50
                {
51
58.0k
                    self.stats.spill_bundle_reg_success += 1;
52
58.0k
                    success = true;
53
58.0k
                    break;
54
442k
                }
55
            }
56
70.4k
            if !success {
57
12.4k
                trace!(
58
0
                    "spilling bundle {:?}: marking spillset {:?} as required",
59
0
                    bundle,
60
0
                    self.bundles[bundle.index()].spillset
61
                );
62
12.4k
                self.spillsets[self.bundles[bundle.index()].spillset.index()].required = true;
63
58.0k
            }
64
        }
65
139k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::try_allocating_regs_for_spilled_bundles
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::try_allocating_regs_for_spilled_bundles
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::try_allocating_regs_for_spilled_bundles
66
67
17.7k
    pub fn spillslot_can_fit_spillset(
68
17.7k
        &mut self,
69
17.7k
        spillslot: SpillSlotIndex,
70
17.7k
        spillset: SpillSetIndex,
71
17.7k
    ) -> bool {
72
18.1k
        for &vreg in &self.spillsets[spillset.index()].vregs {
73
18.6k
            for entry in &self.vregs[vreg.index()].ranges {
74
18.6k
                if self.spillslots[spillslot.index()]
75
18.6k
                    .ranges
76
18.6k
                    .btree
77
18.6k
                    .contains_key(&LiveRangeKey::from_range(&entry.range))
78
                {
79
17.5k
                    return false;
80
1.07k
                }
81
            }
82
        }
83
208
        true
84
17.7k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::spillslot_can_fit_spillset
Line
Count
Source
67
17.7k
    pub fn spillslot_can_fit_spillset(
68
17.7k
        &mut self,
69
17.7k
        spillslot: SpillSlotIndex,
70
17.7k
        spillset: SpillSetIndex,
71
17.7k
    ) -> bool {
72
18.1k
        for &vreg in &self.spillsets[spillset.index()].vregs {
73
18.6k
            for entry in &self.vregs[vreg.index()].ranges {
74
18.6k
                if self.spillslots[spillslot.index()]
75
18.6k
                    .ranges
76
18.6k
                    .btree
77
18.6k
                    .contains_key(&LiveRangeKey::from_range(&entry.range))
78
                {
79
17.5k
                    return false;
80
1.07k
                }
81
            }
82
        }
83
208
        true
84
17.7k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::spillslot_can_fit_spillset
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::spillslot_can_fit_spillset
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::spillslot_can_fit_spillset
85
86
12.4k
    pub fn allocate_spillset_to_spillslot(
87
12.4k
        &mut self,
88
12.4k
        spillset: SpillSetIndex,
89
12.4k
        spillslot: SpillSlotIndex,
90
12.4k
    ) {
91
12.4k
        self.spillsets[spillset.index()].slot = spillslot;
92
93
13.4k
        for vreg in &self.spillsets[spillset.index()].vregs {
94
13.4k
            trace!(
95
0
                "spillslot {:?} alloc'ed to spillset {:?}: vreg {:?}",
96
                spillslot,
97
                spillset,
98
                vreg,
99
            );
100
34.8k
            for entry in &self.vregs[vreg.index()].ranges {
101
34.8k
                trace!(
102
0
                    "spillslot {:?} getting range {:?} from LR {:?} from vreg {:?}",
103
                    spillslot,
104
                    entry.range,
105
                    entry.index,
106
                    vreg,
107
                );
108
34.8k
                self.spillslots[spillslot.index()]
109
34.8k
                    .ranges
110
34.8k
                    .btree
111
34.8k
                    .insert(LiveRangeKey::from_range(&entry.range), entry.index);
112
            }
113
        }
114
12.4k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::allocate_spillset_to_spillslot
Line
Count
Source
86
12.4k
    pub fn allocate_spillset_to_spillslot(
87
12.4k
        &mut self,
88
12.4k
        spillset: SpillSetIndex,
89
12.4k
        spillslot: SpillSlotIndex,
90
12.4k
    ) {
91
12.4k
        self.spillsets[spillset.index()].slot = spillslot;
92
93
13.4k
        for vreg in &self.spillsets[spillset.index()].vregs {
94
13.4k
            trace!(
95
0
                "spillslot {:?} alloc'ed to spillset {:?}: vreg {:?}",
96
                spillslot,
97
                spillset,
98
                vreg,
99
            );
100
34.8k
            for entry in &self.vregs[vreg.index()].ranges {
101
34.8k
                trace!(
102
0
                    "spillslot {:?} getting range {:?} from LR {:?} from vreg {:?}",
103
                    spillslot,
104
                    entry.range,
105
                    entry.index,
106
                    vreg,
107
                );
108
34.8k
                self.spillslots[spillslot.index()]
109
34.8k
                    .ranges
110
34.8k
                    .btree
111
34.8k
                    .insert(LiveRangeKey::from_range(&entry.range), entry.index);
112
            }
113
        }
114
12.4k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::allocate_spillset_to_spillslot
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::allocate_spillset_to_spillslot
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::allocate_spillset_to_spillslot
115
116
139k
    pub fn allocate_spillslots(&mut self) {
117
        const MAX_ATTEMPTS: usize = 10;
118
119
1.15M
        for spillset in 0..self.spillsets.len() {
120
1.15M
            trace!("allocate spillslot: {}", spillset);
121
1.15M
            let spillset = SpillSetIndex::new(spillset);
122
1.15M
            if !self.spillsets[spillset.index()].required {
123
1.14M
                continue;
124
12.4k
            }
125
12.4k
            // Get or create the spillslot list for this size.
126
12.4k
            let size = self.spillsets[spillset.index()].size as usize;
127
12.4k
            if size >= self.slots_by_size.len() {
128
4.25k
                self.slots_by_size.resize(
129
4.25k
                    size + 1,
130
4.25k
                    SpillSlotList {
131
4.25k
                        slots: smallvec![],
132
                        probe_start: 0,
133
                    },
134
                );
135
8.14k
            }
136
            // Try a few existing spillslots.
137
12.4k
            let mut i = self.slots_by_size[size].probe_start;
138
12.4k
            let mut success = false;
139
            // Never probe the same element more than once: limit the
140
            // attempt count to the number of slots in existence.
141
17.7k
            for _attempt in 0..std::cmp::min(self.slots_by_size[size].slots.len(), MAX_ATTEMPTS) {
142
                // Note: this indexing of `slots` is always valid
143
                // because either the `slots` list is empty and the
144
                // iteration limit above consequently means we don't
145
                // run this loop at all, or else `probe_start` is
146
                // in-bounds (because it is made so below when we add
147
                // a slot, and it always takes on the last index `i`
148
                // after this loop).
149
17.7k
                let spillslot = self.slots_by_size[size].slots[i];
150
17.7k
151
17.7k
                if self.spillslot_can_fit_spillset(spillslot, spillset) {
152
208
                    self.allocate_spillset_to_spillslot(spillset, spillslot);
153
208
                    success = true;
154
208
                    self.slots_by_size[size].probe_start = i;
155
208
                    break;
156
17.5k
                }
157
17.5k
158
17.5k
                i = self.slots_by_size[size].next_index(i);
159
            }
160
161
12.4k
            if !success {
162
12.1k
                // Allocate a new spillslot.
163
12.1k
                let spillslot = SpillSlotIndex::new(self.spillslots.len());
164
12.1k
                self.spillslots.push(SpillSlotData {
165
12.1k
                    ranges: LiveRangeSet::new(),
166
12.1k
                    alloc: Allocation::none(),
167
12.1k
                    slots: size as u32,
168
12.1k
                });
169
12.1k
                self.slots_by_size[size].slots.push(spillslot);
170
12.1k
                self.slots_by_size[size].probe_start = self.slots_by_size[size].slots.len() - 1;
171
12.1k
172
12.1k
                self.allocate_spillset_to_spillslot(spillset, spillslot);
173
12.1k
            }
174
        }
175
176
        // Assign actual slot indices to spillslots.
177
139k
        for i in 0..self.spillslots.len() {
178
12.1k
            self.spillslots[i].alloc = self.allocate_spillslot(self.spillslots[i].slots);
179
12.1k
        }
180
181
139k
        trace!("spillslot allocator done");
182
139k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::allocate_spillslots
Line
Count
Source
116
139k
    pub fn allocate_spillslots(&mut self) {
117
        const MAX_ATTEMPTS: usize = 10;
118
119
1.15M
        for spillset in 0..self.spillsets.len() {
120
1.15M
            trace!("allocate spillslot: {}", spillset);
121
1.15M
            let spillset = SpillSetIndex::new(spillset);
122
1.15M
            if !self.spillsets[spillset.index()].required {
123
1.14M
                continue;
124
12.4k
            }
125
12.4k
            // Get or create the spillslot list for this size.
126
12.4k
            let size = self.spillsets[spillset.index()].size as usize;
127
12.4k
            if size >= self.slots_by_size.len() {
128
4.25k
                self.slots_by_size.resize(
129
4.25k
                    size + 1,
130
4.25k
                    SpillSlotList {
131
4.25k
                        slots: smallvec![],
132
                        probe_start: 0,
133
                    },
134
                );
135
8.14k
            }
136
            // Try a few existing spillslots.
137
12.4k
            let mut i = self.slots_by_size[size].probe_start;
138
12.4k
            let mut success = false;
139
            // Never probe the same element more than once: limit the
140
            // attempt count to the number of slots in existence.
141
17.7k
            for _attempt in 0..std::cmp::min(self.slots_by_size[size].slots.len(), MAX_ATTEMPTS) {
142
                // Note: this indexing of `slots` is always valid
143
                // because either the `slots` list is empty and the
144
                // iteration limit above consequently means we don't
145
                // run this loop at all, or else `probe_start` is
146
                // in-bounds (because it is made so below when we add
147
                // a slot, and it always takes on the last index `i`
148
                // after this loop).
149
17.7k
                let spillslot = self.slots_by_size[size].slots[i];
150
17.7k
151
17.7k
                if self.spillslot_can_fit_spillset(spillslot, spillset) {
152
208
                    self.allocate_spillset_to_spillslot(spillset, spillslot);
153
208
                    success = true;
154
208
                    self.slots_by_size[size].probe_start = i;
155
208
                    break;
156
17.5k
                }
157
17.5k
158
17.5k
                i = self.slots_by_size[size].next_index(i);
159
            }
160
161
12.4k
            if !success {
162
12.1k
                // Allocate a new spillslot.
163
12.1k
                let spillslot = SpillSlotIndex::new(self.spillslots.len());
164
12.1k
                self.spillslots.push(SpillSlotData {
165
12.1k
                    ranges: LiveRangeSet::new(),
166
12.1k
                    alloc: Allocation::none(),
167
12.1k
                    slots: size as u32,
168
12.1k
                });
169
12.1k
                self.slots_by_size[size].slots.push(spillslot);
170
12.1k
                self.slots_by_size[size].probe_start = self.slots_by_size[size].slots.len() - 1;
171
12.1k
172
12.1k
                self.allocate_spillset_to_spillslot(spillset, spillslot);
173
12.1k
            }
174
        }
175
176
        // Assign actual slot indices to spillslots.
177
139k
        for i in 0..self.spillslots.len() {
178
12.1k
            self.spillslots[i].alloc = self.allocate_spillslot(self.spillslots[i].slots);
179
12.1k
        }
180
181
139k
        trace!("spillslot allocator done");
182
139k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::allocate_spillslots
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::allocate_spillslots
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::allocate_spillslots
183
184
12.1k
    pub fn allocate_spillslot(&mut self, size: u32) -> Allocation {
185
12.1k
        let mut offset = self.num_spillslots;
186
12.1k
        // Align up to `size`.
187
12.1k
        debug_assert!(size.is_power_of_two());
188
12.1k
        offset = (offset + size - 1) & !(size - 1);
189
12.1k
        let slot = if self.func.multi_spillslot_named_by_last_slot() {
190
0
            offset + size - 1
191
        } else {
192
12.1k
            offset
193
        };
194
12.1k
        offset += size;
195
12.1k
        self.num_spillslots = offset;
196
12.1k
        Allocation::stack(SpillSlot::new(slot as usize))
197
12.1k
    }
<regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>>::allocate_spillslot
Line
Count
Source
184
12.1k
    pub fn allocate_spillslot(&mut self, size: u32) -> Allocation {
185
12.1k
        let mut offset = self.num_spillslots;
186
12.1k
        // Align up to `size`.
187
12.1k
        debug_assert!(size.is_power_of_two());
188
12.1k
        offset = (offset + size - 1) & !(size - 1);
189
12.1k
        let slot = if self.func.multi_spillslot_named_by_last_slot() {
190
0
            offset + size - 1
191
        } else {
192
12.1k
            offset
193
        };
194
12.1k
        offset += size;
195
12.1k
        self.num_spillslots = offset;
196
12.1k
        Allocation::stack(SpillSlot::new(slot as usize))
197
12.1k
    }
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>>::allocate_spillslot
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>>::allocate_spillslot
Unexecuted instantiation: <regalloc2::ion::data_structures::Env<_>>::allocate_spillslot
198
}