Refactor requirement computation
This commit is contained in:
@@ -99,9 +99,10 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
|| self.bundles[to.index()].cached_stack()
|
||||
|| self.bundles[to.index()].cached_fixed()
|
||||
{
|
||||
let req_from = self.compute_requirement(from);
|
||||
let req_to = self.compute_requirement(to);
|
||||
let req = self.merge_requirement(req_from, req_to);
|
||||
let req = self
|
||||
.compute_requirement(from)
|
||||
.0
|
||||
.merge(self.compute_requirement(to).0);
|
||||
if req == Requirement::Conflict {
|
||||
log::trace!(" -> conflicting requirements; aborting merge");
|
||||
return false;
|
||||
|
||||
@@ -367,29 +367,6 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_conflict_split_point(&self, bundle: LiveBundleIndex) -> ProgPoint {
|
||||
// Find the first use whose requirement causes the merge up to
|
||||
// this point to go to Conflict.
|
||||
let mut req = Requirement::Unknown;
|
||||
for entry in &self.bundles[bundle.index()].ranges {
|
||||
for u in &self.ranges[entry.index.index()].uses {
|
||||
let this_req = Requirement::from_operand(u.operand);
|
||||
req = self.merge_requirement(req, this_req);
|
||||
if req == Requirement::Conflict {
|
||||
return u.pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: start of bundle.
|
||||
self.bundles[bundle.index()]
|
||||
.ranges
|
||||
.first()
|
||||
.unwrap()
|
||||
.range
|
||||
.from
|
||||
}
|
||||
|
||||
pub fn get_or_create_spill_bundle(
|
||||
&mut self,
|
||||
bundle: LiveBundleIndex,
|
||||
@@ -752,7 +729,7 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
reg_hint: PReg,
|
||||
) -> Result<(), RegAllocError> {
|
||||
let class = self.spillsets[self.bundles[bundle.index()].spillset.index()].class;
|
||||
let req = self.compute_requirement(bundle);
|
||||
let (req, split_point) = self.compute_requirement(bundle);
|
||||
// Grab a hint from either the queue or our spillset, if any.
|
||||
let mut hint_reg = if reg_hint != PReg::invalid() {
|
||||
reg_hint
|
||||
@@ -772,7 +749,6 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
!self.minimal_bundle(bundle),
|
||||
"Minimal bundle with conflict!"
|
||||
);
|
||||
let split_point = self.find_conflict_split_point(bundle);
|
||||
self.split_and_requeue_bundle(
|
||||
bundle,
|
||||
/* split_at_point = */ split_point,
|
||||
@@ -809,7 +785,7 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
debug_assert!(attempts < 100 * self.func.num_insts());
|
||||
|
||||
let fixed_preg = match req {
|
||||
Requirement::Fixed(preg) => Some(preg),
|
||||
Requirement::FixedReg(preg) | Requirement::FixedStack(preg) => Some(preg),
|
||||
Requirement::Register => None,
|
||||
Requirement::Stack => {
|
||||
// If we must be on the stack, mark our spillset
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
//! Requirements computation.
|
||||
|
||||
use super::{Env, LiveBundleIndex};
|
||||
use crate::{Function, Operand, OperandConstraint, PReg};
|
||||
use crate::{Function, Operand, OperandConstraint, PReg, ProgPoint};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Requirement {
|
||||
Unknown,
|
||||
Fixed(PReg),
|
||||
FixedReg(PReg),
|
||||
FixedStack(PReg),
|
||||
Register,
|
||||
Stack,
|
||||
Any,
|
||||
@@ -26,47 +27,58 @@ pub enum Requirement {
|
||||
}
|
||||
impl Requirement {
|
||||
#[inline(always)]
|
||||
pub fn from_operand(op: Operand) -> Requirement {
|
||||
match op.constraint() {
|
||||
OperandConstraint::FixedReg(preg) => Requirement::Fixed(preg),
|
||||
OperandConstraint::Reg | OperandConstraint::Reuse(_) => Requirement::Register,
|
||||
OperandConstraint::Stack => Requirement::Stack,
|
||||
_ => Requirement::Any,
|
||||
pub fn merge(self, other: Requirement) -> Requirement {
|
||||
match (self, other) {
|
||||
(Requirement::Unknown, other) | (other, Requirement::Unknown) => other,
|
||||
(Requirement::Conflict, _) | (_, Requirement::Conflict) => Requirement::Conflict,
|
||||
(other, Requirement::Any) | (Requirement::Any, other) => other,
|
||||
(Requirement::Register, Requirement::Register) => self,
|
||||
(Requirement::Stack, Requirement::Stack) => self,
|
||||
(Requirement::Register, Requirement::FixedReg(preg))
|
||||
| (Requirement::FixedReg(preg), Requirement::Register) => Requirement::FixedReg(preg),
|
||||
(Requirement::Stack, Requirement::FixedStack(preg))
|
||||
| (Requirement::FixedStack(preg), Requirement::Stack) => Requirement::FixedStack(preg),
|
||||
(Requirement::FixedReg(a), Requirement::FixedReg(b)) if a == b => self,
|
||||
(Requirement::FixedStack(a), Requirement::FixedStack(b)) if a == b => self,
|
||||
_ => Requirement::Conflict,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F: Function> Env<'a, F> {
|
||||
#[inline(always)]
|
||||
pub fn merge_requirement(&self, a: Requirement, b: Requirement) -> Requirement {
|
||||
match (a, b) {
|
||||
(Requirement::Unknown, other) | (other, Requirement::Unknown) => other,
|
||||
(Requirement::Conflict, _) | (_, Requirement::Conflict) => Requirement::Conflict,
|
||||
(other, Requirement::Any) | (Requirement::Any, other) => other,
|
||||
(Requirement::Stack, Requirement::Stack) => Requirement::Stack,
|
||||
(Requirement::Register, Requirement::Register) => Requirement::Register,
|
||||
(Requirement::Register, Requirement::Fixed(preg))
|
||||
| (Requirement::Fixed(preg), Requirement::Register) if !self.pregs[preg.index()].is_stack => Requirement::Fixed(preg),
|
||||
(Requirement::Stack, Requirement::Fixed(preg))
|
||||
| (Requirement::Fixed(preg), Requirement::Stack) if self.pregs[preg.index()].is_stack => Requirement::Fixed(preg),
|
||||
(Requirement::Fixed(a), Requirement::Fixed(b)) if a == b => Requirement::Fixed(a),
|
||||
_ => Requirement::Conflict,
|
||||
pub fn requirement_from_operand(&self, op: Operand) -> Requirement {
|
||||
match op.constraint() {
|
||||
OperandConstraint::FixedReg(preg) => {
|
||||
if self.pregs[preg.index()].is_stack {
|
||||
Requirement::FixedStack(preg)
|
||||
} else {
|
||||
Requirement::FixedReg(preg)
|
||||
}
|
||||
}
|
||||
OperandConstraint::Reg | OperandConstraint::Reuse(_) => Requirement::Register,
|
||||
OperandConstraint::Stack => Requirement::Stack,
|
||||
_ => Requirement::Any,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_requirement(&self, bundle: LiveBundleIndex) -> Requirement {
|
||||
pub fn compute_requirement(&self, bundle: LiveBundleIndex) -> (Requirement, ProgPoint) {
|
||||
let mut req = Requirement::Unknown;
|
||||
log::trace!("compute_requirement: {:?}", bundle);
|
||||
for entry in &self.bundles[bundle.index()].ranges {
|
||||
let ranges = &self.bundles[bundle.index()].ranges;
|
||||
for entry in ranges {
|
||||
log::trace!(" -> LR {:?}", entry.index);
|
||||
for u in &self.ranges[entry.index.index()].uses {
|
||||
log::trace!(" -> use {:?}", u);
|
||||
let r = Requirement::from_operand(u.operand);
|
||||
req = self.merge_requirement(req, r);
|
||||
let r = self.requirement_from_operand(u.operand);
|
||||
req = req.merge(r);
|
||||
log::trace!(" -> req {:?}", req);
|
||||
if req == Requirement::Conflict {
|
||||
return (req, u.pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
log::trace!(" -> final: {:?}", req);
|
||||
req
|
||||
(req, ranges.first().unwrap().range.from)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user