Skip to content

Commit 4b0c5ff

Browse files
committed
Merge cached limits on LiveBundles
In line with the current performance considerations, we cache the limit for each bundle and merge them when bundles are merged.
1 parent e13bb3d commit 4b0c5ff

File tree

2 files changed

+45
-34
lines changed

2 files changed

+45
-34
lines changed

src/ion/data_structures.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ pub struct LiveBundle {
203203
pub allocation: Allocation,
204204
pub prio: u32, // recomputed after every bulk update
205205
pub spill_weight_and_props: u32,
206+
pub limit: Option<usize>,
206207
}
207208

208209
pub const BUNDLE_MAX_SPILL_WEIGHT: u32 = (1 << 28) - 1;
@@ -413,6 +414,7 @@ impl LiveBundles {
413414
spillset: SpillSetIndex::invalid(),
414415
prio: 0,
415416
spill_weight_and_props: 0,
417+
limit: None,
416418
})
417419
}
418420
}

src/ion/merge.rs

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,32 @@
1212

1313
//! Bundle merging.
1414
15-
use super::{Env, LiveBundleIndex, SpillSet, SpillSlotIndex, VRegIndex};
16-
use crate::{
17-
ion::{
18-
data_structures::{BlockparamOut, CodeRange},
19-
LiveRangeList,
20-
},
21-
Function, Inst, OperandConstraint, OperandKind, PReg, ProgPoint,
15+
use crate::ion::data_structures::{
16+
BlockparamOut, CodeRange, Env, LiveBundleIndex, LiveRangeList, SpillSet, SpillSlotIndex,
17+
VRegIndex,
2218
};
19+
use crate::{Function, Inst, OperandConstraint, OperandKind, PReg, ProgPoint};
2320
use alloc::format;
2421

2522
impl<'a, F: Function> Env<'a, F> {
23+
fn merge_bundle_properties(&mut self, from: LiveBundleIndex, to: LiveBundleIndex) {
24+
if self.bundles[from].cached_fixed() {
25+
self.bundles[to].set_cached_fixed();
26+
}
27+
if self.bundles[from].cached_fixed_def() {
28+
self.bundles[to].set_cached_fixed_def();
29+
}
30+
if self.bundles[from].cached_stack() {
31+
self.bundles[to].set_cached_stack();
32+
}
33+
if let Some(theirs) = self.bundles[from].limit {
34+
match self.bundles[to].limit {
35+
Some(ours) => self.bundles[to].limit = Some(ours.min(theirs)),
36+
None => self.bundles[to].limit = Some(theirs),
37+
}
38+
}
39+
}
40+
2641
pub fn merge_bundles(&mut self, from: LiveBundleIndex, to: LiveBundleIndex) -> bool {
2742
if from == to {
2843
// Merge bundle into self -- trivial merge.
@@ -114,8 +129,10 @@ impl<'a, F: Function> Env<'a, F> {
114129
// Check for a requirements conflict.
115130
if self.bundles[from].cached_stack()
116131
|| self.bundles[from].cached_fixed()
132+
|| self.bundles[from].limit.is_some()
117133
|| self.bundles[to].cached_stack()
118134
|| self.bundles[to].cached_fixed()
135+
|| self.bundles[to].limit.is_some()
119136
{
120137
if self.merge_bundle_requirements(from, to).is_err() {
121138
trace!(" -> conflicting requirements; aborting merge");
@@ -157,17 +174,7 @@ impl<'a, F: Function> Env<'a, F> {
157174
}
158175
}
159176
self.bundles[to].ranges = list;
160-
161-
if self.bundles[from].cached_stack() {
162-
self.bundles[to].set_cached_stack();
163-
}
164-
if self.bundles[from].cached_fixed() {
165-
self.bundles[to].set_cached_fixed();
166-
}
167-
if self.bundles[from].cached_fixed_def() {
168-
self.bundles[to].set_cached_fixed_def();
169-
}
170-
177+
self.merge_bundle_properties(from, to);
171178
return true;
172179
}
173180

@@ -243,15 +250,7 @@ impl<'a, F: Function> Env<'a, F> {
243250
*to_range = to_range.join(from_range);
244251
}
245252

246-
if self.bundles[from].cached_stack() {
247-
self.bundles[to].set_cached_stack();
248-
}
249-
if self.bundles[from].cached_fixed() {
250-
self.bundles[to].set_cached_fixed();
251-
}
252-
if self.bundles[from].cached_fixed_def() {
253-
self.bundles[to].set_cached_fixed_def();
254-
}
253+
self.merge_bundle_properties(from, to);
255254

256255
true
257256
}
@@ -283,16 +282,25 @@ impl<'a, F: Function> Env<'a, F> {
283282
let mut fixed = false;
284283
let mut fixed_def = false;
285284
let mut stack = false;
285+
let mut limit: Option<usize> = None;
286286
for entry in &self.bundles[bundle].ranges {
287287
for u in &self.ranges[entry.index].uses {
288-
if let OperandConstraint::FixedReg(_) = u.operand.constraint() {
289-
fixed = true;
290-
if u.operand.kind() == OperandKind::Def {
291-
fixed_def = true;
288+
use OperandConstraint::*;
289+
match u.operand.constraint() {
290+
FixedReg(_) => {
291+
fixed = true;
292+
if u.operand.kind() == OperandKind::Def {
293+
fixed_def = true;
294+
}
295+
}
296+
Stack => stack = true,
297+
Limit(current) => match limit {
298+
Some(prev) => limit = Some(prev.min(current)),
299+
None => limit = Some(current),
300+
},
301+
Any | Reg | Reuse(_) => {
302+
continue;
292303
}
293-
}
294-
if let OperandConstraint::Stack = u.operand.constraint() {
295-
stack = true;
296304
}
297305
if fixed && stack && fixed_def {
298306
break;
@@ -308,6 +316,7 @@ impl<'a, F: Function> Env<'a, F> {
308316
if stack {
309317
self.bundles[bundle].set_cached_stack();
310318
}
319+
self.bundles[bundle].limit = limit;
311320

312321
// Create a spillslot for this bundle.
313322
let reg = self.vreg(vreg);

0 commit comments

Comments
 (0)