1- use rustc_abi:: { Align , BackendRepr , CVariadicStatus , Endian , HasDataLayout , Primitive , Size } ;
2- use rustc_codegen_ssa:: MemFlags ;
1+ use rustc_abi:: {
2+ Align , BackendRepr , CVariadicStatus , Endian , Float , HasDataLayout , Integer , Primitive , Size ,
3+ } ;
34use rustc_codegen_ssa:: common:: IntPredicate ;
45use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
56use rustc_codegen_ssa:: traits:: {
@@ -77,6 +78,35 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
7778 }
7879}
7980
81+ /// Some backends apply special alignment rules to c-variadic arguments.
82+ fn get_param_type_alignment < ' ll , ' tcx > (
83+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
84+ layout : TyAndLayout < ' tcx > ,
85+ ) -> Align {
86+ let BackendRepr :: Scalar ( scalar) = layout. backend_repr else {
87+ bug ! ( "unexpected backend repr {:?}" , layout. backend_repr) ;
88+ } ;
89+
90+ match bx. cx . tcx . sess . target . arch {
91+ Arch :: PowerPC64 => match scalar. primitive ( ) {
92+ Primitive :: Int ( integer, _) => match integer {
93+ Integer :: I8 | Integer :: I16 => unreachable ! ( ) ,
94+ Integer :: I32 | Integer :: I64 => { /* fall through */ }
95+ Integer :: I128 => return Align :: EIGHT ,
96+ } ,
97+ Primitive :: Float ( float) => match float {
98+ Float :: F16 | Float :: F32 => unreachable ! ( ) ,
99+ Float :: F64 => { /* fall through */ }
100+ Float :: F128 => return Align :: from_bytes ( 16 ) . unwrap ( ) ,
101+ } ,
102+ Primitive :: Pointer ( _) => { /* fall through */ }
103+ } ,
104+ _ => { /* fall through */ }
105+ }
106+
107+ layout. align . abi
108+ }
109+
80110enum PassMode {
81111 Direct ,
82112 Indirect ,
@@ -136,23 +166,23 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
136166 (
137167 bx. cx . layout_of ( Ty :: new_imm_ptr ( bx. cx . tcx , target_ty) ) . llvm_type ( bx. cx ) ,
138168 bx. cx . data_layout ( ) . pointer_size ( ) ,
139- bx. cx . data_layout ( ) . pointer_align ( ) ,
169+ bx. cx . data_layout ( ) . pointer_align ( ) . abi ,
140170 )
141171 } else {
142- ( layout. llvm_type ( bx. cx ) , layout. size , layout. align )
172+ ( layout. llvm_type ( bx. cx ) , layout. size , get_param_type_alignment ( bx , layout) )
143173 } ;
144174 let ( addr, addr_align) = emit_direct_ptr_va_arg (
145175 bx,
146176 list,
147177 size,
148- align. abi ,
178+ align,
149179 slot_size,
150180 allow_higher_align,
151181 force_right_adjust,
152182 ) ;
153183 if indirect {
154184 let tmp_ret = bx. load ( llty, addr, addr_align) ;
155- bx. load ( layout. llvm_type ( bx. cx ) , tmp_ret, align. abi )
185+ bx. load ( layout. llvm_type ( bx. cx ) , tmp_ret, align)
156186 } else {
157187 bx. load ( llty, addr, addr_align)
158188 }
@@ -585,8 +615,10 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
585615 // registers. In the case: l->gp_offset > 48 - num_gp * 8 or
586616 // l->fp_offset > 176 - num_fp * 16 go to step 7.
587617
618+ // We support x86_64-unknown-linux-gnux32 which uses 4-byte pointers.
588619 let unsigned_int_offset = 4 ;
589- let ptr_offset = 8 ;
620+ let ptr_offset = bx. tcx ( ) . data_layout . pointer_size ( ) . bytes ( ) ;
621+
590622 let gp_offset_ptr = va_list_addr;
591623 let fp_offset_ptr = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( unsigned_int_offset) ) ;
592624
@@ -660,7 +692,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
660692 let reg_hi_addr = bx. inbounds_ptradd ( reg_lo_addr, bx. const_i32 ( 16 ) ) ;
661693
662694 let align = layout. layout . align ( ) . abi ;
663- let tmp = bx. alloca ( layout. layout . size ( ) , align) ;
695+ let tmp = bx. alloca ( layout. size , layout . align . abi ) ;
664696
665697 let reg_lo = bx. load ( ty_lo, reg_lo_addr, align_lo) ;
666698 let reg_hi = bx. load ( ty_hi, reg_hi_addr, align_hi) ;
@@ -683,7 +715,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
683715 Primitive :: Int ( _, _) | Primitive :: Pointer ( _) => ( gp_addr, fp_addr) ,
684716 } ;
685717
686- let tmp = bx. alloca ( layout. layout . size ( ) , layout. layout . align ( ) . abi ) ;
718+ let tmp = bx. alloca ( layout. size , layout. align . abi ) ;
687719
688720 let reg_lo = bx. load ( ty_lo, reg_lo_addr, align_lo) ;
689721 let reg_hi = bx. load ( ty_hi, reg_hi_addr, align_hi) ;
@@ -751,16 +783,12 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
751783 src_align : Align ,
752784) -> & ' ll Value {
753785 if layout. layout . align . abi > src_align {
754- let tmp = bx. alloca ( layout. layout . size ( ) , layout. layout . align ( ) . abi ) ;
755- bx. memcpy (
756- tmp,
757- layout. layout . align . abi ,
758- reg_addr,
759- src_align,
760- bx. const_u32 ( layout. layout . size ( ) . bytes ( ) as u32 ) ,
761- MemFlags :: empty ( ) ,
762- None ,
763- ) ;
786+ assert ! ( layout. ty. is_integral( ) ) ;
787+
788+ // A memcpy below optimizes poorly for 128-bit integers.
789+ let tmp = bx. alloca ( layout. size , layout. align . abi ) ;
790+ let val = bx. load ( layout. llvm_type ( bx) , reg_addr, src_align) ;
791+ bx. store ( val, tmp, layout. align . abi ) ;
764792 tmp
765793 } else {
766794 reg_addr
@@ -782,9 +810,11 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
782810 // byte boundary if alignment needed by type exceeds 8 byte boundary.
783811 // It isn't stated explicitly in the standard, but in practice we use
784812 // alignment greater than 16 where necessary.
785- if layout. layout . align . bytes ( ) > 8 {
786- unreachable ! ( "all instances of VaArgSafe have an alignment <= 8" ) ;
787- }
813+ let overflow_arg_area_v = if layout. layout . align . bytes ( ) > 8 {
814+ round_pointer_up_to_alignment ( bx, overflow_arg_area_v, layout. layout . align . abi )
815+ } else {
816+ overflow_arg_area_v
817+ } ;
788818
789819 // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
790820 let mem_addr = overflow_arg_area_v;
@@ -1071,7 +1101,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10711101 Arch :: AArch64 => emit_aapcs_va_arg ( bx, addr, target_ty) ,
10721102 Arch :: Arm => {
10731103 // Types wider than 16 bytes are not currently supported. Clang has special logic for
1074- // such types, but `VaArgSafe` is not implemented for any type that is this large.
1104+ // such types, but `VaArgSafe` is not implemented for any type that is this large on
1105+ // arm (i.e. 32-bit) targets.
10751106 assert ! ( bx. cx. size_of( target_ty) . bytes( ) <= 16 ) ;
10761107
10771108 emit_ptr_va_arg (
@@ -1093,6 +1124,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10931124 PassMode :: Direct ,
10941125 SlotSize :: Bytes8 ,
10951126 AllowHigherAlign :: Yes ,
1127+ // ForceRightAdjust only takes effect on big-endian architectures.
10961128 ForceRightAdjust :: Yes ,
10971129 ) ,
10981130 Arch :: RiscV32 if target. llvm_abiname == LlvmAbi :: Ilp32e => {
0 commit comments