///|
/// Share call transfer planning between emission and its register footprint.
fn plan_call_arguments(
allocation : @vcode.Allocation,
instruction : @vcode.Instruction,
types : Array[@native.ValueType],
locations : ArrayView[CallArgumentLocation],
stack_size : Int32,
operand_start~ : Int32 = 0,
stack_base~ : Int32 = 0,
callee? : (Int32, @vcode.PhysicalReg),
result_area? : (Int32, @vcode.PhysicalReg),
) -> @vcode.ResolvedCallTransferPlan raise @vcode.CallTransferError {
let transfers = @vcode.call_argument_transfers(
allocation,
instruction,
types,
locations,
operand_start~,
stack_base~,
callee?,
result_area?,
)
let int_scratch : Array[@vcode.PhysicalReg] = []
for id in [10, 11, 0] {
let used_by_callee = callee is Some((_, destination)) &&
destination.id == id
let used_by_result_area = result_area is Some((_, destination)) &&
destination.id == id
if !used_by_callee && !used_by_result_area {
int_scratch.push(@vcode.PhysicalReg::new(id, Int))
}
}
@vcode.plan_resolved_call_transfers(
allocation,
transfers,
stack_base,
stack_size,
int_scratch,
[
@vcode.PhysicalReg::new(14, FpVector),
@vcode.PhysicalReg::new(15, FpVector),
],
int_transfer_scratch(),
fp_transfer_scratch(),
allocation.safepoint_roots(instruction).map(entry => entry.1),
)
}
///|
fn instruction_call_plan(
inst : X64Inst,
allocation : @vcode.Allocation,
instruction : @vcode.Instruction,
stack_base~ : Int32 = 0,
) -> @vcode.ResolvedCallTransferPlan? raise @vcode.CallTransferError {
match inst {
PlatformCall(_, signature) | ReturnsTwicePlatformCall(_, signature) => {
let layout = platform_call_layout(signature.params)
Some(
plan_call_arguments(
allocation,
instruction,
signature.params,
layout.arguments,
layout.stack_size,
stack_base~,
),
)
}
InternalCall(_, signature, plan)
| InternalCallIndirect(signature, plan)
| TailCallDirect(_, signature, plan)
| TailCallIndirect(signature, plan) => {
let indirect = inst is InternalCallIndirect(_, _) ||
inst is TailCallIndirect(_, _)
let operand_start = if indirect { 1 } else { 0 }
let callee = if indirect { Some((0, int_physical(0))) } else { None }
let result_area = if inst is TailCallDirect(_, _, _) ||
inst is TailCallIndirect(_, _) {
plan
.result_area_register()
.map(destination => {
(signature.params.length() + operand_start, destination)
})
} else {
None
}
Some(
plan_call_arguments(
allocation,
instruction,
signature.params,
plan.arguments,
plan.stack_size,
operand_start~,
stack_base~,
callee?,
result_area?,
),
)
}
_ => None
}
}