@@ -89,11 +89,35 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
8989 list : OperandRef < ' tcx , & ' ll Value > ,
9090 target_ty : Ty < ' tcx > ,
9191) -> & ' ll Value {
92+ let dl = bx. cx . data_layout ( ) ;
93+
9294 // Implementation of the AAPCS64 calling convention for va_args see
9395 // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
96+ //
97+ // typedef struct va_list {
98+ // void * stack; // next stack param
99+ // void * gr_top; // end of GP arg reg save area
100+ // void * vr_top; // end of FP/SIMD arg reg save area
101+ // int gr_offs; // offset from gr_top to next GP register arg
102+ // int vr_offs; // offset from vr_top to next FP/SIMD register arg
103+ // } va_list;
94104 let va_list_addr = list. immediate ( ) ;
95- let va_list_layout = list. deref ( bx. cx ) . layout ;
96- let va_list_ty = va_list_layout. llvm_type ( bx) ;
105+
106+ // There is no padding between fields since `void*` is size=8 align=8, `int` is size=4 align=4.
107+ // See https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
108+ // Table 1, Byte size and byte alignment of fundamental data types
109+ // Table 3, Mapping of C & C++ built-in data types
110+ let ptr_offset = 8 ;
111+ let i32_offset = 4 ;
112+ let gr_top = bx. inbounds_gep ( bx. type_i8 ( ) , va_list_addr, & [ bx. cx . const_usize ( ptr_offset) ] ) ;
113+ let vr_top = bx. inbounds_gep ( bx. type_i8 ( ) , va_list_addr, & [ bx. cx . const_usize ( 2 * ptr_offset) ] ) ;
114+ let gr_offs = bx. inbounds_gep ( bx. type_i8 ( ) , va_list_addr, & [ bx. cx . const_usize ( 3 * ptr_offset) ] ) ;
115+ let vr_offs = bx. inbounds_gep (
116+ bx. type_i8 ( ) ,
117+ va_list_addr,
118+ & [ bx. cx . const_usize ( 3 * ptr_offset + i32_offset) ] ,
119+ ) ;
120+
97121 let layout = bx. cx . layout_of ( target_ty) ;
98122
99123 let maybe_reg = bx. append_sibling_block ( "va_arg.maybe_reg" ) ;
@@ -104,16 +128,12 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
104128 let offset_align = Align :: from_bytes ( 4 ) . unwrap ( ) ;
105129
106130 let gr_type = target_ty. is_any_ptr ( ) || target_ty. is_integral ( ) ;
107- let ( reg_off, reg_top_index, slot_size) = if gr_type {
108- let gr_offs =
109- bx. struct_gep ( va_list_ty, va_list_addr, va_list_layout. llvm_field_index ( bx. cx , 3 ) ) ;
131+ let ( reg_off, reg_top, slot_size) = if gr_type {
110132 let nreg = ( layout. size . bytes ( ) + 7 ) / 8 ;
111- ( gr_offs, va_list_layout . llvm_field_index ( bx . cx , 1 ) , nreg * 8 )
133+ ( gr_offs, gr_top , nreg * 8 )
112134 } else {
113- let vr_off =
114- bx. struct_gep ( va_list_ty, va_list_addr, va_list_layout. llvm_field_index ( bx. cx , 4 ) ) ;
115135 let nreg = ( layout. size . bytes ( ) + 15 ) / 16 ;
116- ( vr_off , va_list_layout . llvm_field_index ( bx . cx , 2 ) , nreg * 16 )
136+ ( vr_offs , vr_top , nreg * 16 )
117137 } ;
118138
119139 // if the offset >= 0 then the value will be on the stack
@@ -141,8 +161,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
141161
142162 bx. switch_to_block ( in_reg) ;
143163 let top_type = bx. type_ptr ( ) ;
144- let top = bx. struct_gep ( va_list_ty, va_list_addr, reg_top_index) ;
145- let top = bx. load ( top_type, top, bx. tcx ( ) . data_layout . pointer_align . abi ) ;
164+ let top = bx. load ( top_type, reg_top, dl. pointer_align . abi ) ;
146165
147166 // reg_value = *(@top + reg_off_v);
148167 let mut reg_addr = bx. gep ( bx. type_i8 ( ) , top, & [ reg_off_v] ) ;
@@ -173,11 +192,33 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
173192 list : OperandRef < ' tcx , & ' ll Value > ,
174193 target_ty : Ty < ' tcx > ,
175194) -> & ' ll Value {
195+ let dl = bx. cx . data_layout ( ) ;
196+
176197 // Implementation of the s390x ELF ABI calling convention for va_args see
177198 // https://github.com/IBM/s390x-abi (chapter 1.2.4)
199+ //
200+ // typedef struct __va_list_tag {
201+ // long __gpr;
202+ // long __fpr;
203+ // void *__overflow_arg_area;
204+ // void *__reg_save_area;
205+ // } va_list[1];
178206 let va_list_addr = list. immediate ( ) ;
179- let va_list_layout = list. deref ( bx. cx ) . layout ;
180- let va_list_ty = va_list_layout. llvm_type ( bx) ;
207+
208+ // There is no padding between fields since `long` and `void*` both have size=8 align=8.
209+ // https://github.com/IBM/s390x-abi (Table 1.1.: Scalar types)
210+ let i64_offset = 8 ;
211+ let ptr_offset = 8 ;
212+ let gpr = va_list_addr;
213+ let fpr = bx. inbounds_gep ( bx. type_i8 ( ) , va_list_addr, & [ bx. cx . const_usize ( i64_offset) ] ) ;
214+ let overflow_arg_area =
215+ bx. inbounds_gep ( bx. type_i8 ( ) , va_list_addr, & [ bx. cx . const_usize ( 2 * i64_offset) ] ) ;
216+ let reg_save_area = bx. inbounds_gep (
217+ bx. type_i8 ( ) ,
218+ va_list_addr,
219+ & [ bx. cx . const_usize ( 2 * i64_offset + ptr_offset) ] ,
220+ ) ;
221+
181222 let layout = bx. cx . layout_of ( target_ty) ;
182223
183224 let in_reg = bx. append_sibling_block ( "va_arg.in_reg" ) ;
@@ -192,15 +233,10 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
192233 let padding = padded_size - unpadded_size;
193234
194235 let gpr_type = indirect || !layout. is_single_fp_element ( bx. cx ) ;
195- let ( max_regs, reg_count_field , reg_save_index, reg_padding) =
196- if gpr_type { ( 5 , 0 , 2 , padding) } else { ( 4 , 1 , 16 , 0 ) } ;
236+ let ( max_regs, reg_count , reg_save_index, reg_padding) =
237+ if gpr_type { ( 5 , gpr , 2 , padding) } else { ( 4 , fpr , 16 , 0 ) } ;
197238
198239 // Check whether the value was passed in a register or in memory.
199- let reg_count = bx. struct_gep (
200- va_list_ty,
201- va_list_addr,
202- va_list_layout. llvm_field_index ( bx. cx , reg_count_field) ,
203- ) ;
204240 let reg_count_v = bx. load ( bx. type_i64 ( ) , reg_count, Align :: from_bytes ( 8 ) . unwrap ( ) ) ;
205241 let use_regs = bx. icmp ( IntPredicate :: IntULT , reg_count_v, bx. const_u64 ( max_regs) ) ;
206242 bx. cond_br ( use_regs, in_reg, in_mem) ;
@@ -209,9 +245,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
209245 bx. switch_to_block ( in_reg) ;
210246
211247 // Work out the address of the value in the register save area.
212- let reg_ptr =
213- bx. struct_gep ( va_list_ty, va_list_addr, va_list_layout. llvm_field_index ( bx. cx , 3 ) ) ;
214- let reg_ptr_v = bx. load ( bx. type_ptr ( ) , reg_ptr, bx. tcx ( ) . data_layout . pointer_align . abi ) ;
248+ let reg_ptr_v = bx. load ( bx. type_ptr ( ) , reg_save_area, dl. pointer_align . abi ) ;
215249 let scaled_reg_count = bx. mul ( reg_count_v, bx. const_u64 ( 8 ) ) ;
216250 let reg_off = bx. add ( scaled_reg_count, bx. const_u64 ( reg_save_index * 8 + reg_padding) ) ;
217251 let reg_addr = bx. gep ( bx. type_i8 ( ) , reg_ptr_v, & [ reg_off] ) ;
@@ -225,27 +259,23 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
225259 bx. switch_to_block ( in_mem) ;
226260
227261 // Work out the address of the value in the argument overflow area.
228- let arg_ptr =
229- bx. struct_gep ( va_list_ty, va_list_addr, va_list_layout. llvm_field_index ( bx. cx , 2 ) ) ;
230- let arg_ptr_v = bx. load ( bx. type_ptr ( ) , arg_ptr, bx. tcx ( ) . data_layout . pointer_align . abi ) ;
262+ let arg_ptr_v =
263+ bx. load ( bx. type_ptr ( ) , overflow_arg_area, bx. tcx ( ) . data_layout . pointer_align . abi ) ;
231264 let arg_off = bx. const_u64 ( padding) ;
232265 let mem_addr = bx. gep ( bx. type_i8 ( ) , arg_ptr_v, & [ arg_off] ) ;
233266
234267 // Update the argument overflow area pointer.
235268 let arg_size = bx. cx ( ) . const_u64 ( padded_size) ;
236269 let new_arg_ptr_v = bx. inbounds_gep ( bx. type_i8 ( ) , arg_ptr_v, & [ arg_size] ) ;
237- bx. store ( new_arg_ptr_v, arg_ptr , bx . tcx ( ) . data_layout . pointer_align . abi ) ;
270+ bx. store ( new_arg_ptr_v, overflow_arg_area , dl . pointer_align . abi ) ;
238271 bx. br ( end) ;
239272
240273 // Return the appropriate result.
241274 bx. switch_to_block ( end) ;
242275 let val_addr = bx. phi ( bx. type_ptr ( ) , & [ reg_addr, mem_addr] , & [ in_reg, in_mem] ) ;
243276 let val_type = layout. llvm_type ( bx) ;
244- let val_addr = if indirect {
245- bx. load ( bx. cx . type_ptr ( ) , val_addr, bx. tcx ( ) . data_layout . pointer_align . abi )
246- } else {
247- val_addr
248- } ;
277+ let val_addr =
278+ if indirect { bx. load ( bx. cx . type_ptr ( ) , val_addr, dl. pointer_align . abi ) } else { val_addr } ;
249279 bx. load ( val_type, val_addr, layout. align . abi )
250280}
251281
0 commit comments