use crate::compiler::graph::{BaseOp, Graph, Literal, NodeId, Type};
use super::X64Reg;
const GPR_ARGS: &'static [X64Reg] = &[
X64Reg::RDI,
X64Reg::RSI,
X64Reg::RDX,
X64Reg::RDX,
X64Reg::R8,
X64Reg::R9,
];
const FPR_ARGS: &'static [X64Reg] = &[
X64Reg::XMM0,
X64Reg::XMM1,
X64Reg::XMM2,
X64Reg::XMM3,
X64Reg::XMM4,
X64Reg::XMM5,
];
pub fn coalesce_live_intervals(g: &Graph, n: NodeId, mut coalesce: impl FnMut(NodeId, NodeId)) {
let op = g[n].op::<BaseOp>();
match op {
BaseOp::Add
| BaseOp::Sub
| BaseOp::Mul
| BaseOp::And
| BaseOp::Or
| BaseOp::Xor
| BaseOp::DivS
| BaseOp::DivU
| BaseOp::FDiv => coalesce(n, g[n].inputs[0]),
BaseOp::Move => coalesce(n, g[n].inputs[0]),
BaseOp::ITruncU | BaseOp::SExt | BaseOp::ZExt => coalesce(n, g[n].inputs[0]),
_ => {}
}
}
pub fn pre_assign_registers(g: &mut Graph, n: NodeId) {
let op = g[n].op::<BaseOp>();
match op {
BaseOp::DivS | BaseOp::DivU => {
let mov = g.new_move_input_node(n, 0);
g[mov].fixed_reg = Some(X64Reg::RAX.into());
g[n].fixed_reg = Some(X64Reg::RAX.into());
g.new_move_output_node(n);
}
BaseOp::RemS | BaseOp::RemU => {
let mov = g.new_move_input_node(n, 0);
g[mov].fixed_reg = Some(X64Reg::RAX.into());
g[n].fixed_reg = Some(X64Reg::RDX.into());
g.new_move_output_node(n);
}
BaseOp::Shl | BaseOp::ShrS | BaseOp::ShrU | BaseOp::Rotl | BaseOp::Rotr => {
g.new_move_input_node(n, 0);
let mov = g.new_move_input_node(n, 1);
g[mov].fixed_reg = Some(X64Reg::RCX.into());
}
BaseOp::Return if g[n].inputs.len() > 0 => {
let mov = g.new_move_input_node(n, 0);
if g.signature.1.is_floating_point() {
g[mov].fixed_reg = Some(X64Reg::XMM0.into());
} else {
g[mov].fixed_reg = Some(X64Reg::RAX.into());
}
}
BaseOp::Call | BaseOp::CallIndirect => {
let args_start_index = match op {
BaseOp::CallIndirect if g[n].has_call_indirect_ctx => 2,
BaseOp::CallIndirect if !g[n].has_call_indirect_ctx => 1,
_ => 0,
};
if op == BaseOp::CallIndirect && g[n].has_call_indirect_ctx {
let mov = g.new_move_input_node(n, 1);
g[mov].fixed_reg = Some(X64Reg::R15 as _);
}
macro_rules! iter_args_with_type_filter {
($filter: expr, |$a:ident, $i:ident| $body: tt) => {{
let filter = $filter;
let mut j = 0;
let num_args = g[n].inputs[args_start_index..].len();
for i in 0..num_args {
let arg = g[n].inputs[args_start_index + i];
if !filter(g[arg].ty) {
continue;
}
{
let ($a, $i) = (arg, j);
$body;
}
j += 1;
}
}};
}
iter_args_with_type_filter!(|ty: Type| !ty.is_floating_point(), |a, i| {
if i < GPR_ARGS.len() {
let input_index = g[n].inputs.iter().position(|i| *i == a).unwrap();
let _mov = g.new_move_input_node(n, input_index);
}
});
iter_args_with_type_filter!(|ty: Type| ty.is_floating_point(), |a, i| {
if i < FPR_ARGS.len() {
let input_index = g[n].inputs.iter().position(|i| *i == a).unwrap();
let _mov = g.new_move_input_node(n, input_index);
}
});
iter_args_with_type_filter!(|ty: Type| !ty.is_floating_point(), |a, i| {
if i < GPR_ARGS.len() {
g[a].fixed_reg = Some(GPR_ARGS[i] as _);
}
});
iter_args_with_type_filter!(|ty: Type| ty.is_floating_point(), |a, i| {
if i < FPR_ARGS.len() {
g[a].fixed_reg = Some(FPR_ARGS[i] as _);
}
});
if g[n].ty.is_floating_point() {
g[n].fixed_reg = Some(X64Reg::XMM0.into());
} else {
g[n].fixed_reg = Some(X64Reg::RAX.into());
}
if g[n].ty != Type::Void {
g.new_move_output_node(n);
}
}
BaseOp::Param => {
let param_index = match g[n].literal.as_ref().unwrap() {
Literal::ParamIndex(v) => *v,
_ => unreachable!(),
};
let fixed_reg = if g[n].ty.is_floating_point() {
let mut index = 0;
for i in 0..param_index {
if g.signature.0[i].is_floating_point() {
index += 1;
}
}
FPR_ARGS.get(index)
} else {
let mut index = 0;
for i in 0..param_index {
if !g.signature.0[i].is_floating_point() {
index += 1;
}
}
GPR_ARGS.get(index)
};
g[n].fixed_reg = fixed_reg.map(|r| Into::<usize>::into(*r));
if g[n].fixed_reg.is_none() {
let (mut gprs, mut fprs) = (0, 0);
let mut stack_arg_index = 0;
for i in 0..param_index {
if g.signature.0[i].is_floating_point() && fprs < FPR_ARGS.len() {
fprs += 1;
} else if !g.signature.0[i].is_floating_point() && gprs < GPR_ARGS.len() {
gprs += 1;
} else {
stack_arg_index += 1;
}
}
g[n].stack_arg_index = Some(stack_arg_index);
}
g.new_move_output_node(n);
}
_ => {}
}
}