1- use rustc_abi:: { Align , BackendRepr , Endian , HasDataLayout , Primitive , Size } ;
1+ use rustc_abi:: { Align , BackendRepr , Endian , Float , HasDataLayout , Integer , Primitive , Size } ;
22use rustc_codegen_ssa:: MemFlags ;
33use rustc_codegen_ssa:: common:: IntPredicate ;
44use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
@@ -8,7 +8,7 @@ use rustc_codegen_ssa::traits::{
88use rustc_middle:: bug;
99use rustc_middle:: ty:: Ty ;
1010use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , TyAndLayout } ;
11- use rustc_target:: spec:: { Arch , Env , LlvmAbi , RustcAbi } ;
11+ use rustc_target:: spec:: { Arch , Env , HasTargetSpec , LlvmAbi , RustcAbi } ;
1212
1313use crate :: builder:: Builder ;
1414use crate :: llvm:: { Type , Value } ;
@@ -30,11 +30,9 @@ fn round_pointer_up_to_alignment<'ll>(
3030 ptr_ty : & ' ll Type ,
3131) -> & ' ll Value {
3232 let ptr = bx. inbounds_ptradd ( addr, bx. const_i32 ( align. bytes ( ) as i32 - 1 ) ) ;
33- bx. call_intrinsic (
34- "llvm.ptrmask" ,
35- & [ ptr_ty, bx. type_i32 ( ) ] ,
36- & [ ptr, bx. const_int ( bx. isize_ty , -( align. bytes ( ) as isize ) as i64 ) ] ,
37- )
33+ let pointer_width = bx. target_spec ( ) . pointer_width ;
34+ let mask = align. bytes ( ) . wrapping_neg ( ) & ( u64:: MAX >> ( 64 - pointer_width) ) ;
35+ bx. call_intrinsic ( "llvm.ptrmask" , & [ ptr_ty, bx. type_isize ( ) ] , & [ ptr, bx. const_usize ( mask) ] )
3836}
3937
4038fn emit_direct_ptr_va_arg < ' ll , ' tcx > (
@@ -75,6 +73,35 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
7573 }
7674}
7775
76+ /// Some backends apply special alignment rules to c-variadic arguments.
77+ fn get_param_type_alignment < ' ll , ' tcx > (
78+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
79+ layout : TyAndLayout < ' tcx > ,
80+ ) -> Align {
81+ let BackendRepr :: Scalar ( scalar) = layout. backend_repr else {
82+ bug ! ( "unexpected backend repr {:?}" , layout. backend_repr) ;
83+ } ;
84+
85+ match bx. cx . tcx . sess . target . arch {
86+ Arch :: PowerPC64 => match scalar. primitive ( ) {
87+ Primitive :: Int ( integer, _) => match integer {
88+ Integer :: I8 | Integer :: I16 => unreachable ! ( ) ,
89+ Integer :: I32 | Integer :: I64 => { /* fall through */ }
90+ Integer :: I128 => return Align :: EIGHT ,
91+ } ,
92+ Primitive :: Float ( float) => match float {
93+ Float :: F16 | Float :: F32 => unreachable ! ( ) ,
94+ Float :: F64 => { /* fall through */ }
95+ Float :: F128 => return Align :: from_bytes ( 16 ) . unwrap ( ) ,
96+ } ,
97+ Primitive :: Pointer ( _) => { /* fall through */ }
98+ } ,
99+ _ => { /* fall through */ }
100+ }
101+
102+ layout. align . abi
103+ }
104+
78105enum PassMode {
79106 Direct ,
80107 Indirect ,
@@ -115,23 +142,23 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
115142 (
116143 bx. cx . layout_of ( Ty :: new_imm_ptr ( bx. cx . tcx , target_ty) ) . llvm_type ( bx. cx ) ,
117144 bx. cx . data_layout ( ) . pointer_size ( ) ,
118- bx. cx . data_layout ( ) . pointer_align ( ) ,
145+ bx. cx . data_layout ( ) . pointer_align ( ) . abi ,
119146 )
120147 } else {
121- ( layout. llvm_type ( bx. cx ) , layout. size , layout. align )
148+ ( layout. llvm_type ( bx. cx ) , layout. size , get_param_type_alignment ( bx , layout) )
122149 } ;
123150 let ( addr, addr_align) = emit_direct_ptr_va_arg (
124151 bx,
125152 list,
126153 size,
127- align. abi ,
154+ align,
128155 slot_size,
129156 allow_higher_align,
130157 force_right_adjust,
131158 ) ;
132159 if indirect {
133160 let tmp_ret = bx. load ( llty, addr, addr_align) ;
134- bx. load ( layout. llvm_type ( bx. cx ) , tmp_ret, align. abi )
161+ bx. load ( layout. llvm_type ( bx. cx ) , tmp_ret, align)
135162 } else {
136163 bx. load ( llty, addr, addr_align)
137164 }
@@ -765,9 +792,16 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
765792 // byte boundary if alignment needed by type exceeds 8 byte boundary.
766793 // It isn't stated explicitly in the standard, but in practice we use
767794 // alignment greater than 16 where necessary.
768- if layout. layout . align . bytes ( ) > 8 {
769- unreachable ! ( "all instances of VaArgSafe have an alignment <= 8" ) ;
770- }
795+ let overflow_arg_area_v = if layout. layout . align . bytes ( ) > 8 {
796+ round_pointer_up_to_alignment (
797+ bx,
798+ overflow_arg_area_v,
799+ layout. layout . align . abi ,
800+ bx. type_ptr ( ) ,
801+ )
802+ } else {
803+ overflow_arg_area_v
804+ } ;
771805
772806 // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
773807 let mem_addr = overflow_arg_area_v;
@@ -1075,6 +1109,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10751109 PassMode :: Direct ,
10761110 SlotSize :: Bytes8 ,
10771111 AllowHigherAlign :: Yes ,
1112+ // ForceRightAdjust only takes effect on big-endian architectures.
10781113 ForceRightAdjust :: Yes ,
10791114 ) ,
10801115 Arch :: RiscV32 if target. llvm_abiname == LlvmAbi :: Ilp32e => {
0 commit comments