WIP
This commit is contained in:
@@ -940,7 +940,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
Some(slot) => slot,
|
Some(slot) => slot,
|
||||||
None => self.alloc_stack_slot(op.vreg()),
|
None => self.alloc_stack_slot(op.vreg()),
|
||||||
};
|
};
|
||||||
self.move_to_stack(op.vreg(), ProgPoint::before(inst));
|
self.move_to_stack(op.vreg().vreg(), ProgPoint::before(inst));
|
||||||
trace!(" -> Allocated op {} to slot {}", op_idx, slot);
|
trace!(" -> Allocated op {} to slot {}", op_idx, slot);
|
||||||
} else {
|
} else {
|
||||||
self.allocs[alloc_idx + op_idx] = Allocation::reg(preg);
|
self.allocs[alloc_idx + op_idx] = Allocation::reg(preg);
|
||||||
@@ -1406,7 +1406,197 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
block: Block,
|
block: Block,
|
||||||
succ: Block,
|
succ: Block,
|
||||||
) -> Result<(), RegAllocError> {
|
) -> Result<(), RegAllocError> {
|
||||||
todo!()
|
trace!(" -> Block has a single allocated edge. Moving");
|
||||||
|
let succ_params = self.func.block_params(succ);
|
||||||
|
let last_inst = self.func.block_insns(block).last();
|
||||||
|
debug_assert!(self.func.is_branch(last_inst));
|
||||||
|
let out_vregs = self.func.branch_blockparams(block, last_inst, 0);
|
||||||
|
debug_assert_eq!(succ_params.len(), out_vregs.len());
|
||||||
|
|
||||||
|
// first handle all the stack moves
|
||||||
|
// then registers
|
||||||
|
let succ_liveins = &self.liveins[succ.index()];
|
||||||
|
let succ_livein_loc_idx = self.livein_loc_lookup[succ.index()] as usize;
|
||||||
|
|
||||||
|
// live vregs that need to be in certain registers
|
||||||
|
let mut live_vregs_in_pregs = Vec::new();
|
||||||
|
|
||||||
|
let mut loc_idx = succ_livein_loc_idx;
|
||||||
|
for live_vreg in succ_liveins.iter() {
|
||||||
|
let loc = self.livein_locs[loc_idx];
|
||||||
|
match loc.slot() {
|
||||||
|
Some(idx) => {
|
||||||
|
if self.vregs[live_vreg].stack_slot().is_none() {
|
||||||
|
// inlined because i dont have the nerve to deal with the borrow checker
|
||||||
|
// self.move_to_stack(live_vreg, ProgPoint::before(last_inst));
|
||||||
|
|
||||||
|
// must exist
|
||||||
|
let slot = self.vregs[live_vreg].allocated_stack_slot().unwrap();
|
||||||
|
|
||||||
|
let preg = if let Some(preg) = self.vregs[live_vreg].preg() {
|
||||||
|
preg
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Trying to move {} to stack but it is not in a preg",
|
||||||
|
live_vreg
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!("Moving {} from {} to slot {}", live_vreg, preg, slot);
|
||||||
|
self.edits.push((
|
||||||
|
ProgPoint::before(last_inst),
|
||||||
|
Edit::Move {
|
||||||
|
from: Allocation::reg(preg),
|
||||||
|
to: Allocation::stack(SpillSlot::new(slot as usize)),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
self.vregs[live_vreg].set_stack_slot_valid();
|
||||||
|
} else {
|
||||||
|
debug_assert_eq!(self.vregs[live_vreg].stack_slot().unwrap(), idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// don't need to reset stack alloc since that is handled when allocating the block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(preg) = loc.preg() {
|
||||||
|
live_vregs_in_pregs.push((live_vreg, preg));
|
||||||
|
} else {
|
||||||
|
self.vregs[live_vreg].cur_use_idx -= 1;
|
||||||
|
}
|
||||||
|
loc_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..out_vregs.len() {
|
||||||
|
let out_vreg = out_vregs[i];
|
||||||
|
let succ_vreg = succ_params[i];
|
||||||
|
let loc = self.livein_locs[loc_idx];
|
||||||
|
match loc.slot() {
|
||||||
|
Some(slot) => {
|
||||||
|
if self.vregs[out_vreg.vreg()].preg().is_none() {
|
||||||
|
// TODO: we could also use a single temp register
|
||||||
|
let preg = self.find_free_reg(
|
||||||
|
out_vreg.class(),
|
||||||
|
PRegSet::empty(),
|
||||||
|
Some(ProgPoint::before(last_inst)),
|
||||||
|
block,
|
||||||
|
self.cur_inst_pos + 1,
|
||||||
|
)?;
|
||||||
|
self.move_vreg_to_preg(
|
||||||
|
out_vreg,
|
||||||
|
preg,
|
||||||
|
ProgPoint::before(last_inst),
|
||||||
|
block,
|
||||||
|
self.cur_inst_pos + 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let preg = self.vregs[out_vreg.vreg()].preg().unwrap();
|
||||||
|
// since this is the stack slot of
|
||||||
|
trace!("Moving {} from {} to slot {}", out_vreg, preg, slot);
|
||||||
|
self.edits.push((
|
||||||
|
ProgPoint::before(last_inst),
|
||||||
|
Edit::Move {
|
||||||
|
from: Allocation::reg(preg),
|
||||||
|
to: Allocation::stack(SpillSlot::new(slot as usize)),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
self.vregs[succ_vreg.vreg()].set_stack_slot_valid();
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
if loc.preg().is_none() {
|
||||||
|
self.vregs[out_vreg.vreg()].cur_use_idx -= 1;
|
||||||
|
}
|
||||||
|
loc_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move to pregs, note: this can unnecessarily spill
|
||||||
|
for &(live_vreg, target_preg) in &live_vregs_in_pregs {
|
||||||
|
self.vregs[live_vreg].cur_use_idx -= 1;
|
||||||
|
if let Some(cur_preg) = self.vregs[live_vreg].preg() {
|
||||||
|
if cur_preg == target_preg {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cur_vreg) = self.pregs[target_preg.index()].vreg() {
|
||||||
|
if !self.vreg_killed(cur_vreg.vreg(), block, self.cur_inst_pos + 1, true) {
|
||||||
|
if self.vregs[cur_vreg.vreg()].stack_slot().is_none() {
|
||||||
|
self.alloc_and_move_to_stack(cur_vreg, ProgPoint::before(last_inst));
|
||||||
|
}
|
||||||
|
self.clear_preg(target_preg.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cur_preg) = self.vregs[live_vreg].preg() {
|
||||||
|
self.vregs[live_vreg].set_preg(target_preg);
|
||||||
|
self.pregs[cur_preg.index()].clear_vreg();
|
||||||
|
self.pregs[target_preg.index()].set_vreg(VReg::new(live_vreg, target_preg.class()));
|
||||||
|
self.edits.push((
|
||||||
|
ProgPoint::before(last_inst),
|
||||||
|
Edit::Move {
|
||||||
|
from: Allocation::reg(cur_preg),
|
||||||
|
to: Allocation::reg(target_preg),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
self.move_vreg_to_preg(
|
||||||
|
VReg::new(live_vreg, target_preg.class()),
|
||||||
|
target_preg,
|
||||||
|
ProgPoint::before(last_inst),
|
||||||
|
block,
|
||||||
|
self.cur_inst_pos + 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loc_idx -= out_vregs.len();
|
||||||
|
for &out_vreg in out_vregs {
|
||||||
|
let loc = self.livein_locs[loc_idx];
|
||||||
|
if let Some(target_preg) = loc.preg() {
|
||||||
|
self.vregs[out_vreg.vreg()].cur_use_idx -= 1;
|
||||||
|
if let Some(cur_preg) = self.vregs[out_vreg.vreg()].preg() {
|
||||||
|
if cur_preg == target_preg {
|
||||||
|
loc_idx += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cur_vreg) = self.pregs[target_preg.index()].vreg() {
|
||||||
|
if !self.vreg_killed(cur_vreg.vreg(), block, self.cur_inst_pos + 1, true) {
|
||||||
|
if self.vregs[cur_vreg.vreg()].stack_slot().is_none() {
|
||||||
|
self.alloc_and_move_to_stack(cur_vreg, ProgPoint::before(last_inst));
|
||||||
|
}
|
||||||
|
self.clear_preg(target_preg.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cur_preg) = self.vregs[out_vreg.vreg()].preg() {
|
||||||
|
self.vregs[out_vreg.vreg()].set_preg(target_preg);
|
||||||
|
self.pregs[cur_preg.index()].clear_vreg();
|
||||||
|
self.pregs[target_preg.index()].set_vreg(out_vreg);
|
||||||
|
self.edits.push((
|
||||||
|
ProgPoint::before(last_inst),
|
||||||
|
Edit::Move {
|
||||||
|
from: Allocation::reg(cur_preg),
|
||||||
|
to: Allocation::reg(target_preg),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
self.move_vreg_to_preg(
|
||||||
|
out_vreg,
|
||||||
|
target_preg,
|
||||||
|
ProgPoint::before(last_inst),
|
||||||
|
block,
|
||||||
|
self.cur_inst_pos + 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loc_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check if the reftype count is correctly managed
|
// TODO: check if the reftype count is correctly managed
|
||||||
@@ -1797,19 +1987,19 @@ impl<'a, F: Function> FastAlloc<'a, F> {
|
|||||||
// panics if there is a stack slot already or the vreg is not in a preg
|
// panics if there is a stack slot already or the vreg is not in a preg
|
||||||
fn alloc_and_move_to_stack(&mut self, vreg: VReg, pos: ProgPoint) {
|
fn alloc_and_move_to_stack(&mut self, vreg: VReg, pos: ProgPoint) {
|
||||||
self.alloc_stack_slot(vreg);
|
self.alloc_stack_slot(vreg);
|
||||||
self.move_to_stack(vreg, pos);
|
self.move_to_stack(vreg.vreg(), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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: usize, pos: ProgPoint) {
|
||||||
let slot = if let Some(slot) = self.vregs[vreg.vreg()].allocated_stack_slot() {
|
let slot = if let Some(slot) = self.vregs[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);
|
||||||
};
|
};
|
||||||
|
|
||||||
let preg = if let Some(preg) = self.vregs[vreg.vreg()].preg() {
|
let preg = if let Some(preg) = self.vregs[vreg].preg() {
|
||||||
preg
|
preg
|
||||||
} else {
|
} else {
|
||||||
panic!("Trying to move {} to stack but it is not in a preg", vreg);
|
panic!("Trying to move {} to stack but it is not in a preg", vreg);
|
||||||
@@ -1823,7 +2013,7 @@ 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();
|
self.vregs[vreg].set_stack_slot_valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocates a stack slot for a vreg
|
// Allocates a stack slot for a vreg
|
||||||
|
|||||||
Reference in New Issue
Block a user