-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
c_variadic: provide our own va_arg implementation for more targets
#150094
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,12 @@ | ||
| use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size, TyAndLayout}; | ||
| use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size}; | ||
| use rustc_codegen_ssa::MemFlags; | ||
| use rustc_codegen_ssa::common::IntPredicate; | ||
| use rustc_codegen_ssa::mir::operand::OperandRef; | ||
| use rustc_codegen_ssa::traits::{ | ||
| BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods, | ||
| }; | ||
| use rustc_middle::ty::Ty; | ||
| use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; | ||
| use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; | ||
| use rustc_target::spec::{Abi, Arch, Env}; | ||
|
|
||
| use crate::builder::Builder; | ||
|
|
@@ -82,6 +82,7 @@ enum PassMode { | |
| enum SlotSize { | ||
| Bytes8 = 8, | ||
| Bytes4 = 4, | ||
| Bytes1 = 1, | ||
| } | ||
|
|
||
| enum AllowHigherAlign { | ||
|
|
@@ -728,7 +729,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( | |
| fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( | ||
| bx: &mut Builder<'_, 'll, 'tcx>, | ||
| reg_addr: &'ll Value, | ||
| layout: TyAndLayout<'tcx, Ty<'tcx>>, | ||
| layout: TyAndLayout<'tcx>, | ||
| src_align: Align, | ||
| ) -> &'ll Value { | ||
| if layout.layout.align.abi > src_align { | ||
|
|
@@ -751,7 +752,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( | |
| fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( | ||
| bx: &mut Builder<'_, 'll, 'tcx>, | ||
| va_list_addr: &'ll Value, | ||
| layout: TyAndLayout<'tcx, Ty<'tcx>>, | ||
| layout: TyAndLayout<'tcx>, | ||
| ) -> &'ll Value { | ||
| let dl = bx.cx.data_layout(); | ||
| let ptr_align_abi = dl.data_layout().pointer_align().abi; | ||
|
|
@@ -1003,15 +1004,17 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( | |
| return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi); | ||
| } | ||
|
|
||
| /// Determine the va_arg implementation to use. The LLVM va_arg instruction | ||
| /// is lacking in some instances, so we should only use it as a fallback. | ||
| pub(super) fn emit_va_arg<'ll, 'tcx>( | ||
| bx: &mut Builder<'_, 'll, 'tcx>, | ||
| addr: OperandRef<'tcx, &'ll Value>, | ||
| target_ty: Ty<'tcx>, | ||
| ) -> &'ll Value { | ||
| // Determine the va_arg implementation to use. The LLVM va_arg instruction | ||
| // is lacking in some instances, so we should only use it as a fallback. | ||
| let target = &bx.cx.tcx.sess.target; | ||
| let layout = bx.cx.layout_of(target_ty); | ||
| let target_ty_size = layout.layout.size().bytes(); | ||
|
|
||
| let target = &bx.cx.tcx.sess.target; | ||
| match target.arch { | ||
| Arch::X86 => emit_ptr_va_arg( | ||
| bx, | ||
|
|
@@ -1069,23 +1072,78 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( | |
| AllowHigherAlign::Yes, | ||
| ForceRightAdjust::No, | ||
| ), | ||
| Arch::LoongArch32 => emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| if target_ty_size > 2 * 4 { PassMode::Indirect } else { PassMode::Direct }, | ||
| SlotSize::Bytes4, | ||
| AllowHigherAlign::Yes, | ||
| ForceRightAdjust::No, | ||
| ), | ||
| Arch::LoongArch64 => emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct }, | ||
| SlotSize::Bytes8, | ||
| AllowHigherAlign::Yes, | ||
| ForceRightAdjust::No, | ||
| ), | ||
| Arch::AmdGpu => emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| PassMode::Direct, | ||
| SlotSize::Bytes4, | ||
| AllowHigherAlign::No, | ||
| ForceRightAdjust::No, | ||
| ), | ||
|
Comment on lines
+1093
to
+1101
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Arch::Nvptx64 => emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| PassMode::Direct, | ||
| SlotSize::Bytes1, | ||
| AllowHigherAlign::Yes, | ||
| ForceRightAdjust::No, | ||
| ), | ||
|
Comment on lines
+1102
to
+1110
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Arch::Wasm32 | Arch::Wasm64 => emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| if layout.is_aggregate() || layout.is_zst() || layout.is_1zst() { | ||
| PassMode::Indirect | ||
| } else { | ||
| PassMode::Direct | ||
| }, | ||
| SlotSize::Bytes4, | ||
| AllowHigherAlign::Yes, | ||
| ForceRightAdjust::No, | ||
| ), | ||
|
Comment on lines
+1111
to
+1123
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. curiously the slot size is always 4, independent of whether wasm32 or wasm64 is used. I suppose that may change in the future if/when wasm64 gets more attention. |
||
| Arch::CSky => emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| PassMode::Direct, | ||
| SlotSize::Bytes4, | ||
| AllowHigherAlign::Yes, | ||
| ForceRightAdjust::No, | ||
| ), | ||
|
Comment on lines
+1124
to
+1132
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| // Windows x86_64 | ||
| Arch::X86_64 if target.is_like_windows => { | ||
| let target_ty_size = bx.cx.size_of(target_ty).bytes(); | ||
| emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| if target_ty_size > 8 || !target_ty_size.is_power_of_two() { | ||
| PassMode::Indirect | ||
| } else { | ||
| PassMode::Direct | ||
| }, | ||
| SlotSize::Bytes8, | ||
| AllowHigherAlign::No, | ||
| ForceRightAdjust::No, | ||
| ) | ||
| } | ||
| Arch::X86_64 if target.is_like_windows => emit_ptr_va_arg( | ||
| bx, | ||
| addr, | ||
| target_ty, | ||
| if target_ty_size > 8 || !target_ty_size.is_power_of_two() { | ||
| PassMode::Indirect | ||
| } else { | ||
| PassMode::Direct | ||
| }, | ||
| SlotSize::Bytes8, | ||
| AllowHigherAlign::No, | ||
| ForceRightAdjust::No, | ||
| ), | ||
| // This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64. | ||
| Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty), | ||
| Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/llvm/llvm-project/blob/c386d6d3bfa400e94ac9cadb85a0b1a72ed54b2b/clang/lib/CodeGen/Targets/LoongArch.cpp#L434
zero-sized types can't reach this logic currently, but we could handle them. This logic is very similar for riscv, but it has an annoying exception for the 32-bit embedded ABI which lowers alignment for
f64andi64/u64from 8 to 4. Apparently that may change as things are ratified.