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