kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

139_variadic_stack_arg_call_result.toy (1397B)


      1 // Regression: a variadic argument is passed on the stack (Apple arm64 ABI),
      2 // and its source value is the result of a *non-inlined* call, which the
      3 // register allocator leaves in the ABI return/arg register x0. The fixed
      4 // parameter `n` also targets x0. A single forward pass over the call's
      5 // arguments would load `n` into x0 first, clobbering the still-pending call
      6 // result before the stack store reads it, printing garbage. The backend must
      7 // read every stack-arg source before overwriting any argument register.
      8 //
      9 // `make` is marked noinline so its result genuinely comes back in x0 via a
     10 // real `bl`; if it inlined, the value would be computed in a scratch reg and
     11 // the hazard would never arise.
     12 
     13 fn @[.noinline] make(x: i64): i64 {
     14   return x + x;
     15 }
     16 
     17 fn vfn(n: i64, ...): i64 {
     18   var ap: va_list;
     19   @va_start(ap);
     20   let a: i64 = @va_arg<i64>(ap);
     21   let b: i64 = @va_arg<i64>(ap);
     22   @va_end(ap);
     23   return n * (100 as i64) + a * (10 as i64) + b;
     24 }
     25 
     26 fn __user_main(): i64 {
     27   // Call result is the last (second) variadic stack arg.
     28   if vfn(7, 3 as i64, make(64)) != (858 as i64) { return 1; }
     29   // Call result is the first variadic stack arg.
     30   if vfn(7, make(64), 3 as i64) != (1983 as i64) { return 2; }
     31   // Both variadic stack args are call results.
     32   if vfn(1, make(10), make(20)) != (340 as i64) { return 3; }
     33   return 42;
     34 }
     35 
     36 fn main(): i32 { return __user_main() as i32; }