@@ -89,11 +89,35 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
89
89
list : OperandRef < ' tcx , & ' ll Value > ,
90
90
target_ty : Ty < ' tcx > ,
91
91
) -> & ' ll Value {
92
+ let dl = bx. cx . data_layout ( ) ;
93
+
92
94
// Implementation of the AAPCS64 calling convention for va_args see
93
95
// 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;
94
104
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
+
97
121
let layout = bx. cx . layout_of ( target_ty) ;
98
122
99
123
let maybe_reg = bx. append_sibling_block ( "va_arg.maybe_reg" ) ;
@@ -104,16 +128,12 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
104
128
let offset_align = Align :: from_bytes ( 4 ) . unwrap ( ) ;
105
129
106
130
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 {
110
132
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 )
112
134
} else {
113
- let vr_off =
114
- bx. struct_gep ( va_list_ty, va_list_addr, va_list_layout. llvm_field_index ( bx. cx , 4 ) ) ;
115
135
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 )
117
137
} ;
118
138
119
139
// if the offset >= 0 then the value will be on the stack
@@ -141,8 +161,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
141
161
142
162
bx. switch_to_block ( in_reg) ;
143
163
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 ) ;
146
165
147
166
// reg_value = *(@top + reg_off_v);
148
167
let mut reg_addr = bx. gep ( bx. type_i8 ( ) , top, & [ reg_off_v] ) ;
@@ -173,11 +192,33 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
173
192
list : OperandRef < ' tcx , & ' ll Value > ,
174
193
target_ty : Ty < ' tcx > ,
175
194
) -> & ' ll Value {
195
+ let dl = bx. cx . data_layout ( ) ;
196
+
176
197
// Implementation of the s390x ELF ABI calling convention for va_args see
177
198
// 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];
178
206
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
+
181
222
let layout = bx. cx . layout_of ( target_ty) ;
182
223
183
224
let in_reg = bx. append_sibling_block ( "va_arg.in_reg" ) ;
@@ -192,15 +233,10 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
192
233
let padding = padded_size - unpadded_size;
193
234
194
235
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 ) } ;
197
238
198
239
// 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
- ) ;
204
240
let reg_count_v = bx. load ( bx. type_i64 ( ) , reg_count, Align :: from_bytes ( 8 ) . unwrap ( ) ) ;
205
241
let use_regs = bx. icmp ( IntPredicate :: IntULT , reg_count_v, bx. const_u64 ( max_regs) ) ;
206
242
bx. cond_br ( use_regs, in_reg, in_mem) ;
@@ -209,9 +245,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
209
245
bx. switch_to_block ( in_reg) ;
210
246
211
247
// 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 ) ;
215
249
let scaled_reg_count = bx. mul ( reg_count_v, bx. const_u64 ( 8 ) ) ;
216
250
let reg_off = bx. add ( scaled_reg_count, bx. const_u64 ( reg_save_index * 8 + reg_padding) ) ;
217
251
let reg_addr = bx. gep ( bx. type_i8 ( ) , reg_ptr_v, & [ reg_off] ) ;
@@ -225,27 +259,23 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
225
259
bx. switch_to_block ( in_mem) ;
226
260
227
261
// 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 ) ;
231
264
let arg_off = bx. const_u64 ( padding) ;
232
265
let mem_addr = bx. gep ( bx. type_i8 ( ) , arg_ptr_v, & [ arg_off] ) ;
233
266
234
267
// Update the argument overflow area pointer.
235
268
let arg_size = bx. cx ( ) . const_u64 ( padded_size) ;
236
269
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 ) ;
238
271
bx. br ( end) ;
239
272
240
273
// Return the appropriate result.
241
274
bx. switch_to_block ( end) ;
242
275
let val_addr = bx. phi ( bx. type_ptr ( ) , & [ reg_addr, mem_addr] , & [ in_reg, in_mem] ) ;
243
276
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 } ;
249
279
bx. load ( val_type, val_addr, layout. align . abi )
250
280
}
251
281
0 commit comments