@@ -237,6 +237,148 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
237
237
val
238
238
}
239
239
240
+ fn emit_powerpc_va_arg < ' ll , ' tcx > (
241
+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
242
+ list : OperandRef < ' tcx , & ' ll Value > ,
243
+ target_ty : Ty < ' tcx > ,
244
+ ) -> & ' ll Value {
245
+ let dl = bx. cx . data_layout ( ) ;
246
+
247
+ // struct __va_list_tag {
248
+ // unsigned char gpr;
249
+ // unsigned char fpr;
250
+ // unsigned short reserved;
251
+ // void *overflow_arg_area;
252
+ // void *reg_save_area;
253
+ // };
254
+ let va_list_addr = list. immediate ( ) ;
255
+
256
+ // Peel off any newtype wrappers.
257
+ let layout = {
258
+ let mut layout = bx. cx . layout_of ( target_ty) ;
259
+
260
+ while let Some ( ( _, inner) ) = layout. non_1zst_field ( bx. cx ) {
261
+ layout = inner;
262
+ }
263
+
264
+ layout
265
+ } ;
266
+
267
+ // Rust does not support any powerpc softfloat targets.
268
+ let is_soft_float_abi = false ;
269
+
270
+ // All instances of VaArgSafe are passed directly.
271
+ let is_indirect = false ;
272
+
273
+ let ( is_i64, is_int, is_f64) = match layout. layout . backend_repr ( ) {
274
+ BackendRepr :: Scalar ( scalar) => match scalar. primitive ( ) {
275
+ rustc_abi:: Primitive :: Int ( integer, _) => ( integer. size ( ) . bits ( ) == 64 , true , false ) ,
276
+ rustc_abi:: Primitive :: Float ( float) => ( false , false , float. size ( ) . bits ( ) == 64 ) ,
277
+ rustc_abi:: Primitive :: Pointer ( _) => ( false , true , false ) ,
278
+ } ,
279
+ _ => unreachable ! ( "all instances of VaArgSafe are represented as scalars" ) ,
280
+ } ;
281
+
282
+ let num_regs_addr = if is_int || is_soft_float_abi {
283
+ va_list_addr // gpr
284
+ } else {
285
+ bx. inbounds_ptradd ( va_list_addr, bx. const_usize ( 1 ) ) // fpr
286
+ } ;
287
+
288
+ let mut num_regs = bx. load ( bx. type_i8 ( ) , num_regs_addr, dl. i8_align . abi ) ;
289
+
290
+ // "Align" the register count when the type is passed as `i64`.
291
+ if is_i64 || ( is_f64 && is_soft_float_abi) {
292
+ num_regs = bx. add ( num_regs, bx. const_u8 ( 1 ) ) ;
293
+ num_regs = bx. and ( num_regs, bx. const_u8 ( 0b1111_1110 ) ) ;
294
+ }
295
+
296
+ let max_regs = 8u8 ;
297
+ let use_regs = bx. icmp ( IntPredicate :: IntULT , num_regs, bx. const_u8 ( max_regs) ) ;
298
+
299
+ let in_reg = bx. append_sibling_block ( "va_arg.in_reg" ) ;
300
+ let in_mem = bx. append_sibling_block ( "va_arg.in_mem" ) ;
301
+ let end = bx. append_sibling_block ( "va_arg.end" ) ;
302
+
303
+ bx. cond_br ( use_regs, in_reg, in_mem) ;
304
+
305
+ let reg_addr = {
306
+ bx. switch_to_block ( in_reg) ;
307
+
308
+ let reg_safe_area_ptr = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( 1 + 1 + 2 + 4 ) ) ;
309
+ let mut reg_addr = bx. load ( bx. type_ptr ( ) , reg_safe_area_ptr, dl. pointer_align . abi ) ;
310
+
311
+ // Floating-point registers start after the general-purpose registers.
312
+ if !is_int && !is_soft_float_abi {
313
+ reg_addr = bx. inbounds_ptradd ( reg_addr, bx. cx . const_usize ( 32 ) )
314
+ }
315
+
316
+ // Get the address of the saved value by scaling the number of
317
+ // registers we've used by the number of.
318
+ let reg_size = if is_int || is_soft_float_abi { 4 } else { 8 } ;
319
+ let reg_offset = bx. mul ( num_regs, bx. cx ( ) . const_u8 ( reg_size) ) ;
320
+ let reg_addr = bx. inbounds_ptradd ( reg_addr, reg_offset) ;
321
+
322
+ // Increase the used-register count.
323
+ let reg_incr = if is_i64 || ( is_f64 && is_soft_float_abi) { 2 } else { 1 } ;
324
+ let new_num_regs = bx. add ( num_regs, bx. cx . const_u8 ( reg_incr) ) ;
325
+ bx. store ( new_num_regs, num_regs_addr, dl. i8_align . abi ) ;
326
+
327
+ bx. br ( end) ;
328
+
329
+ reg_addr
330
+ } ;
331
+
332
+ let mem_addr = {
333
+ bx. switch_to_block ( in_mem) ;
334
+
335
+ bx. store ( bx. const_u8 ( max_regs) , num_regs_addr, dl. i8_align . abi ) ;
336
+
337
+ // Everything in the overflow area is rounded up to a size of at least 4.
338
+ let overflow_area_align = Align :: from_bytes ( 4 ) . unwrap ( ) ;
339
+
340
+ let size = if !is_indirect {
341
+ layout. layout . size . align_to ( overflow_area_align)
342
+ } else {
343
+ dl. pointer_size
344
+ } ;
345
+
346
+ let overflow_area_ptr = bx. inbounds_ptradd ( va_list_addr, bx. cx . const_usize ( 1 + 1 + 2 ) ) ;
347
+ let mut overflow_area = bx. load ( bx. type_ptr ( ) , overflow_area_ptr, dl. pointer_align . abi ) ;
348
+
349
+ // Round up address of argument to alignment
350
+ if layout. layout . align . abi > overflow_area_align {
351
+ overflow_area = round_pointer_up_to_alignment (
352
+ bx,
353
+ overflow_area,
354
+ layout. layout . align . abi ,
355
+ bx. type_ptr ( ) ,
356
+ ) ;
357
+ }
358
+
359
+ let mem_addr = overflow_area;
360
+
361
+ // Increase the overflow area.
362
+ overflow_area = bx. inbounds_ptradd ( overflow_area, bx. const_usize ( size. bytes ( ) ) ) ;
363
+ bx. store ( overflow_area, overflow_area_ptr, dl. pointer_align . abi ) ;
364
+
365
+ bx. br ( end) ;
366
+
367
+ mem_addr
368
+ } ;
369
+
370
+ // Return the appropriate result.
371
+ bx. switch_to_block ( end) ;
372
+ let val_addr = bx. phi ( bx. type_ptr ( ) , & [ reg_addr, mem_addr] , & [ in_reg, in_mem] ) ;
373
+ let val_type = layout. llvm_type ( bx) ;
374
+ let val_addr = if is_indirect {
375
+ bx. load ( bx. cx . type_ptr ( ) , val_addr, dl. pointer_align . abi )
376
+ } else {
377
+ val_addr
378
+ } ;
379
+ bx. load ( val_type, val_addr, layout. align . abi )
380
+ }
381
+
240
382
fn emit_s390x_va_arg < ' ll , ' tcx > (
241
383
bx : & mut Builder < ' _ , ' ll , ' tcx > ,
242
384
list : OperandRef < ' tcx , & ' ll Value > ,
@@ -773,6 +915,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
773
915
}
774
916
"aarch64" => emit_aapcs_va_arg ( bx, addr, target_ty) ,
775
917
"s390x" => emit_s390x_va_arg ( bx, addr, target_ty) ,
918
+ "powerpc" => emit_powerpc_va_arg ( bx, addr, target_ty) ,
776
919
"powerpc64" | "powerpc64le" => emit_ptr_va_arg (
777
920
bx,
778
921
addr,
0 commit comments