c-variadic: fix i128 argument being misread on arm64ec
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 3ca920e..a64452d 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -1085,9 +1085,15 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( bx, addr, target_ty, - PassMode::Direct, + // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is + // not 1, 2, 4, or 8 bytes, must be passed by reference." + if target_ty_size > 8 || !target_ty_size.is_power_of_two() { + PassMode::Indirect + } else { + PassMode::Direct + }, SlotSize::Bytes8, - if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes }, + AllowHigherAlign::No, ForceRightAdjust::No, ), Arch::AArch64 if target.is_like_windows || target.is_like_darwin => emit_ptr_va_arg(
diff --git a/tests/assembly-llvm/c-variadic/aarch64.rs b/tests/assembly-llvm/c-variadic/aarch64.rs index a5dbc8a..fcb44d0 100644 --- a/tests/assembly-llvm/c-variadic/aarch64.rs +++ b/tests/assembly-llvm/c-variadic/aarch64.rs
@@ -287,11 +287,13 @@ pub struct VaList<'a> { // AARCH64_BE-NEXT: ldp x0, x1, [x8] // AARCH64_BE-NEXT: ret + // NOTE: matches x86_64 Windows: an `i128` is passed indirectly, the slot holds a pointer. + // // ARM64EC_MSVC-LABEL: read_i128 = "#read_i128" // ARM64EC_MSVC: ldr x9, [x0] - // ARM64EC_MSVC-NEXT: mov x8, x0 - // ARM64EC_MSVC-NEXT: ldp x0, x1, [x9], #16 - // ARM64EC_MSVC-NEXT: str x9, [x8] + // ARM64EC_MSVC-NEXT: ldr x10, [x9], #8 + // ARM64EC_MSVC-NEXT: str x9, [x0] + // ARM64EC_MSVC-NEXT: ldp x0, x1, [x10] // ARM64EC_MSVC-NEXT: ret // AARCH64_DARWIN-LABEL: _read_i128: