<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/96212>96212</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Sketch of copying a va_list delimited buffer for gpu libc
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            libc
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
            JonChesterfield,
            jhuber6
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          JonChesterfield
      </td>
    </tr>
</table>

<pre>
    GPU libc would like to do things like copy the variadic arguments to printf across to the host and deal with them there. This is really easy if the extent of the structure denoted by a va_list is known and otherwise very difficult. This will work especially well on nvtpx where it is flat, and may be an argument to keep it flat on amdgpu (as opposed to changing some of the structure to pointers).

This is roughly a design note intended for @jhuber6 as writing here is more permanent than in slack.

Choices:
- va_list as ptr + size in a struct
- va_list as ptr + ptr in a struct 
- write the size in the underlying buffer
- write the pointer in the underlying buffer
- other?

The two things in a struct approach is simple and straightforward. va_arg moves the first pointer and leaves the other field along. va_copy copies both. It's inconsistent with nvcc's use of a single pointer and I have some doubts about burning a second vgpr for it on amdgpu.

I think we should go with a single pointer, aimed at the next value for va_arg to dereference, and also store a pointer or size in the buffer it aims at, like:

```
struct
{
  int earlier;
  [ptr end | size_t len];
  int x; <- va_list currently points here
  double y;
};
```

va_arg would dereference x and calculate y as it currently does, but also reads the previous field, increments it, and writes it back to where x used to be. That is, the size/length field is initially just before the nominal start of the struct, and while iterating through it, va_arg stores updated values into it.

That gives the length of the underling buffer in a fashion which still works after you've lost track of whether the start of the buffer was (a va_list passed to some function) while maintaining consistency with the ptx calling convention of a single void*. I'm expecting store/load forwarding to erase all the stack traffic in the common case. Passing a va_list to another function is free, same as it is today.


It has the drawback that va_copy has to work harder than it currently does, since the forward iterator now mutates behind it as it traverses, so va_copy has to memcpy the underlying buffer. That makes this a good idea if va_copy is rare and dubious if it is common.

I suspect there is a way to use a single void* without mutating the buffer behind it, the complexity moving into va_copy is a bit of a shame.

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyEVk1v4zYQ_TXyZbCGLH_FBx82WaRITwu0PS9G5EjimiIFkpKs_vpiKFqxvUULBI4lk_Px-N4boveqNkTnbP-aFcXv1rw15AO5SpGWWVFkxVtWFD-bviR34Of9txX2obHu_LR4VVo5nX_7_hdoVQoYba8laHUhCBakhdAoU_v5jbDdBKEhGNAplEoAurpvyQTPqzunTKgAhbM-vuCljfUB0EiQhBpGFRp-3fKHozX82SgPyoMj1HoCQj-BquJOugYyAez85IPrRegdgSRjA0koJ0AY8IdWPnCIi7GjiaksBx-VJxjITSBVVSnR65DSjUprGK27APmOhIqZR9IarAEzhO4KI1cHKsatNIaseIuRW5ygJECzdM59Xog6XswrOQa2su56yIoX9GC7znqSvE40aGplavC2pV8bYwitMoGcz4rTOsu_ZfnX-XOByfZ1o7lxSUwBYCiA9xhJEirrINvl6dwBPYxOBc449-OhtY6gI9eiicU3aEAZ8BrF5SHjW2OVIJ9t0_OXBWr00AUHWfEKXv3N2QFTF_-xlP_frYTbUi6QZiBSMP7eG0lOT1x52VcVuV-XJ6j-d0ckQ7Z9f4STIIwLue_rwq5zFkXDYHnVdpriwfvgUNVNqKwb0ck1t4iuhtYO5GMBlXI-LFXxHk14-zEWAVFwgNqaOgaIehK2U-ShtKFZw0fIiiMXJKzxykcBRM2YQYj4U-8jcxC8MrWmh4Qf0OBAM7uk7cvgAUvbByh7ZxgZBE_CGglD3bnIFnVH2Ifz_4jgXGAk8E00hdrOpTynjtpQLUnAEJs1dA0woO4ppkhIsZ2Qo4ocGUE3QaH2FnxgVuLSi3UPZJjPk0tF1XqY1ciGtJAzfR7y9Bcf7ymZHV_nL8BiAUKnFbNieZvtX5mhZCRkx7eY_kcATSbbf7tbxpuv2fYVsu3bJ81F7xyZoKe5Ax_VdtvCB6EJpiVKdvyM-FTy_JkAm634DjO4RsgEatFrDAQTC0zd55eWPKNT9mGG1hHKmYKdo0HZ3kOaEW_MMkeze6vF4aLAYtQSxYVPbfbCKzMvulgZbRvZG3nTTbpZ8a7J1KFJNGfDMirM7vqz9wFKqvicI0Vsqwxq8AHdk8UvhTRKswWTw-hgoYnml0pNGEXmeOg7iTwSIuk4b7CgwpODYoBa3QSZSk2ZZ_P49I7ZESr0jbKGKxEN-HAbGx6wYppOts-K40CgecYFx3jZivGKap9buusvxR7Rx9Gw0KdDn6CNyq16I4KyJitOCYQWlQmoooQXYxDTMk2hC1emhU4LBjIc4MEnBqtkVnxdw0dWHFuga0ci4hoh5MOzGAcI21vE2wI59ASo9a0XJoRDnqY3bQrbttaAQE9r-M73kmgzt9aCBTTJ_FJbcaQ6ig7gsaXEYcU3BonTw6ElKwrQ4Hxs0uE485KP82ah8Vc7j_QGnYzg82D7N2l4xVKKjj03mzhmHRg7QtsHZAGU1Cgjo-nE-oLDgZxPMexz7pZakS5Hv0yiJJcWL5F8ygNCba0EJQn5tnOLxQMe3TxwZF9GtaoqoTMj_eTRvucbTJhvUxAjjzhxQTwnng8_EobnQWxyFtVCy6Xhm6iF5el3VWHiKcero67uikUoVUgsa7ClVNxKnrfytD3his6b4-bllOfbfLdqzqKqimovd6ftSe6Pp-1uU8pdgft99SI2m32-UuciL3b5ocg3h81LsVtX1e6wo_yYH_Ltdn_YZ7ucWlR6rfXQrq2rV8r7ns6nQ7EpVhpL0j5divk6m26-7szLv5R97bNdzsT0nwGCCprOf1woiOgH3NwjiSVp1ap45Zyh4qnGFzxOseqdPjchdPGqVLxnxXutQtOXa2FblpUebv--dM7-JHa491i1z4r3ufDhXPwTAAD__xQvFAA">