//===-- Instrumentor Runtime Helper Header -------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This header provides helper structures and functions for reading data // generated by the LLVM Instrumentor pass and passed to runtime functions. // //===----------------------------------------------------------------------===// #ifndef INSTRUMENTOR_RUNTIME_H #define INSTRUMENTOR_RUNTIME_H #ifdef __cplusplus extern "C" { #endif #include #include #ifdef __cplusplus } #endif /// Header for each value in a value pack. Value packs are used to pass function /// arguments and other variable-length data to the runtime. The format is: /// [ValueHeader][Padding][Value Data] /// where padding aligns the value data to 8-byte boundaries. typedef struct { uint32_t size; // Size of the value in bytes uint32_t type_id; // LLVM Type::TypeID of the value } ValuePackHeader; /// Iterator for reading values from a value pack. typedef struct { const char *current; // Current position in the pack uint64_t offset; // Byte offset from the start uint32_t count; // Number of elements in the pack uint32_t index; // Current element index } ValuePackIterator; /// Initialize a value pack iterator. /// \param iter The iterator to initialize /// \param pack_ptr Pointer to the start of the value pack /// \param num_elements Number of elements in the pack static inline void initValuePackIterator(ValuePackIterator *iter, const void *pack_ptr, uint32_t num_elements) { iter->current = (const char *)pack_ptr; iter->offset = 0; iter->count = num_elements; iter->index = 0; } /// Get the header for the current value. static inline ValuePackHeader getValuePackHeader(const ValuePackIterator *iter) { const ValuePackHeader *header = (const ValuePackHeader *)iter->current; return *header; } /// Get a pointer to the current value data. static inline const void *getValuePackData(const ValuePackIterator *iter) { // Skip header (8 bytes: size + type_id) const char *data_start = iter->current + sizeof(ValuePackHeader); // Calculate padding for 8-byte alignment ValuePackHeader header = getValuePackHeader(iter); uint32_t padding = (8 - (header.size % 8)) % 8; // Skip padding return data_start + padding; } /// Move to the next value in the pack. static inline void nextValuePack(ValuePackIterator *iter) { if (iter->index >= iter->count) { iter->current = NULL; return; } ValuePackHeader header = getValuePackHeader(iter); uint32_t padding = (8 - (header.size % 8)) % 8; uint64_t advance = sizeof(ValuePackHeader) + padding + header.size; iter->current += advance; iter->offset += advance; iter->index++; } /// Get the current offset in bytes from the start of the pack. static inline uint64_t getValuePackOffset(const ValuePackIterator *iter) { return iter->offset; } /// Extract a specific value from a value pack by index. /// /// \param pack_ptr Pointer to the start of the value pack /// \param num_elements Number of elements in the pack /// \param index Zero-based index of the value to extract /// \param header Output parameter for the value header (can be NULL) /// \return Pointer to the value data, or NULL if index is out of bounds static inline const void *getValuePackEntry(const void *pack_ptr, uint32_t num_elements, uint32_t index, ValuePackHeader *header) { if (!pack_ptr || index >= num_elements) return NULL; ValuePackIterator iter; initValuePackIterator(&iter, pack_ptr, num_elements); while (iter.current != NULL && iter.index < iter.count) { ValuePackHeader h = getValuePackHeader(&iter); if (iter.index == index) { if (header) *header = h; return getValuePackData(&iter); } nextValuePack(&iter); } return NULL; // Index out of bounds } /// LLVM Type IDs for interpreting value pack data. /// These correspond to llvm::Type::TypeID enum values. enum LLVMTypeID { HalfTyID = 0, ///< 16-bit floating point type BFloatTyID, ///< 16-bit floating point type (7-bit significand) FloatTyID, ///< 32-bit floating point type DoubleTyID, ///< 64-bit floating point type X86_FP80TyID, ///< 80-bit floating point type (X87) FP128TyID, ///< 128-bit floating point type (112-bit significand) PPC_FP128TyID, ///< 128-bit floating point type (two 64-bits, PowerPC) VoidTyID, ///< type with no size LabelTyID, ///< Labels MetadataTyID, ///< Metadata X86_AMXTyID, ///< AMX vectors (8192 bits, X86 specific) TokenTyID, ///< Tokens // Derived types... see DerivedTypes.h file. IntegerTyID, ///< Arbitrary bit width integers ByteTyID, ///< Arbitrary bit width bytes FunctionTyID, ///< Functions PointerTyID, ///< Pointers StructTyID, ///< Structures ArrayTyID, ///< Arrays FixedVectorTyID, ///< Fixed width SIMD vector type ScalableVectorTyID, ///< Scalable SIMD vector type TypedPointerTyID, ///< Typed pointer used by some GPU targets TargetExtTyID, ///< Target extension type }; /// Get the string name of an LLVM Type ID. static inline const char *getLLVMTypeIDName(uint32_t type_id) { switch (type_id) { case HalfTyID: return "half"; case BFloatTyID: return "bfloat"; case FloatTyID: return "float"; case DoubleTyID: return "double"; case X86_FP80TyID: return "x86_fp80"; case FP128TyID: return "fp128"; case PPC_FP128TyID: return "ppc_fp128"; case VoidTyID: return "void"; case LabelTyID: return "label"; case MetadataTyID: return "metadata"; case X86_AMXTyID: return "x86_amx"; case TokenTyID: return "token"; case IntegerTyID: return "integer"; case ByteTyID: return "integer"; case FunctionTyID: return "function"; case PointerTyID: return "pointer"; case StructTyID: return "struct"; case ArrayTyID: return "array"; case FixedVectorTyID: return "fixed_vector"; case ScalableVectorTyID: return "scalable_vector"; case TypedPointerTyID: return "typed_pointer"; case TargetExtTyID: return "target_ext"; default: return "unknown"; } } #ifdef __cplusplus // C++ overlays for range-based iteration and quality of life improvements /// Range wrapper for value packs enabling range-based for loops. /// Example: /// for (auto val : ValuePackRange(pack_ptr, num_elements)) { /// // val provides access to header and data /// } class ValuePackRange { public: struct ValueRef { ValuePackHeader header; const void *data; uint32_t type_id() const { return header.type_id; } uint32_t size() const { return header.size; } const char *type_name() const { return getLLVMTypeIDName(header.type_id); } template const T &as() const { return *static_cast(data); } template const T *ptr() const { return static_cast(data); } }; class iterator { public: iterator(const void *ptr, uint32_t num_elements, uint64_t max_offset) : max_offset_(max_offset) { initValuePackIterator(&iter_, ptr, num_elements); if (ptr && !is_valid_position()) iter_.current = nullptr; } ValueRef operator*() const { return ValueRef{getValuePackHeader(&iter_), getValuePackData(&iter_)}; } iterator &operator++() { nextValuePack(&iter_); if (!is_valid_position()) iter_.current = nullptr; return *this; } bool operator!=(const iterator &other) const { return iter_.current != other.iter_.current; } private: bool is_valid_position() const { if (!iter_.current) return false; if (iter_.index >= iter_.count) return false; if (max_offset_ > 0 && iter_.offset >= max_offset_) return false; return true; } ValuePackIterator iter_; uint64_t max_offset_; }; ValuePackRange(const void *ptr, uint32_t num_elements, uint64_t max_size = 0) : ptr_(ptr), num_elements_(num_elements), max_size_(max_size) {} iterator begin() const { return iterator(ptr_, num_elements_, max_size_); } iterator end() const { return iterator(nullptr, 0, 0); } private: const void *ptr_; uint32_t num_elements_; uint64_t max_size_; }; /// Template helper to extract a typed value from a value pack by index. template inline const T *getValueAs(const void *pack_ptr, uint32_t num_elements, uint32_t index) { return static_cast( getValuePackEntry(pack_ptr, num_elements, index, nullptr)); } #endif // __cplusplus #endif // INSTRUMENTOR_RUNTIME_H // Generated with runtime prefix: __instrumentor_