Skip to content

Commit 23c739d

Browse files
committed
Add support for fixed stack slots
This works by allowing a PReg to be marked as being a stack location instead of a physical register.
1 parent 6d32770 commit 23c739d

7 files changed

+53
-24
lines changed

src/ion/data_structures.rs

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ pub struct VRegData {
262262
pub struct PRegData {
263263
pub reg: PReg,
264264
pub allocations: LiveRangeSet,
265+
pub is_stack: bool,
265266
}
266267

267268
#[derive(Clone, Debug)]

src/ion/liveranges.rs

+4
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ impl<'a, F: Function> Env<'a, F> {
103103
PRegData {
104104
reg: PReg::invalid(),
105105
allocations: LiveRangeSet::new(),
106+
is_stack: false,
106107
},
107108
);
108109
for i in 0..=PReg::MAX {
@@ -111,6 +112,9 @@ impl<'a, F: Function> Env<'a, F> {
111112
let preg_float = PReg::new(i, RegClass::Float);
112113
self.pregs[preg_float.index()].reg = preg_float;
113114
}
115+
for &preg in &self.env.fixed_stack_slots {
116+
self.pregs[preg.index()].is_stack = true;
117+
}
114118
// Create VRegs from the vreg count.
115119
for idx in 0..self.func.num_vregs() {
116120
// We'll fill in the real details when we see the def.

src/ion/merge.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ impl<'a, F: Function> Env<'a, F> {
100100
|| self.bundles[to.index()].cached_stack()
101101
|| self.bundles[to.index()].cached_fixed()
102102
{
103-
let req = self
104-
.compute_requirement(from)
105-
.merge(self.compute_requirement(to));
103+
let req_from = self.compute_requirement(from);
104+
let req_to = self.compute_requirement(to);
105+
let req = self.merge_requirement(req_from, req_to);
106106
if req == Requirement::Conflict {
107107
log::trace!(" -> conflicting requirements; aborting merge");
108108
return false;

src/ion/moves.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ impl<'a, F: Function> Env<'a, F> {
3636
pos == self.cfginfo.block_exit[block.index()]
3737
}
3838

39+
fn allocation_is_stack(&self, alloc: Allocation) -> bool {
40+
if alloc.is_stack() {
41+
true
42+
} else if let Some(preg) = alloc.as_reg() {
43+
self.pregs[preg.index()].is_stack
44+
} else {
45+
false
46+
}
47+
}
48+
3949
pub fn insert_move(
4050
&mut self,
4151
pos: ProgPoint,
@@ -968,9 +978,9 @@ impl<'a, F: Function> Env<'a, F> {
968978
let scratch_used = resolved.iter().any(|&(src, dst, _)| {
969979
src == Allocation::reg(scratch) || dst == Allocation::reg(scratch)
970980
});
971-
let stack_stack_move = resolved
972-
.iter()
973-
.any(|&(src, dst, _)| src.is_stack() && dst.is_stack());
981+
let stack_stack_move = resolved.iter().any(|&(src, dst, _)| {
982+
self.allocation_is_stack(src) && self.allocation_is_stack(dst)
983+
});
974984
let extra_slot = if scratch_used && stack_stack_move {
975985
if self.extra_spillslot[regclass as u8 as usize].is_none() {
976986
let slot = self.allocate_spillslot(regclass);
@@ -989,7 +999,7 @@ impl<'a, F: Function> Env<'a, F> {
989999
if dst == Allocation::reg(scratch) {
9901000
scratch_used_yet = true;
9911001
}
992-
if src.is_stack() && dst.is_stack() {
1002+
if self.allocation_is_stack(src) && self.allocation_is_stack(dst) {
9931003
if !scratch_used_yet {
9941004
self.add_edit(
9951005
pos,

src/ion/process.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl<'a, F: Function> Env<'a, F> {
371371
for entry in &self.bundles[bundle.index()].ranges {
372372
for u in &self.ranges[entry.index.index()].uses {
373373
let this_req = Requirement::from_operand(u.operand);
374-
req = req.merge(this_req);
374+
req = self.merge_requirement(req, this_req);
375375
if req == Requirement::Conflict {
376376
return u.pos;
377377
}
@@ -751,11 +751,14 @@ impl<'a, F: Function> Env<'a, F> {
751751
let class = self.spillsets[self.bundles[bundle.index()].spillset.index()].class;
752752
let req = self.compute_requirement(bundle);
753753
// Grab a hint from either the queue or our spillset, if any.
754-
let hint_reg = if reg_hint != PReg::invalid() {
754+
let mut hint_reg = if reg_hint != PReg::invalid() {
755755
reg_hint
756756
} else {
757757
self.spillsets[self.bundles[bundle.index()].spillset.index()].reg_hint
758758
};
759+
if self.pregs[hint_reg.index()].is_stack {
760+
hint_reg = PReg::invalid();
761+
}
759762
log::trace!("process_bundle: bundle {:?} hint {:?}", bundle, hint_reg,);
760763

761764
if let Requirement::Conflict = req {

src/ion/requirement.rs

+18-15
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,6 @@ pub enum Requirement {
1313
Conflict,
1414
}
1515
impl Requirement {
16-
#[inline(always)]
17-
pub fn merge(self, other: Requirement) -> Requirement {
18-
match (self, other) {
19-
(Requirement::Unknown, other) | (other, Requirement::Unknown) => other,
20-
(Requirement::Conflict, _) | (_, Requirement::Conflict) => Requirement::Conflict,
21-
(other, Requirement::Any) | (Requirement::Any, other) => other,
22-
(Requirement::Stack, Requirement::Stack) => self,
23-
(Requirement::Register, Requirement::Fixed(preg))
24-
| (Requirement::Fixed(preg), Requirement::Register) => Requirement::Fixed(preg),
25-
(Requirement::Register, Requirement::Register) => self,
26-
(Requirement::Fixed(a), Requirement::Fixed(b)) if a == b => self,
27-
_ => Requirement::Conflict,
28-
}
29-
}
3016
#[inline(always)]
3117
pub fn from_operand(op: Operand) -> Requirement {
3218
match op.constraint() {
@@ -39,6 +25,23 @@ impl Requirement {
3925
}
4026

4127
impl<'a, F: Function> Env<'a, F> {
28+
#[inline(always)]
29+
pub fn merge_requirement(&self, a: Requirement, b: Requirement) -> Requirement {
30+
match (a, b) {
31+
(Requirement::Unknown, other) | (other, Requirement::Unknown) => other,
32+
(Requirement::Conflict, _) | (_, Requirement::Conflict) => Requirement::Conflict,
33+
(other, Requirement::Any) | (Requirement::Any, other) => other,
34+
(Requirement::Stack, Requirement::Stack) => Requirement::Stack,
35+
(Requirement::Register, Requirement::Register) => Requirement::Register,
36+
(Requirement::Register, Requirement::Fixed(preg))
37+
| (Requirement::Fixed(preg), Requirement::Register) if !self.pregs[preg.index()].is_stack => Requirement::Fixed(preg),
38+
(Requirement::Stack, Requirement::Fixed(preg))
39+
| (Requirement::Fixed(preg), Requirement::Stack) if self.pregs[preg.index()].is_stack => Requirement::Fixed(preg),
40+
(Requirement::Fixed(a), Requirement::Fixed(b)) if a == b => Requirement::Fixed(a),
41+
_ => Requirement::Conflict,
42+
}
43+
}
44+
4245
pub fn compute_requirement(&self, bundle: LiveBundleIndex) -> Requirement {
4346
let mut req = Requirement::Unknown;
4447
log::trace!("compute_requirement: {:?}", bundle);
@@ -47,7 +50,7 @@ impl<'a, F: Function> Env<'a, F> {
4750
for u in &self.ranges[entry.index.index()].uses {
4851
log::trace!(" -> use {:?}", u);
4952
let r = Requirement::from_operand(u.operand);
50-
req = req.merge(r);
53+
req = self.merge_requirement(req, r);
5154
log::trace!(" -> req {:?}", req);
5255
}
5356
}

src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,14 @@ pub struct MachineEnv {
11611161
/// the emission of two machine-code instructions, this lowering
11621162
/// can use the scratch register between them.
11631163
pub scratch_by_class: [PReg; 2],
1164+
1165+
/// Some `PReg`s can be designated as locations on the stack rather than
1166+
/// actual registers. These can be used to tell the register allocator about
1167+
/// pre-defined stack slots used for function arguments and return values.
1168+
///
1169+
/// `PReg`s in this list cannot be used as a scratch register or as an
1170+
/// allocatable regsiter.
1171+
pub fixed_stack_slots: Vec<PReg>,
11641172
}
11651173

11661174
/// The output of the register allocator.

0 commit comments

Comments
 (0)