x64 and aarch64: allow StructArgument and StructReturn args.

The StructReturn ABI is fairly simple at the codegen/isel level: we only
need to take care to return the sret pointer as one of the return values
if that wasn't specified in the initial function signature.

Struct arguments are a little more complex. A struct argument is stored
as a chunk of memory in the stack-args space. However, the CLIF
semantics are slightly special: on the caller side, the parameter passed
in is a pointer to an arbitrary memory block, and we must memcpy this
data to the on-stack struct-argument; and on the callee side, we provide
a pointer to the passed-in struct-argument as the CLIF block param
value.

This is necessary to support various ABIs other than Wasm, such as that
of Rust (with the cg_clif codegen backend).
This commit is contained in:
Chris Fallin
2020-12-13 18:50:59 -08:00
parent 25088dee9d
commit 456561f431
14 changed files with 641 additions and 166 deletions

View File

@@ -1083,7 +1083,7 @@ fn emit_vm_call<C: LowerCtx<I = Inst>>(
let sig = make_libcall_sig(ctx, insn, call_conv, types::I64);
let caller_conv = ctx.abi().call_conv();
let mut abi = X64ABICaller::from_func(&sig, &extname, dist, caller_conv)?;
let mut abi = X64ABICaller::from_func(&sig, &extname, dist, caller_conv, flags)?;
abi.emit_stack_pre_adjust(ctx);
@@ -3091,7 +3091,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
assert_eq!(inputs.len(), sig.params.len());
assert_eq!(outputs.len(), sig.returns.len());
(
X64ABICaller::from_func(sig, &extname, dist, caller_conv)?,
X64ABICaller::from_func(sig, &extname, dist, caller_conv, flags)?,
&inputs[..],
)
}
@@ -3102,7 +3102,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
assert_eq!(inputs.len() - 1, sig.params.len());
assert_eq!(outputs.len(), sig.returns.len());
(
X64ABICaller::from_ptr(sig, ptr, op, caller_conv)?,
X64ABICaller::from_ptr(sig, ptr, op, caller_conv, flags)?,
&inputs[1..],
)
}
@@ -3112,8 +3112,9 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
abi.emit_stack_pre_adjust(ctx);
assert_eq!(inputs.len(), abi.num_args());
for (i, input) in inputs.iter().enumerate() {
let arg_regs = put_input_in_regs(ctx, *input);
for i in abi.get_copy_to_arg_order() {
let input = inputs[i];
let arg_regs = put_input_in_regs(ctx, input);
abi.emit_copy_regs_to_arg(ctx, i, arg_regs);
}
abi.emit_call(ctx);