| 1 | //===-- InstrumentorVariables.inc.in - instrumentor variables -*- 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 | // This file is configured by the build system to define a variable containing |
| 10 | // instrumentor runtime library source code for use by the instrumentor pass. |
| 11 | // |
| 12 | // The variant of this file not ending with .in has been autogenerated by the |
| 13 | // LLVM build. Do not edit! |
| 14 | // |
| 15 | //===----------------------------------------------------------------------===// |
| 16 | |
| 17 | constexpr char InstrumentorRuntimeHelper[] = |
| 18 | R"(//===-- Instrumentor Runtime Helper Header -------------------------------===// |
| 19 | // |
| 20 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 21 | // See https://llvm.org/LICENSE.txt for license information. |
| 22 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 23 | // |
| 24 | //===----------------------------------------------------------------------===// |
| 25 | // |
| 26 | // This header provides helper structures and functions for reading data |
| 27 | // generated by the LLVM Instrumentor pass and passed to runtime functions. |
| 28 | // |
| 29 | //===----------------------------------------------------------------------===// |
| 30 | |
| 31 | #ifndef INSTRUMENTOR_RUNTIME_H |
| 32 | #define INSTRUMENTOR_RUNTIME_H |
| 33 | |
| 34 | #ifdef __cplusplus |
| 35 | extern "C" { |
| 36 | #endif |
| 37 | |
| 38 | #include <stdint.h> |
| 39 | #include <string.h> |
| 40 | |
| 41 | #ifdef __cplusplus |
| 42 | } |
| 43 | #endif |
| 44 | |
| 45 | /// Header for each value in a value pack. Value packs are used to pass function |
| 46 | /// arguments and other variable-length data to the runtime. The format is: |
| 47 | /// [ValueHeader][Padding][Value Data] |
| 48 | /// where padding aligns the value data to 8-byte boundaries. |
| 49 | typedef struct { |
| 50 | uint32_t size; // Size of the value in bytes |
| 51 | uint32_t type_id; // LLVM Type::TypeID of the value |
| 52 | } ValuePackHeader; |
| 53 | |
| 54 | /// Iterator for reading values from a value pack. |
| 55 | typedef struct { |
| 56 | const char *current; // Current position in the pack |
| 57 | uint64_t offset; // Byte offset from the start |
| 58 | uint32_t count; // Number of elements in the pack |
| 59 | uint32_t index; // Current element index |
| 60 | } ValuePackIterator; |
| 61 | |
| 62 | /// Initialize a value pack iterator. |
| 63 | /// \param iter The iterator to initialize |
| 64 | /// \param pack_ptr Pointer to the start of the value pack |
| 65 | /// \param num_elements Number of elements in the pack |
| 66 | static inline void initValuePackIterator(ValuePackIterator *iter, |
| 67 | const void *pack_ptr, |
| 68 | uint32_t num_elements) { |
| 69 | iter->current = (const char *)pack_ptr; |
| 70 | iter->offset = 0; |
| 71 | iter->count = num_elements; |
| 72 | iter->index = 0; |
| 73 | } |
| 74 | |
| 75 | /// Get the header for the current value. |
| 76 | static inline ValuePackHeader |
| 77 | getValuePackHeader(const ValuePackIterator *iter) { |
| 78 | const ValuePackHeader *header = (const ValuePackHeader *)iter->current; |
| 79 | return *header; |
| 80 | } |
| 81 | |
| 82 | /// Get a pointer to the current value data. |
| 83 | static inline const void *getValuePackData(const ValuePackIterator *iter) { |
| 84 | // Skip header (8 bytes: size + type_id) |
| 85 | const char *data_start = iter->current + sizeof(ValuePackHeader); |
| 86 | // Calculate padding for 8-byte alignment |
| 87 | ValuePackHeader header = getValuePackHeader(iter); |
| 88 | uint32_t padding = (8 - (header.size % 8)) % 8; |
| 89 | // Skip padding |
| 90 | return data_start + padding; |
| 91 | } |
| 92 | |
| 93 | /// Move to the next value in the pack. |
| 94 | static inline void nextValuePack(ValuePackIterator *iter) { |
| 95 | if (iter->index >= iter->count) { |
| 96 | iter->current = NULL; |
| 97 | return; |
| 98 | } |
| 99 | ValuePackHeader header = getValuePackHeader(iter); |
| 100 | uint32_t padding = (8 - (header.size % 8)) % 8; |
| 101 | uint64_t advance = sizeof(ValuePackHeader) + padding + header.size; |
| 102 | iter->current += advance; |
| 103 | iter->offset += advance; |
| 104 | iter->index++; |
| 105 | } |
| 106 | |
| 107 | /// Get the current offset in bytes from the start of the pack. |
| 108 | static inline uint64_t getValuePackOffset(const ValuePackIterator *iter) { |
| 109 | return iter->offset; |
| 110 | } |
| 111 | |
| 112 | /// Extract a specific value from a value pack by index. |
| 113 | /// |
| 114 | /// \param pack_ptr Pointer to the start of the value pack |
| 115 | /// \param num_elements Number of elements in the pack |
| 116 | /// \param index Zero-based index of the value to extract |
| 117 | /// \param header Output parameter for the value header (can be NULL) |
| 118 | /// \return Pointer to the value data, or NULL if index is out of bounds |
| 119 | static inline const void *getValuePackEntry(const void *pack_ptr, |
| 120 | uint32_t num_elements, |
| 121 | uint32_t index, |
| 122 | ValuePackHeader *header) { |
| 123 | if (!pack_ptr || index >= num_elements) |
| 124 | return NULL; |
| 125 | |
| 126 | ValuePackIterator iter; |
| 127 | initValuePackIterator(&iter, pack_ptr, num_elements); |
| 128 | |
| 129 | while (iter.current != NULL && iter.index < iter.count) { |
| 130 | ValuePackHeader h = getValuePackHeader(&iter); |
| 131 | if (iter.index == index) { |
| 132 | if (header) |
| 133 | *header = h; |
| 134 | return getValuePackData(&iter); |
| 135 | } |
| 136 | nextValuePack(&iter); |
| 137 | } |
| 138 | |
| 139 | return NULL; // Index out of bounds |
| 140 | } |
| 141 | |
| 142 | /// LLVM Type IDs for interpreting value pack data. |
| 143 | /// These correspond to llvm::Type::TypeID enum values. |
| 144 | enum LLVMTypeID { |
| 145 | HalfTyID = 0, ///< 16-bit floating point type |
| 146 | BFloatTyID, ///< 16-bit floating point type (7-bit significand) |
| 147 | FloatTyID, ///< 32-bit floating point type |
| 148 | DoubleTyID, ///< 64-bit floating point type |
| 149 | X86_FP80TyID, ///< 80-bit floating point type (X87) |
| 150 | FP128TyID, ///< 128-bit floating point type (112-bit significand) |
| 151 | PPC_FP128TyID, ///< 128-bit floating point type (two 64-bits, PowerPC) |
| 152 | VoidTyID, ///< type with no size |
| 153 | LabelTyID, ///< Labels |
| 154 | MetadataTyID, ///< Metadata |
| 155 | X86_AMXTyID, ///< AMX vectors (8192 bits, X86 specific) |
| 156 | TokenTyID, ///< Tokens |
| 157 | // Derived types... see DerivedTypes.h file. |
| 158 | IntegerTyID, ///< Arbitrary bit width integers |
| 159 | ByteTyID, ///< Arbitrary bit width bytes |
| 160 | FunctionTyID, ///< Functions |
| 161 | PointerTyID, ///< Pointers |
| 162 | StructTyID, ///< Structures |
| 163 | ArrayTyID, ///< Arrays |
| 164 | FixedVectorTyID, ///< Fixed width SIMD vector type |
| 165 | ScalableVectorTyID, ///< Scalable SIMD vector type |
| 166 | TypedPointerTyID, ///< Typed pointer used by some GPU targets |
| 167 | TargetExtTyID, ///< Target extension type |
| 168 | }; |
| 169 | |
| 170 | /// Get the string name of an LLVM Type ID. |
| 171 | static inline const char *getLLVMTypeIDName(int32_t type_id) { |
| 172 | switch (type_id) { |
| 173 | case -1: |
| 174 | return "none"; |
| 175 | case HalfTyID: |
| 176 | return "half"; |
| 177 | case BFloatTyID: |
| 178 | return "bfloat"; |
| 179 | case FloatTyID: |
| 180 | return "float"; |
| 181 | case DoubleTyID: |
| 182 | return "double"; |
| 183 | case X86_FP80TyID: |
| 184 | return "x86_fp80"; |
| 185 | case FP128TyID: |
| 186 | return "fp128"; |
| 187 | case PPC_FP128TyID: |
| 188 | return "ppc_fp128"; |
| 189 | case VoidTyID: |
| 190 | return "void"; |
| 191 | case LabelTyID: |
| 192 | return "label"; |
| 193 | case MetadataTyID: |
| 194 | return "metadata"; |
| 195 | case X86_AMXTyID: |
| 196 | return "x86_amx"; |
| 197 | case TokenTyID: |
| 198 | return "token"; |
| 199 | case IntegerTyID: |
| 200 | return "integer"; |
| 201 | case ByteTyID: |
| 202 | return "integer"; |
| 203 | case FunctionTyID: |
| 204 | return "function"; |
| 205 | case PointerTyID: |
| 206 | return "pointer"; |
| 207 | case StructTyID: |
| 208 | return "struct"; |
| 209 | case ArrayTyID: |
| 210 | return "array"; |
| 211 | case FixedVectorTyID: |
| 212 | return "fixed_vector"; |
| 213 | case ScalableVectorTyID: |
| 214 | return "scalable_vector"; |
| 215 | case TypedPointerTyID: |
| 216 | return "typed_pointer"; |
| 217 | case TargetExtTyID: |
| 218 | return "target_ext"; |
| 219 | default: |
| 220 | return "unknown"; |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | #ifdef __cplusplus |
| 225 | |
| 226 | // C++ overlays for range-based iteration and quality of life improvements |
| 227 | |
| 228 | /// Range wrapper for value packs enabling range-based for loops. |
| 229 | /// Example: |
| 230 | /// for (auto val : ValuePackRange(pack_ptr, num_elements)) { |
| 231 | /// // val provides access to header and data |
| 232 | /// } |
| 233 | class ValuePackRange { |
| 234 | public: |
| 235 | struct ValueRef { |
| 236 | ValuePackHeader header; |
| 237 | const void *data; |
| 238 | |
| 239 | uint32_t type_id() const { return header.type_id; } |
| 240 | uint32_t size() const { return header.size; } |
| 241 | const char *type_name() const { return getLLVMTypeIDName(header.type_id); } |
| 242 | |
| 243 | template <typename T> const T &as() const { |
| 244 | return *static_cast<const T *>(data); |
| 245 | } |
| 246 | template <typename T> const T *ptr() const { |
| 247 | return static_cast<const T *>(data); |
| 248 | } |
| 249 | }; |
| 250 | |
| 251 | class iterator { |
| 252 | public: |
| 253 | iterator(const void *ptr, uint32_t num_elements, uint64_t max_offset) |
| 254 | : max_offset_(max_offset) { |
| 255 | initValuePackIterator(&iter_, ptr, num_elements); |
| 256 | if (ptr && !is_valid_position()) |
| 257 | iter_.current = nullptr; |
| 258 | } |
| 259 | |
| 260 | ValueRef operator*() const { |
| 261 | return ValueRef{getValuePackHeader(&iter_), getValuePackData(&iter_)}; |
| 262 | } |
| 263 | |
| 264 | iterator &operator++() { |
| 265 | nextValuePack(&iter_); |
| 266 | if (!is_valid_position()) |
| 267 | iter_.current = nullptr; |
| 268 | return *this; |
| 269 | } |
| 270 | |
| 271 | bool operator!=(const iterator &other) const { |
| 272 | return iter_.current != other.iter_.current; |
| 273 | } |
| 274 | |
| 275 | private: |
| 276 | bool is_valid_position() const { |
| 277 | if (!iter_.current) |
| 278 | return false; |
| 279 | if (iter_.index >= iter_.count) |
| 280 | return false; |
| 281 | if (max_offset_ > 0 && iter_.offset >= max_offset_) |
| 282 | return false; |
| 283 | return true; |
| 284 | } |
| 285 | |
| 286 | ValuePackIterator iter_; |
| 287 | uint64_t max_offset_; |
| 288 | }; |
| 289 | |
| 290 | ValuePackRange(const void *ptr, uint32_t num_elements, uint64_t max_size = 0) |
| 291 | : ptr_(ptr), num_elements_(num_elements), max_size_(max_size) {} |
| 292 | |
| 293 | iterator begin() const { return iterator(ptr_, num_elements_, max_size_); } |
| 294 | iterator end() const { return iterator(nullptr, 0, 0); } |
| 295 | |
| 296 | private: |
| 297 | const void *ptr_; |
| 298 | uint32_t num_elements_; |
| 299 | uint64_t max_size_; |
| 300 | }; |
| 301 | |
| 302 | /// Template helper to extract a typed value from a value pack by index. |
| 303 | template <typename T> |
| 304 | inline const T *getValueAs(const void *pack_ptr, uint32_t num_elements, |
| 305 | uint32_t index) { |
| 306 | return static_cast<const T *>( |
| 307 | getValuePackEntry(pack_ptr, num_elements, index, nullptr)); |
| 308 | } |
| 309 | |
| 310 | #endif // __cplusplus |
| 311 | |
| 312 | /// Bitmask flags for different instrumentation opportunities. |
| 313 | |
| 314 | /// NumericIO flag bitmask values. |
| 315 | typedef enum NumericFlags { |
| 316 | NUMERIC_FLAG_NONE = 0, |
| 317 | NUMERIC_FLAG_NO_SIGNED_WRAP = 1 << 0, |
| 318 | NUMERIC_FLAG_NO_UNSIGNED_WRAP = 1 << 1, |
| 319 | NUMERIC_FLAG_HAS_NO_NANS = 1 << 2, |
| 320 | NUMERIC_FLAG_HAS_NO_INFS = 1 << 3, |
| 321 | NUMERIC_FLAG_HAS_NO_SIGNED_ZEROS = 1 << 4, |
| 322 | NUMERIC_FLAG_IS_DISJOINT = 1 << 5, |
| 323 | NUMERIC_FLAG_IS_EXACT = 1 << 6, |
| 324 | } NumericFlags; |
| 325 | |
| 326 | /// CompareIO flag bitmask values. |
| 327 | typedef enum CompareFlags { |
| 328 | COMPARE_FLAG_NONE = 0, |
| 329 | COMPARE_FLAG_SAMESIGN = 1 << 0, |
| 330 | COMPARE_FLAG_HAS_NO_NANS = 1 << 1, |
| 331 | COMPARE_FLAG_HAS_NO_INFS = 1 << 2, |
| 332 | COMPARE_FLAG_HAS_NO_SIGNED_ZEROS = 1 << 3, |
| 333 | } CompareFlags; |
| 334 | |
| 335 | #endif // INSTRUMENTOR_RUNTIME_H |
| 336 | )" ; |
| 337 | |