WIP
This commit is contained in:
@@ -23,7 +23,7 @@ struct VRegData {
|
|||||||
preg: PReg,
|
preg: PReg,
|
||||||
stack_slot: u32,
|
stack_slot: u32,
|
||||||
|
|
||||||
// 1 = reftype, 2 = preg_valid, 4 = stack_slot_valid
|
// 1 = reftype, 2 = preg_valid, 4 = stack_slot_valid, 8 = stack_slot_allocated
|
||||||
flags: u8,
|
flags: u8,
|
||||||
|
|
||||||
// use information
|
// use information
|
||||||
@@ -114,7 +114,8 @@ impl Default for VRegData {
|
|||||||
impl VRegData {
|
impl VRegData {
|
||||||
const FLAG_REFTYPE: u8 = 1;
|
const FLAG_REFTYPE: u8 = 1;
|
||||||
const FLAG_PREG: u8 = 2;
|
const FLAG_PREG: u8 = 2;
|
||||||
const FLAG_SLOT: u8 = 4;
|
const FLAG_SLOT_VALID: u8 = 4;
|
||||||
|
const FLAG_SLOT_ALLOCATED: u8 = 8;
|
||||||
|
|
||||||
pub fn preg(&self) -> Option<PReg> {
|
pub fn preg(&self) -> Option<PReg> {
|
||||||
if self.flags & Self::FLAG_PREG != 0 {
|
if self.flags & Self::FLAG_PREG != 0 {
|
||||||
@@ -137,24 +138,50 @@ impl VRegData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack_slot(&self) -> Option<u32> {
|
pub fn stack_slot(&self) -> Option<u32> {
|
||||||
if self.flags & Self::FLAG_SLOT != 0 {
|
if self.flags & Self::FLAG_SLOT_VALID != 0 {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
if self.flags & Self::FLAG_SLOT_ALLOCATED == 0 {
|
||||||
|
panic!("Encountered stack slot that is valid but not allocated");
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(self.stack_slot)
|
Some(self.stack_slot)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_stack_slot(&mut self, slot: u32) {
|
pub fn allocated_stack_slot(&self) -> Option<u32> {
|
||||||
self.stack_slot = slot;
|
if self.flags & Self::FLAG_SLOT_ALLOCATED != 0 {
|
||||||
self.flags |= Self::FLAG_SLOT;
|
Some(self.stack_slot)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_stack_slot(&mut self) {
|
pub fn set_stack_slot_allocated(&mut self, slot: u32) {
|
||||||
self.flags &= !Self::FLAG_SLOT;
|
self.stack_slot = slot;
|
||||||
|
self.flags |= Self::FLAG_SLOT_ALLOCATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_stack_slot_valid(&mut self) {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
if (self.flags & Self::FLAG_SLOT_ALLOCATED) == 0 {
|
||||||
|
panic!("Trying to set a nonallocated stack slot to valid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.flags |= Self::FLAG_SLOT_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_stack_slot(&mut self, only_valid: bool) {
|
||||||
|
if only_valid {
|
||||||
|
self.flags &= !Self::FLAG_SLOT_VALID;
|
||||||
|
} else {
|
||||||
|
self.flags &= !(Self::FLAG_SLOT_ALLOCATED | Self::FLAG_SLOT_VALID);
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
self.stack_slot = 0xFFFFFFFF;
|
self.stack_slot = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_reftype(&self) -> bool {
|
pub fn is_reftype(&self) -> bool {
|
||||||
self.flags & Self::FLAG_REFTYPE != 0
|
self.flags & Self::FLAG_REFTYPE != 0
|
||||||
@@ -631,10 +658,12 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let data = &mut self.vregs[vreg];
|
let data = &mut self.vregs[vreg];
|
||||||
match loc.slot() {
|
match loc.slot() {
|
||||||
Some(slot) => {
|
Some(slot) => {
|
||||||
data.set_stack_slot(slot);
|
debug_assert!(data.allocated_stack_slot().is_some());
|
||||||
|
debug_assert_eq!(data.allocated_stack_slot().unwrap(), slot);
|
||||||
|
data.set_stack_slot_valid();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
data.clear_stack_slot();
|
data.clear_stack_slot(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,7 +941,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let new_preg = self.find_free_reg(
|
let new_preg = self.find_free_reg(
|
||||||
op.vreg().class(),
|
op.vreg().class(),
|
||||||
reg_blacklist,
|
reg_blacklist,
|
||||||
true,
|
Some(ProgPoint::before(inst)),
|
||||||
block,
|
block,
|
||||||
block_after_pos,
|
block_after_pos,
|
||||||
)?;
|
)?;
|
||||||
@@ -949,7 +978,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let preg = self.find_free_reg(
|
let preg = self.find_free_reg(
|
||||||
op.vreg().class(),
|
op.vreg().class(),
|
||||||
reg_blacklist,
|
reg_blacklist,
|
||||||
true,
|
Some(ProgPoint::before(inst)),
|
||||||
block,
|
block,
|
||||||
block_after_pos,
|
block_after_pos,
|
||||||
)?;
|
)?;
|
||||||
@@ -974,7 +1003,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let preg = self.find_free_reg(
|
let preg = self.find_free_reg(
|
||||||
op.vreg().class(),
|
op.vreg().class(),
|
||||||
reg_blacklist,
|
reg_blacklist,
|
||||||
true,
|
Some(ProgPoint::before(inst)),
|
||||||
block,
|
block,
|
||||||
block_after_pos,
|
block_after_pos,
|
||||||
)?;
|
)?;
|
||||||
@@ -1102,7 +1131,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let preg = self.find_free_reg(
|
let preg = self.find_free_reg(
|
||||||
op.vreg().class(),
|
op.vreg().class(),
|
||||||
late_def_disallow,
|
late_def_disallow,
|
||||||
true,
|
Some(ProgPoint::before(inst)),
|
||||||
block,
|
block,
|
||||||
block_after_pos,
|
block_after_pos,
|
||||||
)?;
|
)?;
|
||||||
@@ -1133,7 +1162,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let preg = self.find_free_reg(
|
let preg = self.find_free_reg(
|
||||||
op.vreg().class(),
|
op.vreg().class(),
|
||||||
reg_blacklist,
|
reg_blacklist,
|
||||||
false,
|
None,
|
||||||
block,
|
block,
|
||||||
block_after_pos,
|
block_after_pos,
|
||||||
);
|
);
|
||||||
@@ -1209,9 +1238,10 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
trace!(" -> {} mapping to {} is killed", out_vreg, succ_param);
|
trace!(" -> {} mapping to {} is killed", out_vreg, succ_param);
|
||||||
if let Some(slot) = self.vregs[out_vreg.vreg()].stack_slot() {
|
if let Some(slot) = self.vregs[out_vreg.vreg()].stack_slot() {
|
||||||
trace!(" -> Transferring slot {} to {}", slot, succ_param);
|
trace!(" -> Transferring slot {} to {}", slot, succ_param);
|
||||||
self.vregs[succ_param.vreg()].set_stack_slot(slot);
|
self.vregs[succ_param.vreg()].set_stack_slot_allocated(slot);
|
||||||
|
self.vregs[succ_param.vreg()].set_stack_slot_valid();
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
self.vregs[out_vreg.vreg()].clear_stack_slot();
|
self.vregs[out_vreg.vreg()].clear_stack_slot(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(preg) = self.vregs[out_vreg.vreg()].preg() {
|
if let Some(preg) = self.vregs[out_vreg.vreg()].preg() {
|
||||||
@@ -1282,7 +1312,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let preg = self.find_free_reg(
|
let preg = self.find_free_reg(
|
||||||
succ_param.class(),
|
succ_param.class(),
|
||||||
pregs_allocated,
|
pregs_allocated,
|
||||||
true,
|
Some(ProgPoint::before(last_inst)),
|
||||||
block,
|
block,
|
||||||
self.cur_inst_pos + 1,
|
self.cur_inst_pos + 1,
|
||||||
)?;
|
)?;
|
||||||
@@ -1392,7 +1422,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
reg_class: RegClass,
|
reg_class: RegClass,
|
||||||
reg_blacklist: PRegSet,
|
reg_blacklist: PRegSet,
|
||||||
spill: bool,
|
spill_pos: Option<ProgPoint>, // does not spill if None
|
||||||
block: Block,
|
block: Block,
|
||||||
block_after_pos: usize,
|
block_after_pos: usize,
|
||||||
) -> Result<PReg, RegAllocError> {
|
) -> Result<PReg, RegAllocError> {
|
||||||
@@ -1411,13 +1441,19 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
match self.pregs[preg.index()].vreg() {
|
match self.pregs[preg.index()].vreg() {
|
||||||
None => return Ok(preg),
|
None => return Ok(preg),
|
||||||
Some(vreg) => {
|
Some(vreg) => {
|
||||||
if self.vreg_killed(vreg.vreg(), inst, block, block_last_inst, true) {
|
if spill_pos.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.vreg_killed(vreg.vreg(), block, block_after_pos, true) {
|
||||||
self.clear_preg(preg.index());
|
self.clear_preg(preg.index());
|
||||||
return Ok(preg);
|
return Ok(preg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: prefer regs that are already spilled?
|
// TODO: prefer regs that are already spilled?
|
||||||
let next_use = self.next_use(vreg.vreg());
|
let next_use = self
|
||||||
|
.next_use(vreg.vreg())
|
||||||
|
.expect("vreg should have next use");
|
||||||
if let Some((use_pos, vreg)) = ffu_reg {
|
if let Some((use_pos, vreg)) = ffu_reg {
|
||||||
if use_pos < next_use {
|
if use_pos < next_use {
|
||||||
ffu_reg = Some((next_use, vreg));
|
ffu_reg = Some((next_use, vreg));
|
||||||
@@ -1436,7 +1472,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
let (_, vreg) = ffu_reg.unwrap();
|
let (_, vreg) = ffu_reg.unwrap();
|
||||||
if self.vregs[vreg.vreg()].stack_slot().is_none() {
|
if self.vregs[vreg.vreg()].stack_slot().is_none() {
|
||||||
// TODO: do we need to specify the progpoint?
|
// TODO: do we need to specify the progpoint?
|
||||||
self.alloc_and_move_to_stack(vreg, ProgPoint::before(inst));
|
self.alloc_and_move_to_stack(vreg, spill_pos.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let preg = self.vregs[vreg.vreg()].preg().unwrap();
|
let preg = self.vregs[vreg.vreg()].preg().unwrap();
|
||||||
@@ -1455,7 +1491,25 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
block: Block,
|
block: Block,
|
||||||
block_after_pos: usize,
|
block_after_pos: usize,
|
||||||
) {
|
) {
|
||||||
todo!("")
|
trace!("Moving {} to {} at {:?}", vreg, preg, pos);
|
||||||
|
if let Some(cur_vreg) = self.pregs[preg.index()].vreg() {
|
||||||
|
if !self.vreg_killed(cur_vreg.vreg(), block, block_after_pos, true) {
|
||||||
|
if self.vregs[cur_vreg.vreg()].stack_slot().is_none() {
|
||||||
|
self.alloc_and_move_to_stack(cur_vreg, pos);
|
||||||
|
}
|
||||||
|
self.clear_preg(preg.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let slot = self.vregs[vreg.vreg()].stack_slot().unwrap();
|
||||||
|
trace!(" -> from slot {}", slot);
|
||||||
|
self.edits.push((
|
||||||
|
pos,
|
||||||
|
Edit::Move {
|
||||||
|
from: Allocation::stack(SpillSlot::new(slot as usize)),
|
||||||
|
to: Allocation::reg(preg),
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocates a stack slot for a vreg and moves it there
|
// Allocates a stack slot for a vreg and moves it there
|
||||||
@@ -1468,7 +1522,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
// Moves a vreg to stack
|
// Moves a vreg to stack
|
||||||
// panics if there is no stack slot or the vreg is not in a preg
|
// panics if there is no stack slot or the vreg is not in a preg
|
||||||
fn move_to_stack(&mut self, vreg: VReg, pos: ProgPoint) {
|
fn move_to_stack(&mut self, vreg: VReg, pos: ProgPoint) {
|
||||||
let slot = if let Some(slot) = self.vregs[vreg.vreg()].stack_slot() {
|
let slot = if let Some(slot) = self.vregs[vreg.vreg()].allocated_stack_slot() {
|
||||||
slot
|
slot
|
||||||
} else {
|
} else {
|
||||||
panic!("Trying to move {} to stack but it has no slot", vreg);
|
panic!("Trying to move {} to stack but it has no slot", vreg);
|
||||||
@@ -1488,10 +1542,11 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
to: Allocation::stack(SpillSlot::new(slot as usize)),
|
to: Allocation::stack(SpillSlot::new(slot as usize)),
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
self.vregs[vreg.vreg()].set_stack_slot_valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocates a stack slot for a vreg
|
// Allocates a stack slot for a vreg
|
||||||
// panics if there is a slot already
|
// panics if there is a valid slot already
|
||||||
fn alloc_stack_slot(&mut self, vreg: VReg) -> u32 {
|
fn alloc_stack_slot(&mut self, vreg: VReg) -> u32 {
|
||||||
if self.vregs[vreg.vreg()].stack_slot().is_some() {
|
if self.vregs[vreg.vreg()].stack_slot().is_some() {
|
||||||
panic!(
|
panic!(
|
||||||
@@ -1500,11 +1555,21 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let slot = match self.vregs[vreg.vreg()].allocated_stack_slot() {
|
||||||
|
Some(slot) => {
|
||||||
|
trace!("Using already allocated slot {} for {}", slot, vreg);
|
||||||
|
slot
|
||||||
|
}
|
||||||
|
None => {
|
||||||
let slot = self.create_stack_slot(vreg.class());
|
let slot = self.create_stack_slot(vreg.class());
|
||||||
self.vregs[vreg.vreg()].set_stack_slot(slot);
|
self.vregs[vreg.vreg()].set_stack_slot_allocated(slot);
|
||||||
trace!("Allocated slot {} for {}", slot, vreg);
|
trace!("Allocated slot {} for {}", slot, vreg);
|
||||||
slot
|
slot
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
slot
|
||||||
|
}
|
||||||
|
|
||||||
// Creates a stack slot for a given register class
|
// Creates a stack slot for a given register class
|
||||||
fn create_stack_slot(&mut self, class: RegClass) -> u32 {
|
fn create_stack_slot(&mut self, class: RegClass) -> u32 {
|
||||||
@@ -1522,6 +1587,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
// State Helpers
|
// State Helpers
|
||||||
|
|
||||||
// assigns vreg to preg and saves any live vreg in the preg
|
// assigns vreg to preg and saves any live vreg in the preg
|
||||||
|
// does no moving of the vreg
|
||||||
fn allocate_preg_for_vreg(
|
fn allocate_preg_for_vreg(
|
||||||
&mut self,
|
&mut self,
|
||||||
preg: PReg,
|
preg: PReg,
|
||||||
@@ -1530,7 +1596,17 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
block: Block,
|
block: Block,
|
||||||
block_after_pos: usize,
|
block_after_pos: usize,
|
||||||
) {
|
) {
|
||||||
todo!("")
|
trace!("Assigning {} to {} at {:?}", vreg, preg, pos);
|
||||||
|
if let Some(cur_vreg) = self.pregs[preg.index()].vreg() {
|
||||||
|
if !self.vreg_killed(cur_vreg.vreg(), block, block_after_pos, true) {
|
||||||
|
if self.vregs[cur_vreg.vreg()].stack_slot().is_none() {
|
||||||
|
self.alloc_and_move_to_stack(cur_vreg, pos);
|
||||||
|
}
|
||||||
|
self.clear_preg(preg.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assign_preg(preg, vreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_preg(&mut self, preg: PReg, vreg: VReg) {
|
fn assign_preg(&mut self, preg: PReg, vreg: VReg) {
|
||||||
@@ -1646,14 +1722,6 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_use(&self, vreg: usize) -> u32 {
|
|
||||||
let data = &self.vregs[vreg];
|
|
||||||
if data.cur_use_idx as usize >= data.uses.len() {
|
|
||||||
panic!("next_use called on {} which does not have one", vreg);
|
|
||||||
}
|
|
||||||
return data.uses[data.cur_use_idx as usize];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
|
|
||||||
/// Make sure all reftype vregs currently in pregs have a stack slot
|
/// Make sure all reftype vregs currently in pregs have a stack slot
|
||||||
|
|||||||
Reference in New Issue
Block a user