@@ -44,12 +44,12 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
44
44
45
45
let aligned_size = size. align_to ( slot_size) . bytes ( ) as i32 ;
46
46
let full_direct_size = bx. cx ( ) . const_i32 ( aligned_size) ;
47
- let next = bx. inbounds_gep ( bx . type_i8 ( ) , addr, & [ full_direct_size] ) ;
47
+ let next = bx. inbounds_ptradd ( addr, full_direct_size) ;
48
48
bx. store ( next, va_list_addr, bx. tcx ( ) . data_layout . pointer_align . abi ) ;
49
49
50
50
if size. bytes ( ) < slot_size. bytes ( ) && bx. tcx ( ) . sess . target . endian == Endian :: Big {
51
51
let adjusted_size = bx. cx ( ) . const_i32 ( ( slot_size. bytes ( ) - size. bytes ( ) ) as i32 ) ;
52
- let adjusted = bx. inbounds_gep ( bx . type_i8 ( ) , addr, & [ adjusted_size] ) ;
52
+ let adjusted = bx. inbounds_ptradd ( addr, adjusted_size) ;
53
53
( adjusted, addr_align)
54
54
} else {
55
55
( addr, addr_align)
@@ -89,11 +89,31 @@ 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_ptradd ( va_list_addr, bx. cx . const_usize ( ptr_offset) ) ;
113
+ let vr_top = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( 2 * ptr_offset) ) ;
114
+ let gr_offs = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( 3 * ptr_offset) ) ;
115
+ let vr_offs = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( 3 * ptr_offset + i32_offset) ) ;
116
+
97
117
let layout = bx. cx . layout_of ( target_ty) ;
98
118
99
119
let maybe_reg = bx. append_sibling_block ( "va_arg.maybe_reg" ) ;
@@ -104,16 +124,12 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
104
124
let offset_align = Align :: from_bytes ( 4 ) . unwrap ( ) ;
105
125
106
126
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 ) ) ;
127
+ let ( reg_off, reg_top, slot_size) = if gr_type {
110
128
let nreg = ( layout. size . bytes ( ) + 7 ) / 8 ;
111
- ( gr_offs, va_list_layout . llvm_field_index ( bx . cx , 1 ) , nreg * 8 )
129
+ ( gr_offs, gr_top , nreg * 8 )
112
130
} 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
131
let nreg = ( layout. size . bytes ( ) + 15 ) / 16 ;
116
- ( vr_off , va_list_layout . llvm_field_index ( bx . cx , 2 ) , nreg * 16 )
132
+ ( vr_offs , vr_top , nreg * 16 )
117
133
} ;
118
134
119
135
// if the offset >= 0 then the value will be on the stack
@@ -141,15 +157,14 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
141
157
142
158
bx. switch_to_block ( in_reg) ;
143
159
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 ) ;
160
+ let top = bx. load ( top_type, reg_top, dl. pointer_align . abi ) ;
146
161
147
162
// reg_value = *(@top + reg_off_v);
148
- let mut reg_addr = bx. gep ( bx . type_i8 ( ) , top, & [ reg_off_v] ) ;
163
+ let mut reg_addr = bx. ptradd ( top, reg_off_v) ;
149
164
if bx. tcx ( ) . sess . target . endian == Endian :: Big && layout. size . bytes ( ) != slot_size {
150
165
// On big-endian systems the value is right-aligned in its slot.
151
166
let offset = bx. const_i32 ( ( slot_size - layout. size . bytes ( ) ) as i32 ) ;
152
- reg_addr = bx. gep ( bx . type_i8 ( ) , reg_addr, & [ offset] ) ;
167
+ reg_addr = bx. ptradd ( reg_addr, offset) ;
153
168
}
154
169
let reg_type = layout. llvm_type ( bx) ;
155
170
let reg_value = bx. load ( reg_type, reg_addr, layout. align . abi ) ;
@@ -173,11 +188,29 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
173
188
list : OperandRef < ' tcx , & ' ll Value > ,
174
189
target_ty : Ty < ' tcx > ,
175
190
) -> & ' ll Value {
191
+ let dl = bx. cx . data_layout ( ) ;
192
+
176
193
// Implementation of the s390x ELF ABI calling convention for va_args see
177
194
// https://github.com/IBM/s390x-abi (chapter 1.2.4)
195
+ //
196
+ // typedef struct __va_list_tag {
197
+ // long __gpr;
198
+ // long __fpr;
199
+ // void *__overflow_arg_area;
200
+ // void *__reg_save_area;
201
+ // } va_list[1];
178
202
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) ;
203
+
204
+ // There is no padding between fields since `long` and `void*` both have size=8 align=8.
205
+ // https://github.com/IBM/s390x-abi (Table 1.1.: Scalar types)
206
+ let i64_offset = 8 ;
207
+ let ptr_offset = 8 ;
208
+ let gpr = va_list_addr;
209
+ let fpr = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( i64_offset) ) ;
210
+ let overflow_arg_area = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( 2 * i64_offset) ) ;
211
+ let reg_save_area =
212
+ bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( 2 * i64_offset + ptr_offset) ) ;
213
+
181
214
let layout = bx. cx . layout_of ( target_ty) ;
182
215
183
216
let in_reg = bx. append_sibling_block ( "va_arg.in_reg" ) ;
@@ -192,15 +225,10 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
192
225
let padding = padded_size - unpadded_size;
193
226
194
227
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 ) } ;
228
+ let ( max_regs, reg_count , reg_save_index, reg_padding) =
229
+ if gpr_type { ( 5 , gpr , 2 , padding) } else { ( 4 , fpr , 16 , 0 ) } ;
197
230
198
231
// 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
232
let reg_count_v = bx. load ( bx. type_i64 ( ) , reg_count, Align :: from_bytes ( 8 ) . unwrap ( ) ) ;
205
233
let use_regs = bx. icmp ( IntPredicate :: IntULT , reg_count_v, bx. const_u64 ( max_regs) ) ;
206
234
bx. cond_br ( use_regs, in_reg, in_mem) ;
@@ -209,12 +237,10 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
209
237
bx. switch_to_block ( in_reg) ;
210
238
211
239
// 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 ) ;
240
+ let reg_ptr_v = bx. load ( bx. type_ptr ( ) , reg_save_area, dl. pointer_align . abi ) ;
215
241
let scaled_reg_count = bx. mul ( reg_count_v, bx. const_u64 ( 8 ) ) ;
216
242
let reg_off = bx. add ( scaled_reg_count, bx. const_u64 ( reg_save_index * 8 + reg_padding) ) ;
217
- let reg_addr = bx. gep ( bx . type_i8 ( ) , reg_ptr_v, & [ reg_off] ) ;
243
+ let reg_addr = bx. ptradd ( reg_ptr_v, reg_off) ;
218
244
219
245
// Update the register count.
220
246
let new_reg_count_v = bx. add ( reg_count_v, bx. const_u64 ( 1 ) ) ;
@@ -225,27 +251,23 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
225
251
bx. switch_to_block ( in_mem) ;
226
252
227
253
// 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 ) ;
254
+ let arg_ptr_v =
255
+ bx. load ( bx. type_ptr ( ) , overflow_arg_area, bx. tcx ( ) . data_layout . pointer_align . abi ) ;
231
256
let arg_off = bx. const_u64 ( padding) ;
232
- let mem_addr = bx. gep ( bx . type_i8 ( ) , arg_ptr_v, & [ arg_off] ) ;
257
+ let mem_addr = bx. ptradd ( arg_ptr_v, arg_off) ;
233
258
234
259
// Update the argument overflow area pointer.
235
260
let arg_size = bx. cx ( ) . const_u64 ( padded_size) ;
236
- 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 ) ;
261
+ let new_arg_ptr_v = bx. inbounds_ptradd ( arg_ptr_v, arg_size) ;
262
+ bx. store ( new_arg_ptr_v, overflow_arg_area , dl . pointer_align . abi ) ;
238
263
bx. br ( end) ;
239
264
240
265
// Return the appropriate result.
241
266
bx. switch_to_block ( end) ;
242
267
let val_addr = bx. phi ( bx. type_ptr ( ) , & [ reg_addr, mem_addr] , & [ in_reg, in_mem] ) ;
243
268
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
- } ;
269
+ let val_addr =
270
+ if indirect { bx. load ( bx. cx . type_ptr ( ) , val_addr, dl. pointer_align . abi ) } else { val_addr } ;
249
271
bx. load ( val_type, val_addr, layout. align . abi )
250
272
}
251
273
0 commit comments