@@ -40,6 +40,7 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
4040    align :  Align , 
4141    slot_size :  Align , 
4242    allow_higher_align :  bool , 
43+     force_right_adjust :  bool , 
4344)  -> ( & ' ll  Value ,  Align )  { 
4445    let  va_list_ty = bx. type_ptr ( ) ; 
4546    let  va_list_addr = list. immediate ( ) ; 
@@ -57,7 +58,10 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
5758    let  next = bx. inbounds_ptradd ( addr,  full_direct_size) ; 
5859    bx. store ( next,  va_list_addr,  bx. tcx ( ) . data_layout . pointer_align . abi ) ; 
5960
60-     if  size. bytes ( )  < slot_size. bytes ( )  && bx. tcx ( ) . sess . target . endian  == Endian :: Big  { 
61+     if  size. bytes ( )  < slot_size. bytes ( ) 
62+         && bx. tcx ( ) . sess . target . endian  == Endian :: Big 
63+         && force_right_adjust
64+     { 
6165        let  adjusted_size = bx. cx ( ) . const_i32 ( ( slot_size. bytes ( )  - size. bytes ( ) )  as  i32 ) ; 
6266        let  adjusted = bx. inbounds_ptradd ( addr,  adjusted_size) ; 
6367        ( adjusted,  addr_align) 
@@ -81,16 +85,23 @@ enum AllowHigherAlign {
8185    Yes , 
8286} 
8387
88+ enum  ForceRightAdjust  { 
89+     No , 
90+     Yes , 
91+ } 
92+ 
8493fn  emit_ptr_va_arg < ' ll ,  ' tcx > ( 
8594    bx :  & mut  Builder < ' _ ,  ' ll ,  ' tcx > , 
8695    list :  OperandRef < ' tcx ,  & ' ll  Value > , 
8796    target_ty :  Ty < ' tcx > , 
8897    pass_mode :  PassMode , 
8998    slot_size :  SlotSize , 
9099    allow_higher_align :  AllowHigherAlign , 
100+     force_right_adjust :  ForceRightAdjust , 
91101)  -> & ' ll  Value  { 
92102    let  indirect = matches ! ( pass_mode,  PassMode :: Indirect ) ; 
93103    let  allow_higher_align = matches ! ( allow_higher_align,  AllowHigherAlign :: Yes ) ; 
104+     let  force_right_adjust = matches ! ( force_right_adjust,  ForceRightAdjust :: Yes ) ; 
94105    let  slot_size = Align :: from_bytes ( slot_size as  u64 ) . unwrap ( ) ; 
95106
96107    let  layout = bx. cx . layout_of ( target_ty) ; 
@@ -103,8 +114,15 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
103114    }  else  { 
104115        ( layout. llvm_type ( bx. cx ) ,  layout. size ,  layout. align ) 
105116    } ; 
106-     let  ( addr,  addr_align)  =
107-         emit_direct_ptr_va_arg ( bx,  list,  size,  align. abi ,  slot_size,  allow_higher_align) ; 
117+     let  ( addr,  addr_align)  = emit_direct_ptr_va_arg ( 
118+         bx, 
119+         list, 
120+         size, 
121+         align. abi , 
122+         slot_size, 
123+         allow_higher_align, 
124+         force_right_adjust, 
125+     ) ; 
108126    if  indirect { 
109127        let  tmp_ret = bx. load ( llty,  addr,  addr_align) ; 
110128        bx. load ( bx. cx . layout_of ( target_ty) . llvm_type ( bx. cx ) ,  tmp_ret,  align. abi ) 
@@ -208,6 +226,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
208226        PassMode :: Direct , 
209227        SlotSize :: Bytes8 , 
210228        AllowHigherAlign :: Yes , 
229+         ForceRightAdjust :: No , 
211230    ) ; 
212231    bx. br ( end) ; 
213232
@@ -218,6 +237,150 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
218237    val
219238} 
220239
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 currently support any powerpc softfloat targets. 
268+     let  target = & bx. cx . tcx . sess . target ; 
269+     let  is_soft_float_abi = target. abi  == "softfloat" ; 
270+     assert ! ( !is_soft_float_abi) ; 
271+ 
272+     // All instances of VaArgSafe are passed directly. 
273+     let  is_indirect = false ; 
274+ 
275+     let  ( is_i64,  is_int,  is_f64)  = match  layout. layout . backend_repr ( )  { 
276+         BackendRepr :: Scalar ( scalar)  => match  scalar. primitive ( )  { 
277+             rustc_abi:: Primitive :: Int ( integer,  _)  => ( integer. size ( ) . bits ( )  == 64 ,  true ,  false ) , 
278+             rustc_abi:: Primitive :: Float ( float)  => ( false ,  false ,  float. size ( ) . bits ( )  == 64 ) , 
279+             rustc_abi:: Primitive :: Pointer ( _)  => ( false ,  true ,  false ) , 
280+         } , 
281+         _ => unreachable ! ( "all instances of VaArgSafe are represented as scalars" ) , 
282+     } ; 
283+ 
284+     let  num_regs_addr = if  is_int || is_soft_float_abi { 
285+         va_list_addr // gpr 
286+     }  else  { 
287+         bx. inbounds_ptradd ( va_list_addr,  bx. const_usize ( 1 ) )  // fpr 
288+     } ; 
289+ 
290+     let  mut  num_regs = bx. load ( bx. type_i8 ( ) ,  num_regs_addr,  dl. i8_align . abi ) ; 
291+ 
292+     // "Align" the register count when the type is passed as `i64`. 
293+     if  is_i64 || ( is_f64 && is_soft_float_abi)  { 
294+         num_regs = bx. add ( num_regs,  bx. const_u8 ( 1 ) ) ; 
295+         num_regs = bx. and ( num_regs,  bx. const_u8 ( 0b1111_1110 ) ) ; 
296+     } 
297+ 
298+     let  max_regs = 8u8 ; 
299+     let  use_regs = bx. icmp ( IntPredicate :: IntULT ,  num_regs,  bx. const_u8 ( max_regs) ) ; 
300+ 
301+     let  in_reg = bx. append_sibling_block ( "va_arg.in_reg" ) ; 
302+     let  in_mem = bx. append_sibling_block ( "va_arg.in_mem" ) ; 
303+     let  end = bx. append_sibling_block ( "va_arg.end" ) ; 
304+ 
305+     bx. cond_br ( use_regs,  in_reg,  in_mem) ; 
306+ 
307+     let  reg_addr = { 
308+         bx. switch_to_block ( in_reg) ; 
309+ 
310+         let  reg_safe_area_ptr = bx. inbounds_ptradd ( va_list_addr,  bx. cx . const_usize ( 1  + 1  + 2  + 4 ) ) ; 
311+         let  mut  reg_addr = bx. load ( bx. type_ptr ( ) ,  reg_safe_area_ptr,  dl. pointer_align . abi ) ; 
312+ 
313+         // Floating-point registers start after the general-purpose registers. 
314+         if  !is_int && !is_soft_float_abi { 
315+             reg_addr = bx. inbounds_ptradd ( reg_addr,  bx. cx . const_usize ( 32 ) ) 
316+         } 
317+ 
318+         // Get the address of the saved value by scaling the number of 
319+         // registers we've used by the number of. 
320+         let  reg_size = if  is_int || is_soft_float_abi {  4  }  else  {  8  } ; 
321+         let  reg_offset = bx. mul ( num_regs,  bx. cx ( ) . const_u8 ( reg_size) ) ; 
322+         let  reg_addr = bx. inbounds_ptradd ( reg_addr,  reg_offset) ; 
323+ 
324+         // Increase the used-register count. 
325+         let  reg_incr = if  is_i64 || ( is_f64 && is_soft_float_abi)  {  2  }  else  {  1  } ; 
326+         let  new_num_regs = bx. add ( num_regs,  bx. cx . const_u8 ( reg_incr) ) ; 
327+         bx. store ( new_num_regs,  num_regs_addr,  dl. i8_align . abi ) ; 
328+ 
329+         bx. br ( end) ; 
330+ 
331+         reg_addr
332+     } ; 
333+ 
334+     let  mem_addr = { 
335+         bx. switch_to_block ( in_mem) ; 
336+ 
337+         bx. store ( bx. const_u8 ( max_regs) ,  num_regs_addr,  dl. i8_align . abi ) ; 
338+ 
339+         // Everything in the overflow area is rounded up to a size of at least 4. 
340+         let  overflow_area_align = Align :: from_bytes ( 4 ) . unwrap ( ) ; 
341+ 
342+         let  size = if  !is_indirect { 
343+             layout. layout . size . align_to ( overflow_area_align) 
344+         }  else  { 
345+             dl. pointer_size 
346+         } ; 
347+ 
348+         let  overflow_area_ptr = bx. inbounds_ptradd ( va_list_addr,  bx. cx . const_usize ( 1  + 1  + 2 ) ) ; 
349+         let  mut  overflow_area = bx. load ( bx. type_ptr ( ) ,  overflow_area_ptr,  dl. pointer_align . abi ) ; 
350+ 
351+         // Round up address of argument to alignment 
352+         if  layout. layout . align . abi  > overflow_area_align { 
353+             overflow_area = round_pointer_up_to_alignment ( 
354+                 bx, 
355+                 overflow_area, 
356+                 layout. layout . align . abi , 
357+                 bx. type_ptr ( ) , 
358+             ) ; 
359+         } 
360+ 
361+         let  mem_addr = overflow_area; 
362+ 
363+         // Increase the overflow area. 
364+         overflow_area = bx. inbounds_ptradd ( overflow_area,  bx. const_usize ( size. bytes ( ) ) ) ; 
365+         bx. store ( overflow_area,  overflow_area_ptr,  dl. pointer_align . abi ) ; 
366+ 
367+         bx. br ( end) ; 
368+ 
369+         mem_addr
370+     } ; 
371+ 
372+     // Return the appropriate result. 
373+     bx. switch_to_block ( end) ; 
374+     let  val_addr = bx. phi ( bx. type_ptr ( ) ,  & [ reg_addr,  mem_addr] ,  & [ in_reg,  in_mem] ) ; 
375+     let  val_type = layout. llvm_type ( bx) ; 
376+     let  val_addr = if  is_indirect { 
377+         bx. load ( bx. cx . type_ptr ( ) ,  val_addr,  dl. pointer_align . abi ) 
378+     }  else  { 
379+         val_addr
380+     } ; 
381+     bx. load ( val_type,  val_addr,  layout. align . abi ) 
382+ } 
383+ 
221384fn  emit_s390x_va_arg < ' ll ,  ' tcx > ( 
222385    bx :  & mut  Builder < ' _ ,  ' ll ,  ' tcx > , 
223386    list :  OperandRef < ' tcx ,  & ' ll  Value > , 
@@ -728,6 +891,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
728891            PassMode :: Direct , 
729892            SlotSize :: Bytes4 , 
730893            if  target. is_like_windows  {  AllowHigherAlign :: No  }  else  {  AllowHigherAlign :: Yes  } , 
894+             ForceRightAdjust :: No , 
731895        ) , 
732896        "aarch64"  | "arm64ec"  if  target. is_like_windows  || target. is_like_darwin  => { 
733897            emit_ptr_va_arg ( 
@@ -737,10 +901,24 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
737901                PassMode :: Direct , 
738902                SlotSize :: Bytes8 , 
739903                if  target. is_like_windows  {  AllowHigherAlign :: No  }  else  {  AllowHigherAlign :: Yes  } , 
904+                 ForceRightAdjust :: No , 
740905            ) 
741906        } 
742907        "aarch64"  => emit_aapcs_va_arg ( bx,  addr,  target_ty) , 
743908        "s390x"  => emit_s390x_va_arg ( bx,  addr,  target_ty) , 
909+         "powerpc"  => emit_powerpc_va_arg ( bx,  addr,  target_ty) , 
910+         "powerpc64"  | "powerpc64le"  => emit_ptr_va_arg ( 
911+             bx, 
912+             addr, 
913+             target_ty, 
914+             PassMode :: Direct , 
915+             SlotSize :: Bytes8 , 
916+             AllowHigherAlign :: Yes , 
917+             match  & * target. arch  { 
918+                 "powerpc64"  => ForceRightAdjust :: Yes , 
919+                 _ => ForceRightAdjust :: No , 
920+             } , 
921+         ) , 
744922        // Windows x86_64 
745923        "x86_64"  if  target. is_like_windows  => { 
746924            let  target_ty_size = bx. cx . size_of ( target_ty) . bytes ( ) ; 
@@ -755,6 +933,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
755933                } , 
756934                SlotSize :: Bytes8 , 
757935                AllowHigherAlign :: No , 
936+                 ForceRightAdjust :: No , 
758937            ) 
759938        } 
760939        // This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64. 
0 commit comments