2 use rustc_codegen_ssa
::mir
::operand
::OperandRef
;
3 use rustc_codegen_ssa
::traits
::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods}
;
4 use rustc
::ty
::layout
::{Align, HasDataLayout, HasTyCtxt, LayoutOf, Size}
;
7 use type_of
::LayoutLlvmExt
;
11 fn round_pointer_up_to_alignment(
12 bx
: &mut Builder
<'a
, 'll
, 'tcx
>,
17 let mut ptr_as_int
= bx
.ptrtoint(addr
, bx
.cx().type_isize());
18 ptr_as_int
= bx
.add(ptr_as_int
, bx
.cx().const_i32(align
.bytes() as i32 - 1));
19 ptr_as_int
= bx
.and(ptr_as_int
, bx
.cx().const_i32(-(align
.bytes() as i32)));
20 bx
.inttoptr(ptr_as_int
, ptr_ty
)
23 fn emit_direct_ptr_va_arg(
24 bx
: &mut Builder
<'a
, 'll
, 'tcx
>,
25 list
: OperandRef
<'tcx
, &'ll Value
>,
30 allow_higher_align
: bool
31 ) -> (&'ll Value
, Align
) {
32 let va_list_ptr_ty
= bx
.cx().type_ptr_to(bx
.cx
.type_i8p());
33 let va_list_addr
= if list
.layout
.llvm_type(bx
.cx
) != va_list_ptr_ty
{
34 bx
.bitcast(list
.immediate(), va_list_ptr_ty
)
39 let ptr
= bx
.load(va_list_addr
, bx
.tcx().data_layout
.pointer_align
.abi
);
41 let (addr
, addr_align
) = if allow_higher_align
&& align
> slot_size
{
42 (round_pointer_up_to_alignment(bx
, ptr
, align
, bx
.cx().type_i8p()), align
)
48 let aligned_size
= size
.align_to(slot_size
).bytes() as i32;
49 let full_direct_size
= bx
.cx().const_i32(aligned_size
);
50 let next
= bx
.inbounds_gep(addr
, &[full_direct_size
]);
51 bx
.store(next
, va_list_addr
, bx
.tcx().data_layout
.pointer_align
.abi
);
53 if size
.bytes() < slot_size
.bytes() &&
54 &*bx
.tcx().sess
.target
.target
.target_endian
== "big" {
55 let adjusted_size
= bx
.cx().const_i32((slot_size
.bytes() - size
.bytes()) as i32);
56 let adjusted
= bx
.inbounds_gep(addr
, &[adjusted_size
]);
57 (bx
.bitcast(adjusted
, bx
.cx().type_ptr_to(llty
)), addr_align
)
59 (bx
.bitcast(addr
, bx
.cx().type_ptr_to(llty
)), addr_align
)
64 bx
: &mut Builder
<'a
, 'll
, 'tcx
>,
65 list
: OperandRef
<'tcx
, &'ll Value
>,
69 allow_higher_align
: bool
71 let layout
= bx
.cx
.layout_of(target_ty
);
72 let (llty
, size
, align
) = if indirect
{
73 (bx
.cx
.layout_of(bx
.cx
.tcx
.mk_imm_ptr(target_ty
)).llvm_type(bx
.cx
),
74 bx
.cx
.data_layout().pointer_size
,
75 bx
.cx
.data_layout().pointer_align
)
77 (layout
.llvm_type(bx
.cx
),
81 let (addr
, addr_align
) = emit_direct_ptr_va_arg(bx
, list
, llty
, size
, align
.abi
,
82 slot_size
, allow_higher_align
);
84 let tmp_ret
= bx
.load(addr
, addr_align
);
85 bx
.load(tmp_ret
, align
.abi
)
87 bx
.load(addr
, addr_align
)
91 pub(super) fn emit_va_arg(
92 bx
: &mut Builder
<'a
, 'll
, 'tcx
>,
93 addr
: OperandRef
<'tcx
, &'ll Value
>,
96 // Determine the va_arg implementation to use. The LLVM va_arg instruction
97 // is lacking in some instances, so we should only use it as a fallback.
98 let target
= &bx
.cx
.tcx
.sess
.target
.target
;
99 let arch
= &bx
.cx
.tcx
.sess
.target
.target
.arch
;
100 match (&**arch
, target
.options
.is_like_windows
) {
103 emit_ptr_va_arg(bx
, addr
, target_ty
, false,
104 Align
::from_bytes(4).unwrap(), false)
108 emit_ptr_va_arg(bx
, addr
, target_ty
, false,
109 Align
::from_bytes(4).unwrap(), true)
112 ("aarch4", true) => {
113 emit_ptr_va_arg(bx
, addr
, target_ty
, false,
114 Align
::from_bytes(8).unwrap(), false)
117 ("aarch4", _
) if target
.target_os
== "ios" => {
118 emit_ptr_va_arg(bx
, addr
, target_ty
, false,
119 Align
::from_bytes(8).unwrap(), true)
122 ("x86_64", true) => {
123 let target_ty_size
= bx
.cx
.size_of(target_ty
).bytes();
124 let indirect
= if target_ty_size
> 8 || !target_ty_size
.is_power_of_two() {
129 emit_ptr_va_arg(bx
, addr
, target_ty
, indirect
,
130 Align
::from_bytes(8).unwrap(), false)
132 // For all other architecture/OS combinations fall back to using
133 // the LLVM va_arg instruction.
134 // https://llvm.org/docs/LangRef.html#va-arg-instruction
136 let va_list
= if (target
.arch
== "aarch64" ||
137 target
.arch
== "x86_64" ||
138 target
.arch
== "powerpc") &&
139 !target
.options
.is_like_windows
{
140 bx
.load(addr
.immediate(), bx
.tcx().data_layout
.pointer_align
.abi
)
144 bx
.va_arg(va_list
, bx
.cx
.layout_of(target_ty
).llvm_type(bx
.cx
))