Skip to content

Commit

Permalink
cranelift: Handle argument extension in the Winch calling convention (b…
Browse files Browse the repository at this point in the history
…ytecodealliance#8215)

* Disable argument packing with the winch cc if extension is present

* Don't generate functions that use SIMD and the Winch calling convention

* Handle i128 values for the winch calling convention
  • Loading branch information
elliottt authored Mar 22, 2024
1 parent 83faa91 commit 8eb7914
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 8 deletions.
33 changes: 26 additions & 7 deletions cranelift/codegen/src/isa/x64/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ impl ABIMachineSpec for X64ABIMachineSpec {
next_stack = 32;
}

// If any param uses extension, the winch calling convention will not pack its results
// on the stack and will instead align them to 8-byte boundaries the same way that all the
// other calling conventions do. This isn't consistent with Winch itself, but is fine as
// Winch only uses this calling convention via trampolines, and those trampolines don't add
// extension annotations. Additionally, handling extension attributes this way allows clif
// functions that use them with the Winch calling convention to interact successfully with
// testing infrastructure.
let uses_extension = params
.iter()
.any(|p| p.extension != ir::ArgumentExtension::None);

for (ix, param) in params.iter().enumerate() {
let last_param = ix == params.len() - 1;

Expand Down Expand Up @@ -213,25 +224,25 @@ impl ABIMachineSpec for X64ABIMachineSpec {
}

let mut slots = ABIArgSlotVec::new();
for (rc, reg_ty) in rcs.iter().zip(reg_tys.iter()) {
for (ix, (rc, reg_ty)) in rcs.iter().zip(reg_tys.iter()).enumerate() {
let last_slot = last_param && ix == rcs.len() - 1;

let intreg = *rc == RegClass::Int;
let nextreg = if intreg {
match args_or_rets {
ArgsOrRets::Args => {
get_intreg_for_arg(&call_conv, next_gpr, next_param_idx)
}
ArgsOrRets::Rets => {
get_intreg_for_retval(&call_conv, flags, next_gpr, last_param)
get_intreg_for_retval(&call_conv, flags, next_gpr, last_slot)
}
}
} else {
match args_or_rets {
ArgsOrRets::Args => {
get_fltreg_for_arg(&call_conv, next_vreg, next_param_idx)
}
ArgsOrRets::Rets => {
get_fltreg_for_retval(&call_conv, next_vreg, last_param)
}
ArgsOrRets::Rets => get_fltreg_for_retval(&call_conv, next_vreg, last_slot),
}
};
next_param_idx += 1;
Expand All @@ -248,7 +259,10 @@ impl ABIMachineSpec for X64ABIMachineSpec {
});
} else {
let size = reg_ty.bytes();
let size = if call_conv == CallConv::Winch && args_or_rets == ArgsOrRets::Rets {
let size = if call_conv == CallConv::Winch
&& args_or_rets == ArgsOrRets::Rets
&& !uses_extension
{
size
} else {
let size = std::cmp::max(size, 8);
Expand Down Expand Up @@ -318,7 +332,12 @@ impl ABIMachineSpec for X64ABIMachineSpec {
if let ABIArg::Slots { slots, .. } = arg {
for slot in slots.iter_mut() {
if let ABIArgSlot::Stack { offset, ty, .. } = slot {
let size = i64::from(ty.bytes());
let size = if uses_extension {
i64::from(std::cmp::max(ty.bytes(), 8))
} else {
i64::from(ty.bytes())
};

*offset = i64::from(next_stack) - *offset - size;
}
}
Expand Down
74 changes: 74 additions & 0 deletions cranelift/filetests/filetests/isa/x64/winch.clif
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,77 @@ block0(v0: i32, v1: i64, v2: i32, v3: i64):
; popq %rbp
; retq

function %stack_result_extension() -> i64, i8 uext, i8 uext winch {
block0:
v0 = iconst.i64 0x00000000ffff2222
v1 = iconst.i8 85
v2 = iconst.i8 11
return v0, v1, v2
}

; VCode:
; pushq %rbp
; movq %rsp, %rbp
; block0:
; movl $-56798, %r11d
; movl $85, %r9d
; movl $11, %r10d
; movq %r11, 8(%rdi)
; movzbq %r9b, %r11
; movq %r9, 0(%rdi)
; movzbq %r10b, %rax
; movq %rbp, %rsp
; popq %rbp
; ret
;
; Disassembled:
; block0: ; offset 0x0
; pushq %rbp
; movq %rsp, %rbp
; block1: ; offset 0x4
; movl $0xffff2222, %r11d
; movl $0x55, %r9d
; movl $0xb, %r10d
; movq %r11, 8(%rdi)
; movzbq %r9b, %r11
; movq %r9, (%rdi)
; movzbq %r10b, %rax
; movq %rbp, %rsp
; popq %rbp
; retq

function %stack_result_no_extension() -> i64, i8, i8 winch {
block0:
v0 = iconst.i64 0x00000000ffff2222
v1 = iconst.i8 85
v2 = iconst.i8 11
return v0, v1, v2
}

; VCode:
; pushq %rbp
; movq %rsp, %rbp
; block0:
; movl $-56798, %edx
; movl $85, %r8d
; movl $11, %eax
; movq %rdx, 1(%rdi)
; movb %r8b, 0(%rdi)
; movq %rbp, %rsp
; popq %rbp
; ret
;
; Disassembled:
; block0: ; offset 0x0
; pushq %rbp
; movq %rsp, %rbp
; block1: ; offset 0x4
; movl $0xffff2222, %edx
; movl $0x55, %r8d
; movl $0xb, %eax
; movq %rdx, 1(%rdi)
; movb %r8b, (%rdi)
; movq %rbp, %rsp
; popq %rbp
; retq

30 changes: 30 additions & 0 deletions cranelift/filetests/filetests/runtests/winch.clif
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,33 @@ block0:
}

; run: %call_winch() == [3, 2, 1, 0]

function %f1() -> i8 uext, i64, i8 uext winch {
block0:
v0 = iconst.i64 0x40070000ffff2222
v1 = iconst.i8 85
v2 = iconst.i8 11
return v1, v0, v2
}

; run: %f1() == [85, 0x40070000ffff2222, 11]

function %f2() -> i64, i8 uext, i8 uext winch {
block0:
v0 = iconst.i64 0x00000000ffff2222
v1 = iconst.i8 85
v2 = iconst.i8 11
return v0, v1, v2
}

; run: %f2() == [0x00000000ffff2222, 85, 11]

function %f3() -> f64, i8, i8 winch {
block0:
v0 = f64const 0x0.400070088f700p-1022
v1 = iconst.i8 85
v2 = iconst.i8 11
return v0, v1, v2
}

; run: %f3() == [0x0.400070088f700p-1022, 85, 11]
9 changes: 8 additions & 1 deletion cranelift/fuzzgen/src/cranelift_arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,19 @@ impl<'a> CraneliftArbitrary for &mut Unstructured<'a> {

fn signature(
&mut self,
simd_enabled: bool,
mut simd_enabled: bool,
architecture: Architecture,
max_params: usize,
max_rets: usize,
) -> Result<Signature> {
let callconv = self.callconv(architecture)?;

// Winch doesn't support SIMD yet
// https://github.com/bytecodealliance/wasmtime/issues/8093
if callconv == CallConv::Winch {
simd_enabled = false;
}

let mut sig = Signature::new(callconv);

for _ in 0..max_params {
Expand Down

0 comments on commit 8eb7914

Please sign in to comment.