xref: /aosp_15_r20/external/llvm-libc/src/__support/arg_list.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- Holder Class for manipulating va_lists ------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
10 #define LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
11 
12 #include "src/__support/common.h"
13 #include "src/__support/macros/config.h"
14 
15 #include <stdarg.h>
16 #include <stddef.h>
17 #include <stdint.h>
18 
19 namespace LIBC_NAMESPACE_DECL {
20 namespace internal {
21 
22 template <typename V, typename A>
align_up(V val,A align)23 LIBC_INLINE constexpr V align_up(V val, A align) {
24   return ((val + V(align) - 1) / V(align)) * V(align);
25 }
26 
27 class ArgList {
28   va_list vlist;
29 
30 public:
ArgList(va_list vlist)31   LIBC_INLINE ArgList(va_list vlist) { va_copy(this->vlist, vlist); }
ArgList(ArgList & other)32   LIBC_INLINE ArgList(ArgList &other) { va_copy(this->vlist, other.vlist); }
~ArgList()33   LIBC_INLINE ~ArgList() { va_end(this->vlist); }
34 
35   LIBC_INLINE ArgList &operator=(ArgList &rhs) {
36     va_copy(vlist, rhs.vlist);
37     return *this;
38   }
39 
next_var()40   template <class T> LIBC_INLINE T next_var() { return va_arg(vlist, T); }
41 };
42 
43 // Used for testing things that use an ArgList when it's impossible to know what
44 // the arguments should be ahead of time. An example of this would be fuzzing,
45 // since a function passed a random input could request unpredictable arguments.
46 class MockArgList {
47   size_t arg_counter = 0;
48 
49 public:
50   LIBC_INLINE MockArgList() = default;
MockArgList(va_list)51   LIBC_INLINE MockArgList(va_list) { ; }
MockArgList(MockArgList & other)52   LIBC_INLINE MockArgList(MockArgList &other) {
53     arg_counter = other.arg_counter;
54   }
55   LIBC_INLINE ~MockArgList() = default;
56 
57   LIBC_INLINE MockArgList &operator=(MockArgList &rhs) {
58     arg_counter = rhs.arg_counter;
59     return *this;
60   }
61 
next_var()62   template <class T> LIBC_INLINE T next_var() {
63     arg_counter++;
64     return T(arg_counter);
65   }
66 
read_count()67   size_t read_count() const { return arg_counter; }
68 };
69 
70 // Used by the GPU implementation to parse how many bytes need to be read from
71 // the variadic argument buffer.
72 template <bool packed> class DummyArgList {
73   size_t arg_counter = 0;
74 
75 public:
76   LIBC_INLINE DummyArgList() = default;
DummyArgList(va_list)77   LIBC_INLINE DummyArgList(va_list) { ; }
DummyArgList(DummyArgList & other)78   LIBC_INLINE DummyArgList(DummyArgList &other) {
79     arg_counter = other.arg_counter;
80   }
81   LIBC_INLINE ~DummyArgList() = default;
82 
83   LIBC_INLINE DummyArgList &operator=(DummyArgList &rhs) {
84     arg_counter = rhs.arg_counter;
85     return *this;
86   }
87 
next_var()88   template <class T> LIBC_INLINE T next_var() {
89     arg_counter = packed ? arg_counter + sizeof(T)
90                          : align_up(arg_counter, alignof(T)) + sizeof(T);
91     return T(arg_counter);
92   }
93 
read_count()94   size_t read_count() const { return arg_counter; }
95 };
96 
97 // Used for the GPU implementation of `printf`. This models a variadic list as a
98 // simple array of pointers that are built manually by the implementation.
99 template <bool packed> class StructArgList {
100   void *ptr;
101   void *end;
102 
103 public:
StructArgList(void * ptr,size_t size)104   LIBC_INLINE StructArgList(void *ptr, size_t size)
105       : ptr(ptr), end(reinterpret_cast<unsigned char *>(ptr) + size) {}
StructArgList(const StructArgList & other)106   LIBC_INLINE StructArgList(const StructArgList &other) {
107     ptr = other.ptr;
108     end = other.end;
109   }
110   LIBC_INLINE StructArgList() = default;
111   LIBC_INLINE ~StructArgList() = default;
112 
113   LIBC_INLINE StructArgList &operator=(const StructArgList &rhs) {
114     ptr = rhs.ptr;
115     return *this;
116   }
117 
get_ptr()118   LIBC_INLINE void *get_ptr() const { return ptr; }
119 
next_var()120   template <class T> LIBC_INLINE T next_var() {
121     if (!packed)
122       ptr = reinterpret_cast<void *>(
123           align_up(reinterpret_cast<uintptr_t>(ptr), alignof(T)));
124     if (ptr >= end)
125       return T(-1);
126 
127     // Memcpy because pointer alignment may be illegal given a packed struct.
128     T val;
129     __builtin_memcpy(&val, ptr, sizeof(T));
130 
131     ptr =
132         reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(ptr) + sizeof(T));
133     return val;
134   }
135 };
136 
137 } // namespace internal
138 } // namespace LIBC_NAMESPACE_DECL
139 
140 #endif // LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
141