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 ;
@@ -77,6 +77,35 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
7777 }
7878}
7979
80+ /// Some backends apply special alignment rules to c-variadic arguments.
81+ fn get_param_type_alignment < ' ll , ' tcx > (
82+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
83+ layout : TyAndLayout < ' tcx > ,
84+ ) -> Align {
85+ let BackendRepr :: Scalar ( scalar) = layout. backend_repr else {
86+ bug ! ( "unexpected backend repr {:?}" , layout. backend_repr) ;
87+ } ;
88+
89+ match bx. cx . tcx . sess . target . arch {
90+ Arch :: PowerPC64 => match scalar. primitive ( ) {
91+ Primitive :: Int ( integer, _) => match integer {
92+ Integer :: I8 | Integer :: I16 => unreachable ! ( ) ,
93+ Integer :: I32 | Integer :: I64 => { /* fall through */ }
94+ Integer :: I128 => return Align :: EIGHT ,
95+ } ,
96+ Primitive :: Float ( float) => match float {
97+ Float :: F16 | Float :: F32 => unreachable ! ( ) ,
98+ Float :: F64 => { /* fall through */ }
99+ Float :: F128 => return Align :: from_bytes ( 16 ) . unwrap ( ) ,
100+ } ,
101+ Primitive :: Pointer ( _) => { /* fall through */ }
102+ } ,
103+ _ => { /* fall through */ }
104+ }
105+
106+ layout. align . abi
107+ }
108+
80109enum PassMode {
81110 Direct ,
82111 Indirect ,
@@ -136,23 +165,23 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
136165 (
137166 bx. cx . layout_of ( Ty :: new_imm_ptr ( bx. cx . tcx , target_ty) ) . llvm_type ( bx. cx ) ,
138167 bx. cx . data_layout ( ) . pointer_size ( ) ,
139- bx. cx . data_layout ( ) . pointer_align ( ) ,
168+ bx. cx . data_layout ( ) . pointer_align ( ) . abi ,
140169 )
141170 } else {
142- ( layout. llvm_type ( bx. cx ) , layout. size , layout. align )
171+ ( layout. llvm_type ( bx. cx ) , layout. size , get_param_type_alignment ( bx , layout) )
143172 } ;
144173 let ( addr, addr_align) = emit_direct_ptr_va_arg (
145174 bx,
146175 list,
147176 size,
148- align. abi ,
177+ align,
149178 slot_size,
150179 allow_higher_align,
151180 force_right_adjust,
152181 ) ;
153182 if indirect {
154183 let tmp_ret = bx. load ( llty, addr, addr_align) ;
155- bx. load ( layout. llvm_type ( bx. cx ) , tmp_ret, align. abi )
184+ bx. load ( layout. llvm_type ( bx. cx ) , tmp_ret, align)
156185 } else {
157186 bx. load ( llty, addr, addr_align)
158187 }
@@ -585,8 +614,10 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
585614 // registers. In the case: l->gp_offset > 48 - num_gp * 8 or
586615 // l->fp_offset > 176 - num_fp * 16 go to step 7.
587616
617+ // We support x86_64-unknown-linux-gnux32 which uses 4-byte pointers.
588618 let unsigned_int_offset = 4 ;
589- let ptr_offset = 8 ;
619+ let ptr_offset = bx. tcx ( ) . data_layout . pointer_size ( ) . bytes ( ) ;
620+
590621 let gp_offset_ptr = va_list_addr;
591622 let fp_offset_ptr = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( unsigned_int_offset) ) ;
592623
@@ -660,7 +691,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
660691 let reg_hi_addr = bx. inbounds_ptradd ( reg_lo_addr, bx. const_i32 ( 16 ) ) ;
661692
662693 let align = layout. layout . align ( ) . abi ;
663- let tmp = bx. alloca ( layout. layout . size ( ) , align ) ;
694+ let tmp = bx. alloca_with_ty ( layout) ;
664695
665696 let reg_lo = bx. load ( ty_lo, reg_lo_addr, align_lo) ;
666697 let reg_hi = bx. load ( ty_hi, reg_hi_addr, align_hi) ;
@@ -683,7 +714,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
683714 Primitive :: Int ( _, _) | Primitive :: Pointer ( _) => ( gp_addr, fp_addr) ,
684715 } ;
685716
686- let tmp = bx. alloca ( layout. layout . size ( ) , layout . layout . align ( ) . abi ) ;
717+ let tmp = bx. alloca_with_ty ( layout) ;
687718
688719 let reg_lo = bx. load ( ty_lo, reg_lo_addr, align_lo) ;
689720 let reg_hi = bx. load ( ty_hi, reg_hi_addr, align_hi) ;
@@ -751,7 +782,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
751782 src_align : Align ,
752783) -> & ' ll Value {
753784 if layout. layout . align . abi > src_align {
754- let tmp = bx. alloca ( layout. layout . size ( ) , layout . layout . align ( ) . abi ) ;
785+ let tmp = bx. alloca_with_ty ( layout) ;
755786 bx. memcpy (
756787 tmp,
757788 layout. layout . align . abi ,
@@ -782,9 +813,11 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
782813 // byte boundary if alignment needed by type exceeds 8 byte boundary.
783814 // It isn't stated explicitly in the standard, but in practice we use
784815 // alignment greater than 16 where necessary.
785- if layout. layout . align . bytes ( ) > 8 {
786- unreachable ! ( "all instances of VaArgSafe have an alignment <= 8" ) ;
787- }
816+ let overflow_arg_area_v = if layout. layout . align . bytes ( ) > 8 {
817+ round_pointer_up_to_alignment ( bx, overflow_arg_area_v, layout. layout . align . abi )
818+ } else {
819+ overflow_arg_area_v
820+ } ;
788821
789822 // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
790823 let mem_addr = overflow_arg_area_v;
@@ -1069,7 +1102,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10691102 Arch :: AArch64 => emit_aapcs_va_arg ( bx, addr, target_ty) ,
10701103 Arch :: Arm => {
10711104 // Types wider than 16 bytes are not currently supported. Clang has special logic for
1072- // such types, but `VaArgSafe` is not implemented for any type that is this large.
1105+ // such types, but `VaArgSafe` is not implemented for any type that is this large on
1106+ // arm (i.e. 32-bit) targets.
10731107 assert ! ( bx. cx. size_of( target_ty) . bytes( ) <= 16 ) ;
10741108
10751109 emit_ptr_va_arg (
@@ -1091,6 +1125,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10911125 PassMode :: Direct ,
10921126 SlotSize :: Bytes8 ,
10931127 AllowHigherAlign :: Yes ,
1128+ // ForceRightAdjust only takes effect on big-endian architectures.
10941129 ForceRightAdjust :: Yes ,
10951130 ) ,
10961131 Arch :: RiscV32 if target. llvm_abiname == LlvmAbi :: Ilp32e => {
0 commit comments