Handle i128 arguments in the aarch64 ABI

When dealing with params that need to be split, we follow the
arch64 ABI and split the value in two, and make sure that start that
argument in an even numbered xN register.

The apple ABI does not require this, so on those platforms, we start
params anywhere.
This commit is contained in:
Afonso Bordado
2021-05-11 10:25:33 +01:00
parent 5fb2c8c235
commit ac624da8d9
4 changed files with 362 additions and 97 deletions

View File

@@ -1572,10 +1572,21 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
// N.B.: according to the AArch64 ABI, the top bits of a register
// (above the bits for the value's type) are undefined, so we
// need not extend the return values.
let reg = put_input_in_reg(ctx, *input, NarrowValueMode::None);
let retval_reg = ctx.retval(i).only_reg().unwrap();
let src_regs = put_input_in_regs(ctx, *input);
let retval_regs = ctx.retval(i);
assert_eq!(src_regs.len(), retval_regs.len());
let ty = ctx.input_ty(insn, i);
ctx.emit(Inst::gen_move(retval_reg, reg, ty));
let (_, tys) = Inst::rc_for_type(ty)?;
src_regs
.regs()
.iter()
.zip(retval_regs.regs().iter())
.zip(tys.iter())
.for_each(|((&src, &dst), &ty)| {
ctx.emit(Inst::gen_move(dst, src, ty));
});
}
// N.B.: the Ret itself is generated by the ABI.
}
@@ -1753,13 +1764,13 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
assert!(inputs.len() == abi.num_args());
for i in abi.get_copy_to_arg_order() {
let input = inputs[i];
let arg_reg = put_input_in_reg(ctx, input, NarrowValueMode::None);
abi.emit_copy_regs_to_arg(ctx, i, ValueRegs::one(arg_reg));
let arg_regs = put_input_in_regs(ctx, input);
abi.emit_copy_regs_to_arg(ctx, i, arg_regs);
}
abi.emit_call(ctx);
for (i, output) in outputs.iter().enumerate() {
let retval_reg = get_output_reg(ctx, *output).only_reg().unwrap();
abi.emit_copy_retval_to_regs(ctx, i, ValueRegs::one(retval_reg));
let retval_regs = get_output_reg(ctx, *output);
abi.emit_copy_retval_to_regs(ctx, i, retval_regs);
}
abi.emit_stack_post_adjust(ctx);
}
@@ -2306,7 +2317,39 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
panic!("Vector ops not implemented.");
}
Opcode::Isplit | Opcode::Iconcat => panic!("Vector ops not supported."),
Opcode::Isplit => {
assert_eq!(
ctx.input_ty(insn, 0),
I128,
"Isplit only implemented for i128's"
);
assert_eq!(ctx.output_ty(insn, 0), I64);
assert_eq!(ctx.output_ty(insn, 1), I64);
let src_regs = put_input_in_regs(ctx, inputs[0]);
let dst_lo = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let dst_hi = get_output_reg(ctx, outputs[1]).only_reg().unwrap();
ctx.emit(Inst::gen_move(dst_lo, src_regs.regs()[0], I64));
ctx.emit(Inst::gen_move(dst_hi, src_regs.regs()[1], I64));
}
Opcode::Iconcat => {
assert_eq!(
ctx.output_ty(insn, 0),
I128,
"Iconcat only implemented for i128's"
);
assert_eq!(ctx.input_ty(insn, 0), I64);
assert_eq!(ctx.input_ty(insn, 1), I64);
let src_lo = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let src_hi = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
let dst = get_output_reg(ctx, outputs[0]);
ctx.emit(Inst::gen_move(dst.regs()[0], src_lo, I64));
ctx.emit(Inst::gen_move(dst.regs()[1], src_hi, I64));
}
Opcode::Imax | Opcode::Umax | Opcode::Umin | Opcode::Imin => {
let alu_op = match op {