From 4f6346768e154fa719c061c8089f5a68b3a143df Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Fri, 7 May 2021 17:45:51 -0700 Subject: [PATCH] Pinned-VReg mechanism. --- src/ion/mod.rs | 28 ++++++++++++++++++++++++++++ src/lib.rs | 9 +++++++++ 2 files changed, 37 insertions(+) diff --git a/src/ion/mod.rs b/src/ion/mod.rs index e6f3347..25a2312 100644 --- a/src/ion/mod.rs +++ b/src/ion/mod.rs @@ -1718,6 +1718,13 @@ impl<'a, F: Function> Env<'a, F> { return false; } + // If either bundle is already assigned (due to a pinned vreg), don't merge. + if !self.bundles[from.index()].allocation.is_none() + || !self.bundles[to.index()].allocation.is_none() + { + return false; + } + #[cfg(debug)] { // Sanity check: both bundles should contain only ranges with appropriate VReg classes. @@ -1882,6 +1889,22 @@ impl<'a, F: Function> Env<'a, F> { range = self.ranges[range.index()].next_in_reg; } log::debug!("vreg v{} gets bundle{}", vreg.index(), bundle.index()); + + // If this vreg is pinned, assign the allocation and block the PRegs. + if let Some(preg) = self.func.is_pinned_vreg(self.vreg_regs[vreg.index()]) { + self.bundles[bundle.index()].allocation = Allocation::reg(preg); + + let mut iter = self.bundles[bundle.index()].first_range; + while iter.is_valid() { + let range = self.ranges[iter.index()].range; + // Create a new LiveRange for the PReg + // reservation, unaffiliated with the VReg, to + // reserve it (like a clobber) without the + // possibility of eviction. + self.add_liverange_to_preg(range, preg); + iter = self.ranges[iter.index()].next_in_bundle; + } + } } for inst in 0..self.func.insts() { @@ -2006,6 +2029,11 @@ impl<'a, F: Function> Env<'a, F> { let mut lr = self.vregs[vreg.index()].first_range; while lr.is_valid() { let bundle = self.ranges[lr.index()].bundle; + if !self.bundles[bundle.index()].allocation.is_none() { + // Pinned VReg -- already allocated, so skip. + lr = self.ranges[lr.index()].next_in_bundle; + continue; + } if self.bundles[bundle.index()].first_range == lr { // First time seeing `bundle`: allocate a spillslot for it, // compute its priority, and enqueue it. diff --git a/src/lib.rs b/src/lib.rs index 437e6ba..860aa43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -741,6 +741,15 @@ pub trait Function { &[] } + /// Is the given VReg pinned permanently to a PReg? Note that the + /// input program must not contain constraints that contradict + /// this (e.g., using another VReg with a fixed-reg policy to a + /// given preg at the same time as using a VReg pinned to that + /// preg) or else allocation may be impossible. + fn is_pinned_vreg(&self, _: VReg) -> Option { + None + } + // -------------- // Spills/reloads // --------------