xref: /llvm-project/libc/src/__support/arg_list.h (revision 40effc7af5679b7d54d3176a5eef2cdee1962ecd)
15561ab34SMichael Jones //===-- Holder Class for manipulating va_lists ------------------*- C++ -*-===//
25561ab34SMichael Jones //
35561ab34SMichael Jones // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45561ab34SMichael Jones // See https://llvm.org/LICENSE.txt for license information.
55561ab34SMichael Jones // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65561ab34SMichael Jones //
75561ab34SMichael Jones //===----------------------------------------------------------------------===//
85561ab34SMichael Jones 
9270547f3SGuillaume Chatelet #ifndef LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
10270547f3SGuillaume Chatelet #define LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
115561ab34SMichael Jones 
12494734b0SSiva Chandra Reddy #include "src/__support/common.h"
135ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
14494734b0SSiva Chandra Reddy 
155561ab34SMichael Jones #include <stdarg.h>
1647fb6d1cSMichael Jones #include <stddef.h>
177327014bSJoseph Huber #include <stdint.h>
185561ab34SMichael Jones 
195ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
205561ab34SMichael Jones namespace internal {
215561ab34SMichael Jones 
22*40effc7aSJoseph Huber template <typename V, typename A>
23*40effc7aSJoseph Huber LIBC_INLINE constexpr V align_up(V val, A align) {
24*40effc7aSJoseph Huber   return ((val + V(align) - 1) / V(align)) * V(align);
25*40effc7aSJoseph Huber }
26*40effc7aSJoseph Huber 
275561ab34SMichael Jones class ArgList {
285561ab34SMichael Jones   va_list vlist;
295561ab34SMichael Jones 
305561ab34SMichael Jones public:
31494734b0SSiva Chandra Reddy   LIBC_INLINE ArgList(va_list vlist) { va_copy(this->vlist, vlist); }
32494734b0SSiva Chandra Reddy   LIBC_INLINE ArgList(ArgList &other) { va_copy(this->vlist, other.vlist); }
33494734b0SSiva Chandra Reddy   LIBC_INLINE ~ArgList() { va_end(this->vlist); }
345561ab34SMichael Jones 
35494734b0SSiva Chandra Reddy   LIBC_INLINE ArgList &operator=(ArgList &rhs) {
36a439c4afSSiva Chandra Reddy     va_copy(vlist, rhs.vlist);
37a439c4afSSiva Chandra Reddy     return *this;
38a439c4afSSiva Chandra Reddy   }
39a439c4afSSiva Chandra Reddy 
40494734b0SSiva Chandra Reddy   template <class T> LIBC_INLINE T next_var() { return va_arg(vlist, T); }
415561ab34SMichael Jones };
425561ab34SMichael Jones 
4347fb6d1cSMichael Jones // Used for testing things that use an ArgList when it's impossible to know what
4447fb6d1cSMichael Jones // the arguments should be ahead of time. An example of this would be fuzzing,
4547fb6d1cSMichael Jones // since a function passed a random input could request unpredictable arguments.
4647fb6d1cSMichael Jones class MockArgList {
4747fb6d1cSMichael Jones   size_t arg_counter = 0;
4847fb6d1cSMichael Jones 
4947fb6d1cSMichael Jones public:
5047fb6d1cSMichael Jones   LIBC_INLINE MockArgList() = default;
5147fb6d1cSMichael Jones   LIBC_INLINE MockArgList(va_list) { ; }
5247fb6d1cSMichael Jones   LIBC_INLINE MockArgList(MockArgList &other) {
5347fb6d1cSMichael Jones     arg_counter = other.arg_counter;
5447fb6d1cSMichael Jones   }
5547fb6d1cSMichael Jones   LIBC_INLINE ~MockArgList() = default;
5647fb6d1cSMichael Jones 
5747fb6d1cSMichael Jones   LIBC_INLINE MockArgList &operator=(MockArgList &rhs) {
5847fb6d1cSMichael Jones     arg_counter = rhs.arg_counter;
5947fb6d1cSMichael Jones     return *this;
6047fb6d1cSMichael Jones   }
6147fb6d1cSMichael Jones 
6247fb6d1cSMichael Jones   template <class T> LIBC_INLINE T next_var() {
63*40effc7aSJoseph Huber     arg_counter++;
64*40effc7aSJoseph Huber     return T(arg_counter);
65*40effc7aSJoseph Huber   }
66*40effc7aSJoseph Huber 
67*40effc7aSJoseph Huber   size_t read_count() const { return arg_counter; }
68*40effc7aSJoseph Huber };
69*40effc7aSJoseph Huber 
70*40effc7aSJoseph Huber // Used by the GPU implementation to parse how many bytes need to be read from
71*40effc7aSJoseph Huber // the variadic argument buffer.
72*40effc7aSJoseph Huber template <bool packed> class DummyArgList {
73*40effc7aSJoseph Huber   size_t arg_counter = 0;
74*40effc7aSJoseph Huber 
75*40effc7aSJoseph Huber public:
76*40effc7aSJoseph Huber   LIBC_INLINE DummyArgList() = default;
77*40effc7aSJoseph Huber   LIBC_INLINE DummyArgList(va_list) { ; }
78*40effc7aSJoseph Huber   LIBC_INLINE DummyArgList(DummyArgList &other) {
79*40effc7aSJoseph Huber     arg_counter = other.arg_counter;
80*40effc7aSJoseph Huber   }
81*40effc7aSJoseph Huber   LIBC_INLINE ~DummyArgList() = default;
82*40effc7aSJoseph Huber 
83*40effc7aSJoseph Huber   LIBC_INLINE DummyArgList &operator=(DummyArgList &rhs) {
84*40effc7aSJoseph Huber     arg_counter = rhs.arg_counter;
85*40effc7aSJoseph Huber     return *this;
86*40effc7aSJoseph Huber   }
87*40effc7aSJoseph Huber 
88*40effc7aSJoseph Huber   template <class T> LIBC_INLINE T next_var() {
89*40effc7aSJoseph Huber     arg_counter = packed ? arg_counter + sizeof(T)
90*40effc7aSJoseph Huber                          : align_up(arg_counter, alignof(T)) + sizeof(T);
9147fb6d1cSMichael Jones     return T(arg_counter);
9247fb6d1cSMichael Jones   }
9347fb6d1cSMichael Jones 
9447fb6d1cSMichael Jones   size_t read_count() const { return arg_counter; }
9547fb6d1cSMichael Jones };
9647fb6d1cSMichael Jones 
977327014bSJoseph Huber // Used for the GPU implementation of `printf`. This models a variadic list as a
987327014bSJoseph Huber // simple array of pointers that are built manually by the implementation.
99*40effc7aSJoseph Huber template <bool packed> class StructArgList {
1007327014bSJoseph Huber   void *ptr;
1017327014bSJoseph Huber   void *end;
1027327014bSJoseph Huber 
1037327014bSJoseph Huber public:
1047327014bSJoseph Huber   LIBC_INLINE StructArgList(void *ptr, size_t size)
1057327014bSJoseph Huber       : ptr(ptr), end(reinterpret_cast<unsigned char *>(ptr) + size) {}
1067327014bSJoseph Huber   LIBC_INLINE StructArgList(const StructArgList &other) {
1077327014bSJoseph Huber     ptr = other.ptr;
1087327014bSJoseph Huber     end = other.end;
1097327014bSJoseph Huber   }
1107327014bSJoseph Huber   LIBC_INLINE StructArgList() = default;
1117327014bSJoseph Huber   LIBC_INLINE ~StructArgList() = default;
1127327014bSJoseph Huber 
1137327014bSJoseph Huber   LIBC_INLINE StructArgList &operator=(const StructArgList &rhs) {
1147327014bSJoseph Huber     ptr = rhs.ptr;
1157327014bSJoseph Huber     return *this;
1167327014bSJoseph Huber   }
1177327014bSJoseph Huber 
1187327014bSJoseph Huber   LIBC_INLINE void *get_ptr() const { return ptr; }
1197327014bSJoseph Huber 
1207327014bSJoseph Huber   template <class T> LIBC_INLINE T next_var() {
121*40effc7aSJoseph Huber     if (!packed)
1227327014bSJoseph Huber       ptr = reinterpret_cast<void *>(
123*40effc7aSJoseph Huber           align_up(reinterpret_cast<uintptr_t>(ptr), alignof(T)));
1247327014bSJoseph Huber     if (ptr >= end)
1257327014bSJoseph Huber       return T(-1);
1267327014bSJoseph Huber 
127*40effc7aSJoseph Huber     // Memcpy because pointer alignment may be illegal given a packed struct.
128*40effc7aSJoseph Huber     T val;
129*40effc7aSJoseph Huber     __builtin_memcpy(&val, ptr, sizeof(T));
130*40effc7aSJoseph Huber 
131*40effc7aSJoseph Huber     ptr =
132*40effc7aSJoseph Huber         reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(ptr) + sizeof(T));
1337327014bSJoseph Huber     return val;
1347327014bSJoseph Huber   }
1357327014bSJoseph Huber };
1367327014bSJoseph Huber 
1375561ab34SMichael Jones } // namespace internal
1385ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
1395561ab34SMichael Jones 
140270547f3SGuillaume Chatelet #endif // LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
141