1 //===-- Holder Class for manipulating va_lists ------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
10 #define LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
12 #include "src/__support/common.h"
13 #include "src/__support/macros/config.h"
19 namespace LIBC_NAMESPACE_DECL
{
22 template <typename V
, typename A
>
23 LIBC_INLINE
constexpr V
align_up(V val
, A align
) {
24 return ((val
+ V(align
) - 1) / V(align
)) * V(align
);
31 LIBC_INLINE
ArgList(va_list vlist
) { va_copy(this->vlist
, vlist
); }
32 LIBC_INLINE
ArgList(ArgList
&other
) { va_copy(this->vlist
, other
.vlist
); }
33 LIBC_INLINE
~ArgList() { va_end(this->vlist
); }
35 LIBC_INLINE ArgList
&operator=(ArgList
&rhs
) {
36 va_copy(vlist
, rhs
.vlist
);
40 template <class T
> LIBC_INLINE T
next_var() { return va_arg(vlist
, T
); }
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.
47 size_t arg_counter
= 0;
50 LIBC_INLINE
MockArgList() = default;
51 LIBC_INLINE
MockArgList(va_list) { ; }
52 LIBC_INLINE
MockArgList(MockArgList
&other
) {
53 arg_counter
= other
.arg_counter
;
55 LIBC_INLINE
~MockArgList() = default;
57 LIBC_INLINE MockArgList
&operator=(MockArgList
&rhs
) {
58 arg_counter
= rhs
.arg_counter
;
62 template <class T
> LIBC_INLINE T
next_var() {
64 return T(arg_counter
);
67 size_t read_count() const { return arg_counter
; }
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;
76 LIBC_INLINE
DummyArgList() = default;
77 LIBC_INLINE
DummyArgList(va_list) { ; }
78 LIBC_INLINE
DummyArgList(DummyArgList
&other
) {
79 arg_counter
= other
.arg_counter
;
81 LIBC_INLINE
~DummyArgList() = default;
83 LIBC_INLINE DummyArgList
&operator=(DummyArgList
&rhs
) {
84 arg_counter
= rhs
.arg_counter
;
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
);
94 size_t read_count() const { return arg_counter
; }
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
{
104 LIBC_INLINE
StructArgList(void *ptr
, size_t size
)
105 : ptr(ptr
), end(reinterpret_cast<unsigned char *>(ptr
) + size
) {}
106 LIBC_INLINE
StructArgList(const StructArgList
&other
) {
110 LIBC_INLINE
StructArgList() = default;
111 LIBC_INLINE
~StructArgList() = default;
113 LIBC_INLINE StructArgList
&operator=(const StructArgList
&rhs
) {
118 LIBC_INLINE
void *get_ptr() const { return ptr
; }
120 template <class T
> LIBC_INLINE T
next_var() {
122 ptr
= reinterpret_cast<void *>(
123 align_up(reinterpret_cast<uintptr_t>(ptr
), alignof(T
)));
127 // Memcpy because pointer alignment may be illegal given a packed struct.
129 __builtin_memcpy(&val
, ptr
, sizeof(T
));
132 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(ptr
) + sizeof(T
));
137 } // namespace internal
138 } // namespace LIBC_NAMESPACE_DECL
140 #endif // LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H