Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion compiler/rustc_codegen_llvm/src/va_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,28 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
// sparc64 is a big-endian target and stores variable arguments right-adjusted.
ForceRightAdjust::Yes,
),
Arch::Sparc => {
std::assert_matches!(stability, CVariadicStatus::Unstable { .. });

// f128 is passed indirectly.
let pass_mode = match layout.layout.backend_repr() {
BackendRepr::Scalar(scalar) => match scalar.primitive() {
Primitive::Float(Float::F128) => PassMode::Indirect,
_ => PassMode::Direct,
},
_ => PassMode::Direct,
};
Comment on lines +1239 to +1246

@folkertdev folkertdev Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f128 does not yet implement VaArgSafe, so this is unreachable in practice, but:

View changes since the review


emit_ptr_va_arg(
bx,
addr,
target_ty,
pass_mode,
SlotSize::Bytes4,
AllowHigherAlign::No,
ForceRightAdjust::Yes,
)
}
Comment on lines +1236 to +1257

@folkertdev folkertdev Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sparc is still gated by the c_variadic_experimental_arch feature.

The arguments to emit_ptr_va_arg here are based on the LLVM implementation. Many targets have an implementation of va_arg in Clang, but for sparc it is really LLVM that expands va_arg.

https://github.com/llvm/llvm-project/blob/5194e33faad9d84fd8d21c0305621a17e0d8a49f/llvm/lib/Target/Sparc/SparcISelLowering.cpp#L2768-L2790

  • it just loads from a pointer regardless of the size of the argument, hence unconditional PassMode::Direct
  • The pointer is increased by just the VT size in bytes. Due to argument promotion, the smallest type that can actually be read using va_arg is 4 bytes, and no attempt is made to align to something higher than that. So SlotSize::Bytes4.
  • AllowHigherAlign::Yes would align e.g. an i128 to a 16-byte boundary. This function does not take the alignment into account at all. So, AllowHigherAlign::No
  • This setting is true on BE targets with a slot size of 8, where a 4-byte value could be either in the low or high bytes. Despite being a BE target, the setting is not relevant for sparc because all values that could be passed divide cleanly into 4-byte slots.

View changes since the review

Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => emit_ptr_va_arg(
bx,
addr,
Expand All @@ -1256,7 +1278,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
Arch::Bpf => bug!("bpf does not support c-variadic functions"),
Arch::SpirV => bug!("spirv does not support c-variadic functions"),

Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => {
Arch::Avr | Arch::M68k | Arch::Msp430 => {
std::assert_matches!(stability, CVariadicStatus::Unstable { .. });

// Clang uses the LLVM implementation for these architectures.
Expand Down
15 changes: 9 additions & 6 deletions tests/assembly-llvm/c-variadic/sparc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,17 @@ unsafe extern "C" fn read_i64(ap: &mut VaList<'_>) -> i64 {
// CHECK-LABEL: read_i64
//
// SPARC: ld [%o0], %o1
// SPARC-NEXT: add %o1, 4, %o2
// SPARC-NEXT: add %o1, 8, %o2
// SPARC-NEXT: st %o2, [%o0]
// SPARC-NEXT: ld [%o1], %o2
// SPARC-NEXT: add %o1, 8, %o3
// SPARC-NEXT: st %o3, [%o0]
// SPARC-NEXT: ld [%o1+4], %o1
// SPARC-NEXT: ld [%o1+4], %o0
// SPARC-NEXT: add %sp, 96, %o2
// SPARC-NEXT: or %o2, 4, %o2
// SPARC-NEXT: st %o0, [%o2]
// SPARC-NEXT: ld [%o1], %o0
// SPARC-NEXT: st %o0, [%sp+96]
// SPARC-NEXT: ldd [%sp+96], %o0
// SPARC-NEXT: retl
// SPARC-NEXT: mov %o2, %o0
// SPARC-NEXT: add %sp, 104, %sp
//
// SPARC64: ldx [%o0], %o1
// SPARC64-NEXT: add %o1, 8, %o2
Expand Down
2 changes: 1 addition & 1 deletion tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![crate_type = "staticlib"]
#![feature(c_variadic_int128)]
#![feature(c_variadic_int128, c_variadic_experimental_arch)]

use core::ffi::{CStr, VaList, c_char, c_double, c_int, c_long, c_longlong};

Expand Down
Loading