@@ -3,8 +3,9 @@ use crate::type_::Type;
33use  crate :: type_of:: LayoutLlvmExt ; 
44use  crate :: value:: Value ; 
55use  rustc_codegen_ssa:: mir:: operand:: OperandRef ; 
6- use  rustc_codegen_ssa:: traits:: { 
7-     BaseTypeMethods ,  BuilderMethods ,  ConstMethods ,  DerivedTypeMethods , 
6+ use  rustc_codegen_ssa:: { 
7+     common:: IntPredicate , 
8+     traits:: { BaseTypeMethods ,  BuilderMethods ,  ConstMethods ,  DerivedTypeMethods } , 
89} ; 
910use  rustc_middle:: ty:: layout:: HasTyCtxt ; 
1011use  rustc_middle:: ty:: Ty ; 
@@ -89,6 +90,81 @@ fn emit_ptr_va_arg(
8990    } 
9091} 
9192
93+ fn  emit_aapcs_va_arg ( 
94+     bx :  & mut  Builder < ' a ,  ' ll ,  ' tcx > , 
95+     list :  OperandRef < ' tcx ,  & ' ll  Value > , 
96+     target_ty :  Ty < ' tcx > , 
97+ )  -> & ' ll  Value  { 
98+     // Implementation of the AAPCS64 calling convention for va_args see 
99+     // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst 
100+     let  va_list_addr = list. immediate ( ) ; 
101+     let  layout = bx. cx . layout_of ( target_ty) ; 
102+ 
103+     let  mut  maybe_reg = bx. build_sibling_block ( "va_arg.maybe_reg" ) ; 
104+     let  mut  in_reg = bx. build_sibling_block ( "va_arg.in_reg" ) ; 
105+     let  mut  on_stack = bx. build_sibling_block ( "va_arg.on_stack" ) ; 
106+     let  mut  end = bx. build_sibling_block ( "va_arg.end" ) ; 
107+     let  zero = bx. const_i32 ( 0 ) ; 
108+     let  offset_align = Align :: from_bytes ( 4 ) . unwrap ( ) ; 
109+     assert ! ( & * bx. tcx( ) . sess. target. target. target_endian == "little" ) ; 
110+ 
111+     let  gr_type = target_ty. is_any_ptr ( )  || target_ty. is_integral ( ) ; 
112+     let  ( reg_off,  reg_top_index,  slot_size)  = if  gr_type { 
113+         let  gr_offs = bx. struct_gep ( va_list_addr,  7 ) ; 
114+         let  nreg = ( layout. size . bytes ( )  + 7 )  / 8 ; 
115+         ( gr_offs,  3 ,  nreg *  8 ) 
116+     }  else  { 
117+         let  vr_off = bx. struct_gep ( va_list_addr,  9 ) ; 
118+         let  nreg = ( layout. size . bytes ( )  + 15 )  / 16 ; 
119+         ( vr_off,  5 ,  nreg *  16 ) 
120+     } ; 
121+ 
122+     // if the offset >= 0 then the value will be on the stack 
123+     let  mut  reg_off_v = bx. load ( reg_off,  offset_align) ; 
124+     let  use_stack = bx. icmp ( IntPredicate :: IntSGE ,  reg_off_v,  zero) ; 
125+     bx. cond_br ( use_stack,  & on_stack. llbb ( ) ,  & maybe_reg. llbb ( ) ) ; 
126+ 
127+     // The value at this point might be in a register, but there is a chance that 
128+     // it could be on the stack so we have to update the offset and then check 
129+     // the offset again. 
130+ 
131+     if  gr_type && layout. align . abi . bytes ( )  > 8  { 
132+         reg_off_v = maybe_reg. add ( reg_off_v,  bx. const_i32 ( 15 ) ) ; 
133+         reg_off_v = maybe_reg. and ( reg_off_v,  bx. const_i32 ( -16 ) ) ; 
134+     } 
135+     let  new_reg_off_v = maybe_reg. add ( reg_off_v,  bx. const_i32 ( slot_size as  i32 ) ) ; 
136+ 
137+     maybe_reg. store ( new_reg_off_v,  reg_off,  offset_align) ; 
138+ 
139+     // Check to see if we have overflowed the registers as a result of this. 
140+     // If we have then we need to use the stack for this value 
141+     let  use_stack = maybe_reg. icmp ( IntPredicate :: IntSGT ,  new_reg_off_v,  zero) ; 
142+     maybe_reg. cond_br ( use_stack,  & on_stack. llbb ( ) ,  & in_reg. llbb ( ) ) ; 
143+ 
144+     let  top = in_reg. struct_gep ( va_list_addr,  reg_top_index) ; 
145+     let  top = in_reg. load ( top,  bx. tcx ( ) . data_layout . pointer_align . abi ) ; 
146+ 
147+     // reg_value = *(@top + reg_off_v); 
148+     let  top = in_reg. gep ( top,  & [ reg_off_v] ) ; 
149+     let  top = in_reg. bitcast ( top,  bx. cx . type_ptr_to ( layout. llvm_type ( bx) ) ) ; 
150+     let  reg_value = in_reg. load ( top,  layout. align . abi ) ; 
151+     in_reg. br ( & end. llbb ( ) ) ; 
152+ 
153+     // On Stack block 
154+     let  stack_value =
155+         emit_ptr_va_arg ( & mut  on_stack,  list,  target_ty,  false ,  Align :: from_bytes ( 8 ) . unwrap ( ) ,  true ) ; 
156+     on_stack. br ( & end. llbb ( ) ) ; 
157+ 
158+     let  val = end. phi ( 
159+         layout. immediate_llvm_type ( bx) , 
160+         & [ reg_value,  stack_value] , 
161+         & [ & in_reg. llbb ( ) ,  & on_stack. llbb ( ) ] , 
162+     ) ; 
163+ 
164+     * bx = end; 
165+     val
166+ } 
167+ 
92168pub ( super )  fn  emit_va_arg ( 
93169    bx :  & mut  Builder < ' a ,  ' ll ,  ' tcx > , 
94170    addr :  OperandRef < ' tcx ,  & ' ll  Value > , 
@@ -115,6 +191,7 @@ pub(super) fn emit_va_arg(
115191        ( "aarch64" ,  _)  if  target. target_os  == "ios"  => { 
116192            emit_ptr_va_arg ( bx,  addr,  target_ty,  false ,  Align :: from_bytes ( 8 ) . unwrap ( ) ,  true ) 
117193        } 
194+         ( "aarch64" ,  _)  => emit_aapcs_va_arg ( bx,  addr,  target_ty) , 
118195        // Windows x86_64 
119196        ( "x86_64" ,  true )  => { 
120197            let  target_ty_size = bx. cx . size_of ( target_ty) . bytes ( ) ; 
0 commit comments