Skip to content

Commit d8a0f80

Browse files
committed
fixup! Implement va_arg for Hexagon Linux musl targets
1 parent 0c1612e commit d8a0f80

File tree

1 file changed

+53
-2
lines changed

1 file changed

+53
-2
lines changed

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
780780
mem_addr
781781
}
782782

783-
fn emit_hexagon_va_arg<'ll, 'tcx>(
783+
fn emit_hexagon_va_arg_musl<'ll, 'tcx>(
784784
bx: &mut Builder<'_, 'll, 'tcx>,
785785
list: OperandRef<'tcx, &'ll Value>,
786786
target_ty: Ty<'tcx>,
@@ -865,6 +865,57 @@ fn emit_hexagon_va_arg<'ll, 'tcx>(
865865
bx.load(layout.llvm_type(bx), value_addr, layout.align.abi)
866866
}
867867

868+
fn emit_hexagon_va_arg_bare_metal<'ll, 'tcx>(
869+
bx: &mut Builder<'_, 'll, 'tcx>,
870+
list: OperandRef<'tcx, &'ll Value>,
871+
target_ty: Ty<'tcx>,
872+
) -> &'ll Value {
873+
// Implementation of va_arg for Hexagon bare-metal (non-musl) targets.
874+
// Based on LLVM's EmitVAArgForHexagon implementation.
875+
//
876+
// va_list is a simple pointer (char *)
877+
let va_list_addr = list.immediate();
878+
let layout = bx.cx.layout_of(target_ty);
879+
let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi;
880+
881+
// Load current pointer from va_list
882+
let current_ptr = bx.load(bx.type_ptr(), va_list_addr, ptr_align_abi);
883+
884+
// Handle address alignment for types with alignment > 4 bytes
885+
let ty_align = layout.align.abi;
886+
let aligned_ptr = if ty_align.bytes() > 4 {
887+
// Ensure alignment is a power of 2
888+
debug_assert!(ty_align.bytes().is_power_of_two(), "Alignment is not power of 2!");
889+
round_pointer_up_to_alignment(bx, current_ptr, ty_align, bx.type_ptr())
890+
} else {
891+
current_ptr
892+
};
893+
894+
// Calculate offset: round up type size to 4-byte boundary (minimum stack slot size)
895+
let type_size = layout.size.bytes();
896+
let offset = ((type_size + 3) / 4) * 4; // align to 4 bytes
897+
898+
// Update va_list to point to next argument
899+
let next_ptr = bx.inbounds_ptradd(aligned_ptr, bx.const_usize(offset));
900+
bx.store(next_ptr, va_list_addr, ptr_align_abi);
901+
902+
// Load and return the argument value
903+
bx.load(layout.llvm_type(bx), aligned_ptr, layout.align.abi)
904+
}
905+
906+
fn emit_hexagon_va_arg<'ll, 'tcx>(
907+
bx: &mut Builder<'_, 'll, 'tcx>,
908+
list: OperandRef<'tcx, &'ll Value>,
909+
target_ty: Ty<'tcx>,
910+
is_musl: bool,
911+
) -> &'ll Value {
912+
if is_musl {
913+
emit_hexagon_va_arg_musl(bx, list, target_ty)
914+
} else {
915+
emit_hexagon_va_arg_bare_metal(bx, list, target_ty)
916+
}
917+
}
918+
868919
fn emit_xtensa_va_arg<'ll, 'tcx>(
869920
bx: &mut Builder<'_, 'll, 'tcx>,
870921
list: OperandRef<'tcx, &'ll Value>,
@@ -1049,7 +1100,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10491100
// This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.
10501101
Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty),
10511102
Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty),
1052-
Arch::Hexagon if target.env == Env::Musl => emit_hexagon_va_arg(bx, addr, target_ty),
1103+
Arch::Hexagon => emit_hexagon_va_arg(bx, addr, target_ty, target.env == Env::Musl),
10531104
// For all other architecture/OS combinations fall back to using
10541105
// the LLVM va_arg instruction.
10551106
// https://llvm.org/docs/LangRef.html#va-arg-instruction

0 commit comments

Comments
 (0)