Assign stack slots to incoming function arguments.
Function arguments that don't fit in registers are passed on the stack. Create "incoming_arg" stack slots representing the stack arguments, and assign them to the value arguments during spilling.
This commit is contained in:
@@ -109,3 +109,15 @@ ebb0(v0: i32):
|
|||||||
; check: call_indirect $sig0, $v0($v0, $c)
|
; check: call_indirect $sig0, $v0($v0, $c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Two arguments on the stack.
|
||||||
|
function %stackargs(i32, i32, i32, i32, i32, i32, i32, i32) -> i32 {
|
||||||
|
; check: ss0 = incoming_arg 4
|
||||||
|
; check: ss1 = incoming_arg 4, offset 4
|
||||||
|
; not: incoming_arg
|
||||||
|
ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32):
|
||||||
|
; unordered: fill $v6
|
||||||
|
; unordered: fill $v7
|
||||||
|
v10 = iadd v6, v7
|
||||||
|
return v10
|
||||||
|
}
|
||||||
|
|||||||
@@ -155,10 +155,10 @@ impl StackSlots {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a stack slot representing an incoming function argument.
|
/// Create a stack slot representing an incoming function argument.
|
||||||
pub fn make_incoming_arg(&mut self, ty: Type, offset: u32) -> StackSlot {
|
pub fn make_incoming_arg(&mut self, ty: Type, offset: i32) -> StackSlot {
|
||||||
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, ty.bytes());
|
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, ty.bytes());
|
||||||
assert!(offset <= i32::max_value() as u32 - data.size);
|
assert!(offset <= i32::max_value() - data.size as i32);
|
||||||
data.offset = offset as i32;
|
data.offset = offset;
|
||||||
self.push(data)
|
self.push(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,14 @@ impl ArgumentLoc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this a stack location?
|
||||||
|
pub fn is_stack(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
ArgumentLoc::Stack(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return an object that can display this argument location, using the register info from the
|
/// Return an object that can display this argument location, using the register info from the
|
||||||
/// target ISA.
|
/// target ISA.
|
||||||
pub fn display<'a, R: Into<Option<&'a RegInfo>>>(self, regs: R) -> DisplayArgumentLoc<'a> {
|
pub fn display<'a, R: Into<Option<&'a RegInfo>>>(self, regs: R) -> DisplayArgumentLoc<'a> {
|
||||||
|
|||||||
@@ -253,19 +253,8 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Affinity::Stack => {
|
// The spiller will have assigned an incoming stack slot already.
|
||||||
if let ArgumentLoc::Stack(_offset) = abi.location {
|
Affinity::Stack => assert!(abi.location.is_stack()),
|
||||||
// TODO: Allocate a stack slot at incoming offset and assign it.
|
|
||||||
panic!("Unimplemented {}: {} stack allocation",
|
|
||||||
lv.value,
|
|
||||||
abi.display(&self.reginfo));
|
|
||||||
} else {
|
|
||||||
// This should have been fixed by the reload pass.
|
|
||||||
panic!("Entry arg {} has stack affinity, but ABI {}",
|
|
||||||
lv.value,
|
|
||||||
abi.display(&self.reginfo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This is a ghost value, unused in the function. Don't assign it to a location
|
// This is a ghost value, unused in the function. Don't assign it to a location
|
||||||
// either.
|
// either.
|
||||||
Affinity::None => {}
|
Affinity::None => {}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use ir::{DataFlowGraph, Layout, Cursor, InstBuilder};
|
use ir::{DataFlowGraph, Layout, Cursor, InstBuilder};
|
||||||
use ir::{Function, Ebb, Inst, Value, ValueLoc, SigRef};
|
use ir::{Function, Ebb, Inst, Value, ValueLoc, ArgumentLoc, Signature, SigRef};
|
||||||
use ir::{InstEncodings, StackSlots, ValueLocations};
|
use ir::{InstEncodings, StackSlots, ValueLocations};
|
||||||
use isa::registers::{RegClass, RegClassMask};
|
use isa::registers::{RegClass, RegClassMask};
|
||||||
use isa::{TargetIsa, RegInfo, EncInfo, RecipeConstraints, ConstraintKind};
|
use isa::{TargetIsa, RegInfo, EncInfo, RecipeConstraints, ConstraintKind};
|
||||||
@@ -45,6 +45,7 @@ struct Context<'a> {
|
|||||||
encodings: &'a mut InstEncodings,
|
encodings: &'a mut InstEncodings,
|
||||||
stack_slots: &'a mut StackSlots,
|
stack_slots: &'a mut StackSlots,
|
||||||
locations: &'a mut ValueLocations,
|
locations: &'a mut ValueLocations,
|
||||||
|
func_signature: &'a Signature,
|
||||||
|
|
||||||
// References to contextual data structures we need.
|
// References to contextual data structures we need.
|
||||||
domtree: &'a DominatorTree,
|
domtree: &'a DominatorTree,
|
||||||
@@ -92,6 +93,7 @@ impl Spilling {
|
|||||||
encodings: &mut func.encodings,
|
encodings: &mut func.encodings,
|
||||||
stack_slots: &mut func.stack_slots,
|
stack_slots: &mut func.stack_slots,
|
||||||
locations: &mut func.locations,
|
locations: &mut func.locations,
|
||||||
|
func_signature: &func.signature,
|
||||||
domtree,
|
domtree,
|
||||||
liveness,
|
liveness,
|
||||||
virtregs,
|
virtregs,
|
||||||
@@ -109,12 +111,37 @@ impl<'a> Context<'a> {
|
|||||||
layout: &mut Layout,
|
layout: &mut Layout,
|
||||||
dfg: &mut DataFlowGraph,
|
dfg: &mut DataFlowGraph,
|
||||||
tracker: &mut LiveValueTracker) {
|
tracker: &mut LiveValueTracker) {
|
||||||
|
if let Some(entry) = layout.entry_block() {
|
||||||
|
self.spill_entry_arguments(entry, dfg);
|
||||||
|
}
|
||||||
|
|
||||||
self.topo.reset(layout.ebbs());
|
self.topo.reset(layout.ebbs());
|
||||||
while let Some(ebb) = self.topo.next(layout, self.domtree) {
|
while let Some(ebb) = self.topo.next(layout, self.domtree) {
|
||||||
self.visit_ebb(ebb, layout, dfg, tracker);
|
self.visit_ebb(ebb, layout, dfg, tracker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Assign stack slots to incoming function arguments on the stack.
|
||||||
|
fn spill_entry_arguments(&mut self, entry: Ebb, dfg: &DataFlowGraph) {
|
||||||
|
for (abi, &arg) in self.func_signature
|
||||||
|
.argument_types
|
||||||
|
.iter()
|
||||||
|
.zip(dfg.ebb_args(entry)) {
|
||||||
|
if let ArgumentLoc::Stack(offset) = abi.location {
|
||||||
|
// Function arguments passed on the stack can't be part of a virtual register. We
|
||||||
|
// would need to write other values to the stack slot, but it belongs to the
|
||||||
|
// caller. (Not that the caller would care, nobody depends on stack arguments being
|
||||||
|
// preserved across calls).
|
||||||
|
assert_eq!(self.virtregs.get(arg),
|
||||||
|
None,
|
||||||
|
"Stack argument {} can't be part of a virtual register",
|
||||||
|
arg);
|
||||||
|
let ss = self.stack_slots.make_incoming_arg(abi.value_type, offset);
|
||||||
|
*self.locations.ensure(arg) = ValueLoc::Stack(ss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_ebb(&mut self,
|
fn visit_ebb(&mut self,
|
||||||
ebb: Ebb,
|
ebb: Ebb,
|
||||||
layout: &mut Layout,
|
layout: &mut Layout,
|
||||||
|
|||||||
Reference in New Issue
Block a user