Stream: git-wasmtime

Topic: wasmtime / issue #14945 aarch64: argument after a stack-p...


view this post on Zulip Wasmtime GitHub notifications bot (Oct 22 2026 at 17:55):

alexcrichton opened issue #14945:

This test:

target aarch64

function %f(i64, i64, i64, i64, i64, i64, i64, i128, i64) -> i64 system_v {
block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64, v6: i64, v7: i128, v8: i64):
    return v8
}

function %f_apple(i64, i64, i64, i64, i64, i64, i64, i128, i64) -> i64 apple_aarch64 {
block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64, v6: i64, v7: i128, v8: i64):
    return v8
}

reads the last argument from x7:

$ cargo run -p cranelift-tools -- compile --target aarch64 -D i128-ngrn.clif
Disassembly of 20 bytes <%f>:
   0:   fd 7b bf a9             stp x29, x30, [sp, #-0x10]!
   4:   fd 03 00 91             mov x29, sp
   8:   e0 03 07 aa             mov x0, x7
   c:   fd 7b c1 a8             ldp x29, x30, [sp], #0x10
  10:   c0 03 5f d6             ret

Disassembly of 20 bytes <%f_apple>:
   0:   fd 7b bf a9             stp x29, x30, [sp, #-0x10]!
   4:   fd 03 00 91             mov x29, sp
   8:   e0 03 07 aa             mov x0, x7
   c:   fd 7b c1 a8             ldp x29, x30, [sp], #0x10
  10:   c0 03 5f d6             ret

but the equivalent C:

long f(long a0, long a1, long a2, long a3, long a4, long a5, long a6, __int128 b, long c) {
    return c;
}

reads it from the stack with both GCC and clang:

$ aarch64-linux-gnu-gcc -O2 -S -o - i128-ngrn.c
f:
    ldr x0, [sp, 16]

$ clang --target=arm64-apple-darwin -O2 -S -o - i128-ngrn.c
_f:
    ldr x0, [sp, #16]

<details>
<summary>Details</summary>

AAPCS64 stage C: an i128 that doesn't fit in the remaining integer
registers goes on the stack, and C.13 then sets NGRN = 8, so every later
integer argument goes on the stack too. Clang does the same for Darwin. In
compute_arg_locs (cranelift/codegen/src/isa/aarch64/abi.rs), when the
register pair doesn't fit, the i128 goes on the stack but next_xreg is
left at 7, so the following i64 gets x7. Setting next_xreg = max_per_class_reg_vals in that case should fix both calling conventions.

Cranelift-to-Cranelift calls agree with each other, so this only shows up
when such a signature is shared with C/Rust code (e.g. cranelift-jit,
cg_clif). Wasmtime never passes i128 across a call boundary.

</details>

view this post on Zulip Wasmtime GitHub notifications bot (Oct 22 2026 at 17:55):

alexcrichton added the bug label to Issue #14945.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 22 2026 at 17:55):

alexcrichton added the cranelift label to Issue #14945.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 22 2026 at 17:55):

alexcrichton added the cranelift:area:aarch64 label to Issue #14945.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 24 2026 at 02:52):

cfallin closed issue #14945:

This test:

target aarch64

function %f(i64, i64, i64, i64, i64, i64, i64, i128, i64) -> i64 system_v {
block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64, v6: i64, v7: i128, v8: i64):
    return v8
}

function %f_apple(i64, i64, i64, i64, i64, i64, i64, i128, i64) -> i64 apple_aarch64 {
block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64, v6: i64, v7: i128, v8: i64):
    return v8
}

reads the last argument from x7:

$ cargo run -p cranelift-tools -- compile --target aarch64 -D i128-ngrn.clif
Disassembly of 20 bytes <%f>:
   0:   fd 7b bf a9             stp x29, x30, [sp, #-0x10]!
   4:   fd 03 00 91             mov x29, sp
   8:   e0 03 07 aa             mov x0, x7
   c:   fd 7b c1 a8             ldp x29, x30, [sp], #0x10
  10:   c0 03 5f d6             ret

Disassembly of 20 bytes <%f_apple>:
   0:   fd 7b bf a9             stp x29, x30, [sp, #-0x10]!
   4:   fd 03 00 91             mov x29, sp
   8:   e0 03 07 aa             mov x0, x7
   c:   fd 7b c1 a8             ldp x29, x30, [sp], #0x10
  10:   c0 03 5f d6             ret

but the equivalent C:

long f(long a0, long a1, long a2, long a3, long a4, long a5, long a6, __int128 b, long c) {
    return c;
}

reads it from the stack with both GCC and clang:

$ aarch64-linux-gnu-gcc -O2 -S -o - i128-ngrn.c
f:
    ldr x0, [sp, 16]

$ clang --target=arm64-apple-darwin -O2 -S -o - i128-ngrn.c
_f:
    ldr x0, [sp, #16]

<details>
<summary>Details</summary>

AAPCS64 stage C: an i128 that doesn't fit in the remaining integer
registers goes on the stack, and C.13 then sets NGRN = 8, so every later
integer argument goes on the stack too. Clang does the same for Darwin. In
compute_arg_locs (cranelift/codegen/src/isa/aarch64/abi.rs), when the
register pair doesn't fit, the i128 goes on the stack but next_xreg is
left at 7, so the following i64 gets x7. Setting next_xreg = max_per_class_reg_vals in that case should fix both calling conventions.

Cranelift-to-Cranelift calls agree with each other, so this only shows up
when such a signature is shared with C/Rust code (e.g. cranelift-jit,
cg_clif). Wasmtime never passes i128 across a call boundary.

</details>


Last updated: Oct 31 2026 at 23:03 UTC