[llvm] [Instrumentor] Move instrumentor stub library into its own header file (PR #199329)
Ethan Luis McDonough via llvm-commits
llvm-commits at lists.llvm.org
Sat May 23 01:12:32 PDT 2026
https://github.com/EthanLuisMcDonough created https://github.com/llvm/llvm-project/pull/199329
This patch depends on #198366. It moves the instrumentor runtime helper header into its own file and makes it accessible as a string value to the instrumentor pass.
>From c679d998762cdf2db2a185c7fea0a0f0eaa3354c Mon Sep 17 00:00:00 2001
From: Johannes Doerfert <jdoerfert.llvm at gmail.com>
Date: Sun, 17 May 2026 21:27:58 -0700
Subject: [PATCH] [Instrumentor] Improve stub printer (for C/C++ and value
packs)
The stub printer now emits a helper header to deal with value packs (in
C and C++). We also make the files C/C++ compatible and use the proper
format strings for int32_t and int64_t.
---
.../llvm/Transforms/IPO/Instrumentor.h | 1 +
.../Transforms/IPO/InstrumentorStubPrinter.h | 5 +
llvm/lib/Transforms/IPO/Instrumentor.cpp | 13 +-
.../IPO/InstrumentorStubPrinter.cpp | 415 +++++++++++++++++-
.../Instrumentation/Instrumentor/default_rt | 37 --
.../Instrumentation/Instrumentor/default_rt.c | 124 ++++++
.../Instrumentation/Instrumentor/default_rt.h | 264 +++++++++++
.../Instrumentor/generate_rt.ll | 3 +-
.../Instrumentor/lit.local.cfg | 1 +
.../Instrumentor/rt_config.json | 192 +++++++-
10 files changed, 1004 insertions(+), 51 deletions(-)
delete mode 100644 llvm/test/Instrumentation/Instrumentor/default_rt
create mode 100644 llvm/test/Instrumentation/Instrumentor/default_rt.c
create mode 100644 llvm/test/Instrumentation/Instrumentor/default_rt.h
create mode 100644 llvm/test/Instrumentation/Instrumentor/lit.local.cfg
diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
index 5da1a427b242f..60078cbb3f812 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -64,6 +64,7 @@ struct IRTArg {
REPLACABLE_CUSTOM = 1 << 2,
POTENTIALLY_INDIRECT = 1 << 3,
INDIRECT_HAS_SIZE = 1 << 4,
+ VALUE_PACK = 1 << 5,
LAST,
};
diff --git a/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h b/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h
index 6e1e24d5fef9e..18bb2dc1ff111 100644
--- a/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h
+++ b/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h
@@ -26,6 +26,11 @@ namespace instrumentor {
void printRuntimeStub(const InstrumentationConfig &IConf,
StringRef StubRuntimeName, LLVMContext &Ctx);
+/// Print the runtime header file that provides helper structures and functions
+/// for reading data generated by the Instrumentor pass.
+void printRuntimeHeader(const InstrumentationConfig &IConf,
+ StringRef HeaderFileName, LLVMContext &Ctx);
+
} // end namespace instrumentor
} // end namespace llvm
diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp
index 68f4bb6dae7c9..fc5da00e903ef 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -835,12 +835,13 @@ void FunctionIO::init(InstrumentationConfig &IConf,
"Number of function arguments (without varargs).", IRTArg::NONE,
std::bind(&FunctionIO::getNumArguments, this, _1, _2, _3, _4)));
if (Config.has(PassArguments))
- IRTArgs.push_back(
- IRTArg(IIRB.PtrTy, "arguments", "Description of the arguments.",
- IsPRE && Config.has(ReplaceArguments) ? IRTArg::REPLACABLE_CUSTOM
- : IRTArg::NONE,
- std::bind(&FunctionIO::getArguments, this, _1, _2, _3, _4),
- std::bind(&FunctionIO::setArguments, this, _1, _2, _3, _4)));
+ IRTArgs.push_back(IRTArg(
+ IIRB.PtrTy, "arguments", "Description of the arguments.",
+ (IsPRE && Config.has(ReplaceArguments) ? IRTArg::REPLACABLE_CUSTOM
+ : IRTArg::NONE) |
+ IRTArg::VALUE_PACK,
+ std::bind(&FunctionIO::getArguments, this, _1, _2, _3, _4),
+ std::bind(&FunctionIO::setArguments, this, _1, _2, _3, _4)));
if (Config.has(PassIsMain))
IRTArgs.push_back(IRTArg(IIRB.Int8Ty, "is_main",
"Flag to indicate it is the main function.",
diff --git a/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp b/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp
index 2e720e346c5ec..846ad85982e7f 100644
--- a/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp
+++ b/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
@@ -54,9 +55,9 @@ static std::string getPrintfFormatString(Type *Ty, unsigned Flags) {
if (Ty->isIntegerTy()) {
if (Ty->getIntegerBitWidth() > 32) {
assert(Ty->getIntegerBitWidth() == 64);
- return "%lli";
+ return "%\" PRId64 \"";
}
- return "%i";
+ return "%\" PRId32 \"";
}
if (Ty->isPointerTy())
return Flags & IRTArg::STRING ? "%s" : "%p";
@@ -95,6 +96,14 @@ std::pair<std::string, std::string> IRTCallDescription::createCBodies() const {
if (!isPotentiallyIndirect(IRArg))
IndirectReturnValue = IRArg.Name;
}
+
+ // Handle value pack arguments specially
+ if (IRArg.Flags & IRTArg::VALUE_PACK) {
+ DirectFormat += "[value pack at %p]";
+ IndirectFormat += "[value pack at %p]";
+ continue;
+ }
+
if (!isPotentiallyIndirect(IRArg)) {
AddToFormats(getPrintfFormatString(IRArg.Ty, IRArg.Flags));
} else {
@@ -103,7 +112,7 @@ std::pair<std::string, std::string> IRTCallDescription::createCBodies() const {
IndirectArg += "_ptr";
// Add the indirect argument size
if (!(IRArg.Flags & IRTArg::INDIRECT_HAS_SIZE)) {
- IndirectFormat += ", " + IRArg.Name.str() + "_size: %i";
+ IndirectFormat += ", " + IRArg.Name.str() + "_size: %\" PRId32 \"";
IndirectArg += ", " + IRArg.Name.str() + "_size";
}
}
@@ -111,6 +120,52 @@ std::pair<std::string, std::string> IRTCallDescription::createCBodies() const {
std::string DirectBody = DirectFormat + "\\n\"" + DirectArg + ");\n";
std::string IndirectBody = IndirectFormat + "\\n\"" + IndirectArg + ");\n";
+
+ // Add value pack element printing
+ for (size_t ArgIdx = 0; ArgIdx < IO.IRTArgs.size(); ++ArgIdx) {
+ auto &IRArg = IO.IRTArgs[ArgIdx];
+ if (!IRArg.Enabled || !(IRArg.Flags & IRTArg::VALUE_PACK))
+ continue;
+
+ // Find the count parameter - it should be the previous enabled argument
+ std::string CountParam;
+ for (int PrevIdx = ArgIdx - 1; PrevIdx >= 0; --PrevIdx) {
+ if (IO.IRTArgs[PrevIdx].Enabled &&
+ IO.IRTArgs[PrevIdx].Name.equals_insensitive(
+ ("num_" + IRArg.Name).str())) {
+ CountParam = IO.IRTArgs[PrevIdx].Name.str();
+ break;
+ }
+ }
+
+ // If no count parameter found, use 0 (will skip iteration)
+ if (CountParam.empty())
+ CountParam = "0 /* count not enabled! */";
+
+ auto AddToBodies = [&](Twine T) {
+ DirectBody += T.str();
+ IndirectBody += T.str();
+ };
+
+ // Direct version: iterate through the value pack at the pointer
+ AddToBodies(" ValuePackIterator iter_" + IRArg.Name.str() + ";\n");
+ AddToBodies(" initValuePackIterator(&iter_" + IRArg.Name.str() + ", " +
+ IRArg.Name.str() + ", " + CountParam + ");\n");
+ AddToBodies(" while (iter_" + IRArg.Name.str() + ".index < iter_" +
+ IRArg.Name.str() + ".count) {\n");
+ AddToBodies(" ValuePackHeader header_" + IRArg.Name.str() +
+ " = getValuePackHeader(&iter_" + IRArg.Name.str() + ");\n");
+ AddToBodies(" const void *data_" + IRArg.Name.str() +
+ " = getValuePackData(&iter_" + IRArg.Name.str() + ");\n");
+ AddToBodies(" printf(\" [%" PRIu32 "] type=%s size=%" PRIu32
+ " data=%p\\n\", iter_" +
+ IRArg.Name.str() + ".index, getLLVMTypeIDName(header_" +
+ IRArg.Name.str() + ".type_id), header_" + IRArg.Name.str() +
+ ".size, data_" + IRArg.Name.str() + ");\n");
+ AddToBodies(" nextValuePack(&iter_" + IRArg.Name.str() + ");\n");
+ AddToBodies(" }\n");
+ }
+
if (RetTy)
IndirectReturnValue = DirectReturnValue = "0";
if (!DirectReturnValue.empty())
@@ -171,6 +226,316 @@ IRTCallDescription::createCSignature(const InstrumentationConfig &IConf) const {
MakeSignature(IndirectRetTy, IndirectName, IndirectArgs)};
}
+void printRuntimeHeader(const InstrumentationConfig &IConf,
+ StringRef HeaderFileName, LLVMContext &Ctx) {
+ if (HeaderFileName.empty())
+ return;
+
+ std::error_code EC;
+ raw_fd_ostream OS(HeaderFileName, EC);
+ if (EC) {
+ Ctx.emitError(
+ Twine("failed to open instrumentor runtime header file for writing: ") +
+ EC.message());
+ return;
+ }
+
+ StringRef Prefix = IConf.getRTName();
+
+ OS << "//===-- Instrumentor Runtime Helper Header "
+ "-------------------------------===//\n";
+ OS << "//\n";
+ OS << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+ "Exceptions.\n";
+ OS << "// See https://llvm.org/LICENSE.txt for license information.\n";
+ OS << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n";
+ OS << "//\n";
+ OS << "//"
+ "===-------------------------------------------------------------------"
+ "---===//\n";
+ OS << "//\n";
+ OS << "// This header provides helper structures and functions for reading "
+ "data\n";
+ OS << "// generated by the LLVM Instrumentor pass and passed to runtime "
+ "functions.\n";
+ OS << "//\n";
+ OS << "// Generated with runtime prefix: " << Prefix << "\n";
+ OS << "//\n";
+ OS << "//"
+ "===-------------------------------------------------------------------"
+ "---===//\n\n";
+
+ OS << "#ifndef INSTRUMENTOR_RUNTIME_H\n";
+ OS << "#define INSTRUMENTOR_RUNTIME_H\n\n";
+
+ OS << "#ifdef __cplusplus\n";
+ OS << "extern \"C\" {\n";
+ OS << "#endif\n\n";
+
+ OS << "#include <stdint.h>\n";
+ OS << "#include <string.h>\n\n";
+
+ OS << "#ifdef __cplusplus\n";
+ OS << "}\n";
+ OS << "#endif\n\n";
+
+ // Value pack structures
+ OS << "/// Header for each value in a value pack.\n";
+ OS << "/// Value packs are used to pass function arguments and other "
+ "variable-length\n";
+ OS << "/// data to the runtime. The format is:\n";
+ OS << "/// [ValueHeader][Padding][Value Data]\n";
+ OS << "/// where padding aligns the value data to 8-byte boundaries.\n";
+ OS << "typedef struct {\n";
+ OS << " uint32_t size; // Size of the value in bytes\n";
+ OS << " uint32_t type_id; // LLVM Type::TypeID of the value\n";
+ OS << "} ValuePackHeader;\n\n";
+
+ // Value pack iterator
+ OS << "/// Iterator for reading values from a value pack.\n";
+ OS << "typedef struct {\n";
+ OS << " const char *current; // Current position in the pack\n";
+ OS << " uint64_t offset; // Byte offset from the start\n";
+ OS << " uint32_t count; // Number of elements in the pack\n";
+ OS << " uint32_t index; // Current element index\n";
+ OS << "} ValuePackIterator;\n\n";
+
+ OS << "/// Initialize a value pack iterator.\n";
+ OS << "/// \\param iter The iterator to initialize\n";
+ OS << "/// \\param pack_ptr Pointer to the start of the value pack\n";
+ OS << "/// \\param num_elements Number of elements in the pack\n";
+ OS << "static inline void initValuePackIterator(ValuePackIterator *iter, "
+ "const void *pack_ptr, uint32_t num_elements) {\n";
+ OS << " iter->current = (const char *)pack_ptr;\n";
+ OS << " iter->offset = 0;\n";
+ OS << " iter->count = num_elements;\n";
+ OS << " iter->index = 0;\n";
+ OS << "}\n\n";
+
+ OS << "/// Get the header for the current value.\n";
+ OS << "static inline ValuePackHeader getValuePackHeader(const "
+ "ValuePackIterator *iter) {\n";
+ OS << " const ValuePackHeader *header = (const ValuePackHeader "
+ "*)iter->current;\n";
+ OS << " return *header;\n";
+ OS << "}\n\n";
+
+ OS << "/// Get a pointer to the current value data.\n";
+ OS << "static inline const void *getValuePackData(const ValuePackIterator "
+ "*iter) {\n";
+ OS << " // Skip header (8 bytes: size + type_id)\n";
+ OS << " const char *data_start = iter->current + sizeof(ValuePackHeader);\n";
+ OS << " // Calculate padding for 8-byte alignment\n";
+ OS << " ValuePackHeader header = getValuePackHeader(iter);\n";
+ OS << " uint32_t padding = (8 - (header.size % 8)) % 8;\n";
+ OS << " // Skip padding\n";
+ OS << " return data_start + padding;\n";
+ OS << "}\n\n";
+
+ OS << "/// Move to the next value in the pack.\n";
+ OS << "static inline void nextValuePack(ValuePackIterator *iter) {\n";
+ OS << " if (iter->index >= iter->count) {\n";
+ OS << " iter->current = NULL;\n";
+ OS << " return;\n";
+ OS << " }\n";
+ OS << " ValuePackHeader header = getValuePackHeader(iter);\n";
+ OS << " uint32_t padding = (8 - (header.size % 8)) % 8;\n";
+ OS << " uint64_t advance = sizeof(ValuePackHeader) + padding + "
+ "header.size;\n";
+ OS << " iter->current += advance;\n";
+ OS << " iter->offset += advance;\n";
+ OS << " iter->index++;\n";
+ OS << "}\n\n";
+
+ OS << "/// Get the current offset in bytes from the start of the pack.\n";
+ OS << "static inline uint64_t getValuePackOffset(const ValuePackIterator "
+ "*iter) {\n";
+ OS << " return iter->offset;\n";
+ OS << "}\n\n";
+
+ OS << "/// Extract a specific value from a value pack by index.\n";
+ OS << "///\n";
+ OS << "/// \\param pack_ptr Pointer to the start of the value pack\n";
+ OS << "/// \\param num_elements Number of elements in the pack\n";
+ OS << "/// \\param index Zero-based index of the value to extract\n";
+ OS << "/// \\param header Output parameter for the value header (can be "
+ "NULL)\n";
+ OS << "/// \\return Pointer to the value data, or NULL if index is out of "
+ "bounds\n";
+ OS << "static inline const void *getValuePackEntry(const void *pack_ptr, "
+ "uint32_t num_elements,\n";
+ OS << " uint32_t index, "
+ "ValuePackHeader *header) {\n";
+ OS << " if (!pack_ptr || index >= num_elements)\n";
+ OS << " return NULL;\n\n";
+ OS << " ValuePackIterator iter;\n";
+ OS << " initValuePackIterator(&iter, pack_ptr, num_elements);\n\n";
+ OS << " while (iter.current != NULL && iter.index < iter.count) {\n";
+ OS << " ValuePackHeader h = getValuePackHeader(&iter);\n";
+ OS << " if (iter.index == index) {\n";
+ OS << " if (header)\n";
+ OS << " *header = h;\n";
+ OS << " return getValuePackData(&iter);\n";
+ OS << " }\n";
+ OS << " nextValuePack(&iter);\n";
+ OS << " }\n\n";
+ OS << " return NULL; // Index out of bounds\n";
+ OS << "}\n\n";
+
+ // LLVM Type IDs enum
+ OS << "/// LLVM Type IDs for interpreting value pack data.\n";
+ OS << "/// These correspond to llvm::Type::TypeID enum values.\n";
+ OS << "enum LLVMTypeID {\n";
+ OS << " HalfTyID = 0, ///< 16-bit floating point type\n";
+ OS << " BFloatTyID, ///< 16-bit floating point type (7-bit "
+ "significand)\n";
+ OS << " FloatTyID, ///< 32-bit floating point type\n";
+ OS << " DoubleTyID, ///< 64-bit floating point type\n";
+ OS << " X86_FP80TyID, ///< 80-bit floating point type (X87)\n";
+ OS << " FP128TyID, ///< 128-bit floating point type (112-bit "
+ "significand)\n";
+ OS << " PPC_FP128TyID, ///< 128-bit floating point type (two 64-bits, "
+ "PowerPC)\n";
+ OS << " VoidTyID, ///< type with no size\n";
+ OS << " LabelTyID, ///< Labels\n";
+ OS << " MetadataTyID, ///< Metadata\n";
+ OS << " X86_AMXTyID, ///< AMX vectors (8192 bits, X86 specific)\n";
+ OS << " TokenTyID, ///< Tokens\n";
+
+ OS << " // Derived types... see DerivedTypes.h file.\n";
+ OS << " IntegerTyID, ///< Arbitrary bit width integers\n";
+ OS << " ByteTyID, ///< Arbitrary bit width bytes\n";
+ OS << " FunctionTyID, ///< Functions\n";
+ OS << " PointerTyID, ///< Pointers\n";
+ OS << " StructTyID, ///< Structures\n";
+ OS << " ArrayTyID, ///< Arrays\n";
+ OS << " FixedVectorTyID, ///< Fixed width SIMD vector type\n";
+ OS << " ScalableVectorTyID, ///< Scalable SIMD vector type\n";
+ OS << " TypedPointerTyID, ///< Typed pointer used by some GPU targets\n";
+ OS << " TargetExtTyID, ///< Target extension type\n";
+ OS << "};\n\n";
+
+ // Type ID printer function
+ OS << "/// Get the string name of an LLVM Type ID.\n";
+ OS << "static inline const char *getLLVMTypeIDName(uint32_t type_id) {\n";
+ OS << " switch (type_id) {\n";
+ OS << " case HalfTyID: return \"half\";\n";
+ OS << " case BFloatTyID: return \"bfloat\";\n";
+ OS << " case FloatTyID: return \"float\";\n";
+ OS << " case DoubleTyID: return \"double\";\n";
+ OS << " case X86_FP80TyID: return \"x86_fp80\";\n";
+ OS << " case FP128TyID: return \"fp128\";\n";
+ OS << " case PPC_FP128TyID: return \"ppc_fp128\";\n";
+ OS << " case VoidTyID: return \"void\";\n";
+ OS << " case LabelTyID: return \"label\";\n";
+ OS << " case MetadataTyID: return \"metadata\";\n";
+ OS << " case X86_AMXTyID: return \"x86_amx\";\n";
+ OS << " case TokenTyID: return \"token\";\n";
+ OS << " case IntegerTyID: return \"integer\";\n";
+ OS << " case ByteTyID: return \"integer\";\n";
+ OS << " case FunctionTyID: return \"function\";\n";
+ OS << " case PointerTyID: return \"pointer\";\n";
+ OS << " case StructTyID: return \"struct\";\n";
+ OS << " case ArrayTyID: return \"array\";\n";
+ OS << " case FixedVectorTyID: return \"fixed_vector\";\n";
+ OS << " case ScalableVectorTyID: return \"scalable_vector\";\n";
+ OS << " case TypedPointerTyID: return \"typed_pointer\";\n";
+ OS << " case TargetExtTyID: return \"target_ext\";\n";
+ OS << " default: return \"unknown\";\n";
+ OS << " }\n";
+ OS << "}\n\n";
+
+ // C++ overlays section
+ OS << "#ifdef __cplusplus\n\n";
+
+ OS << "// C++ overlays for range-based iteration and quality of life "
+ "improvements\n\n";
+
+ // ValuePackRange class
+ OS << "/// Range wrapper for value packs enabling range-based for loops.\n";
+ OS << "/// Example:\n";
+ OS << "/// for (auto val : ValuePackRange(pack_ptr, num_elements)) {\n";
+ OS << "/// // val provides access to header and data\n";
+ OS << "/// }\n";
+ OS << "class ValuePackRange {\n";
+ OS << "public:\n";
+ OS << " struct ValueRef {\n";
+ OS << " ValuePackHeader header;\n";
+ OS << " const void *data;\n\n";
+ OS << " uint32_t type_id() const { return header.type_id; }\n";
+ OS << " uint32_t size() const { return header.size; }\n";
+ OS << " const char *type_name() const { return "
+ "getLLVMTypeIDName(header.type_id); }\n\n";
+ OS << " template <typename T> const T &as() const {\n";
+ OS << " return *static_cast<const T*>(data);\n";
+ OS << " }\n";
+ OS << " template <typename T> const T *ptr() const {\n";
+ OS << " return static_cast<const T*>(data);\n";
+ OS << " }\n";
+ OS << " };\n\n";
+
+ OS << " class iterator {\n";
+ OS << " public:\n";
+ OS << " iterator(const void *ptr, uint32_t num_elements, uint64_t "
+ "max_offset)\n";
+ OS << " : max_offset_(max_offset) {\n";
+ OS << " initValuePackIterator(&iter_, ptr, num_elements);\n";
+ OS << " if (ptr && !is_valid_position()) iter_.current = nullptr;\n";
+ OS << " }\n\n";
+ OS << " ValueRef operator*() const {\n";
+ OS << " return ValueRef{\n";
+ OS << " getValuePackHeader(&iter_),\n";
+ OS << " getValuePackData(&iter_)\n";
+ OS << " };\n";
+ OS << " }\n\n";
+ OS << " iterator &operator++() {\n";
+ OS << " nextValuePack(&iter_);\n";
+ OS << " if (!is_valid_position()) iter_.current = nullptr;\n";
+ OS << " return *this;\n";
+ OS << " }\n\n";
+ OS << " bool operator!=(const iterator &other) const {\n";
+ OS << " return iter_.current != other.iter_.current;\n";
+ OS << " }\n\n";
+ OS << " private:\n";
+ OS << " bool is_valid_position() const {\n";
+ OS << " if (!iter_.current) return false;\n";
+ OS << " if (iter_.index >= iter_.count) return false;\n";
+ OS << " if (max_offset_ > 0 && iter_.offset >= max_offset_) return "
+ "false;\n";
+ OS << " return true;\n";
+ OS << " }\n\n";
+ OS << " ValuePackIterator iter_;\n";
+ OS << " uint64_t max_offset_;\n";
+ OS << " };\n\n";
+
+ OS << " ValuePackRange(const void *ptr, uint32_t num_elements, uint64_t "
+ "max_size = 0)\n";
+ OS << " : ptr_(ptr), num_elements_(num_elements), max_size_(max_size) "
+ "{}\n\n";
+ OS << " iterator begin() const { return iterator(ptr_, num_elements_, "
+ "max_size_); }\n";
+ OS << " iterator end() const { return iterator(nullptr, 0, 0); }\n\n";
+ OS << "private:\n";
+ OS << " const void *ptr_;\n";
+ OS << " uint32_t num_elements_;\n";
+ OS << " uint64_t max_size_;\n";
+ OS << "};\n\n";
+
+ // Helper template functions
+ OS << "/// Template helper to extract a typed value from a value pack by "
+ "index.\n";
+ OS << "template <typename T>\n";
+ OS << "inline const T *getValueAs(const void *pack_ptr, uint32_t "
+ "num_elements, uint32_t index) {\n";
+ OS << " return static_cast<const T*>(getValuePackEntry(pack_ptr, "
+ "num_elements, index, nullptr));\n";
+ OS << "}\n\n";
+
+ OS << "#endif // __cplusplus\n\n";
+
+ OS << "#endif // INSTRUMENTOR_RUNTIME_H\n";
+}
+
void printRuntimeStub(const InstrumentationConfig &IConf,
StringRef StubRuntimeName, LLVMContext &Ctx) {
if (StubRuntimeName.empty())
@@ -185,9 +550,45 @@ void printRuntimeStub(const InstrumentationConfig &IConf,
return;
}
- OS << "// LLVM Instrumentor stub runtime\n\n";
+ // Generate the header file alongside the stub
+ StringRef Prefix = IConf.getRTName();
+ std::string HeaderFileName = StubRuntimeName.str();
+ size_t DotPos = HeaderFileName.rfind('.');
+ if (DotPos != std::string::npos)
+ HeaderFileName = HeaderFileName.substr(0, DotPos);
+ HeaderFileName += ".h";
+ printRuntimeHeader(IConf, HeaderFileName, Ctx);
+
+ OS << "//===-- Instrumentor Runtime Stub "
+ "-----------------------------------------===//\n";
+ OS << "//\n";
+ OS << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+ "Exceptions.\n";
+ OS << "// See https://llvm.org/LICENSE.txt for license information.\n";
+ OS << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n";
+ OS << "//\n";
+ OS << "//"
+ "===-------------------------------------------------------------------"
+ "---===//\n";
+ OS << "//\n";
+ OS << "// This file is auto-generated by the LLVM Instrumentor pass.\n";
+ OS << "// It provides stub implementations of instrumentation runtime "
+ "functions\n";
+ OS << "// that print human-readable information about instrumentation "
+ "events.\n";
+ OS << "//\n";
+ OS << "// Generated with runtime prefix: " << Prefix << "\n";
+ OS << "//\n";
+ OS << "//"
+ "===-------------------------------------------------------------------"
+ "---===//\n\n";
+ OS << "#include <inttypes.h>\n";
OS << "#include <stdint.h>\n";
- OS << "#include <stdio.h>\n\n";
+ OS << "#include <stdio.h>\n";
+ OS << "#include \"" << llvm::sys::path::filename(HeaderFileName) << "\"\n\n";
+ OS << "#ifdef __cplusplus\n";
+ OS << "extern \"C\" {\n";
+ OS << "#endif\n\n";
for (auto &ChoiceMap : IConf.IChoices) {
for (auto &[_, IO] : ChoiceMap) {
@@ -206,6 +607,10 @@ void printRuntimeStub(const InstrumentationConfig &IConf,
}
}
}
+
+ OS << "#ifdef __cplusplus\n";
+ OS << "}\n";
+ OS << "#endif\n";
}
} // end namespace instrumentor
diff --git a/llvm/test/Instrumentation/Instrumentor/default_rt b/llvm/test/Instrumentation/Instrumentor/default_rt
deleted file mode 100644
index 1e9750b2f6874..0000000000000
--- a/llvm/test/Instrumentation/Instrumentor/default_rt
+++ /dev/null
@@ -1,37 +0,0 @@
-// LLVM Instrumentor stub runtime
-
-#include <stdint.h>
-#include <stdio.h>
-
-void *__instrumentor_pre_load(void *pointer, int32_t pointer_as, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
- printf("load pre -- pointer: %p, pointer_as: %i, value_size: %lli, alignment: %lli, value_type_id: %i, atomicity_ordering: %i, sync_scope_id: %i, is_volatile: %i, id: %i\n", pointer, pointer_as, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
- return pointer;
-}
-
-void *__instrumentor_pre_store(void *pointer, int32_t pointer_as, int64_t value, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
- printf("store pre -- pointer: %p, pointer_as: %i, value: %lli, value_size: %lli, alignment: %lli, value_type_id: %i, atomicity_ordering: %i, sync_scope_id: %i, is_volatile: %i, id: %i\n", pointer, pointer_as, value, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
- return pointer;
-}
-
-void *__instrumentor_pre_store_ind(void *pointer, int32_t pointer_as, int64_t *value_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
- printf("store pre -- pointer: %p, pointer_as: %i, value: %p, value_size: %lli, alignment: %lli, value_type_id: %i, atomicity_ordering: %i, sync_scope_id: %i, is_volatile: %i, id: %i\n", pointer, pointer_as, value_ptr, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
- return pointer;
-}
-
-int64_t __instrumentor_post_load(void *pointer, int32_t pointer_as, int64_t value, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
- printf("load post -- pointer: %p, pointer_as: %i, value: %lli, value_size: %lli, alignment: %lli, value_type_id: %i, atomicity_ordering: %i, sync_scope_id: %i, is_volatile: %i, id: %i\n", pointer, pointer_as, value, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
- return value;
-}
-
-void __instrumentor_post_load_ind(void *pointer, int32_t pointer_as, int64_t *value_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
- printf("load post -- pointer: %p, pointer_as: %i, value: %p, value_size: %lli, alignment: %lli, value_type_id: %i, atomicity_ordering: %i, sync_scope_id: %i, is_volatile: %i, id: %i\n", pointer, pointer_as, value_ptr, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
-}
-
-void __instrumentor_post_store(void *pointer, int32_t pointer_as, int64_t value, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
- printf("store post -- pointer: %p, pointer_as: %i, value: %lli, value_size: %lli, alignment: %lli, value_type_id: %i, atomicity_ordering: %i, sync_scope_id: %i, is_volatile: %i, id: %i\n", pointer, pointer_as, value, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
-}
-
-void __instrumentor_post_store_ind(void *pointer, int32_t pointer_as, int64_t *value_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
- printf("store post -- pointer: %p, pointer_as: %i, value: %p, value_size: %lli, alignment: %lli, value_type_id: %i, atomicity_ordering: %i, sync_scope_id: %i, is_volatile: %i, id: %i\n", pointer, pointer_as, value_ptr, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
-}
-
diff --git a/llvm/test/Instrumentation/Instrumentor/default_rt.c b/llvm/test/Instrumentation/Instrumentor/default_rt.c
new file mode 100644
index 0000000000000..d0bbf6e992b59
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/default_rt.c
@@ -0,0 +1,124 @@
+//===-- Instrumentor Runtime Stub -----------------------------------------===//
+//
+// 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 file is auto-generated by the LLVM Instrumentor pass.
+// It provides stub implementations of instrumentation runtime functions
+// that print human-readable information about instrumentation events.
+//
+// Generated with runtime prefix: __instrumentor_
+//
+//===----------------------------------------------------------------------===//
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "default_rt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void __instrumentor_pre_module(char *module_name, char *target_triple, int32_t id) {
+ printf("module pre -- module_name: %s, target_triple: %s, id: %" PRId32 "\n", module_name, target_triple, id);
+}
+
+void __instrumentor_post_module(char *module_name, char *target_triple, int32_t id) {
+ printf("module post -- module_name: %s, target_triple: %s, id: %" PRId32 "\n", module_name, target_triple, id);
+}
+
+void *__instrumentor_pre_global(void *address, int32_t address_space, int64_t declared_size, int64_t alignment, char *name, int64_t initial_value, int8_t is_constant, int8_t is_definition, int32_t id) {
+ printf("global pre -- address: %p, address_space: %" PRId32 ", declared_size: %" PRId64 ", alignment: %" PRId64 ", name: %s, initial_value: %" PRId64 ", is_constant: %" PRId32 ", is_definition: %" PRId32 ", id: %" PRId32 "\n", address, address_space, declared_size, alignment, name, initial_value, is_constant, is_definition, id);
+ return address;
+}
+
+void *__instrumentor_pre_global_ind(void *address, int32_t address_space, int64_t declared_size, int64_t alignment, char *name, int64_t *initial_value_ptr, int8_t is_constant, int8_t is_definition, int32_t id) {
+ printf("global pre -- address: %p, address_space: %" PRId32 ", declared_size: %" PRId64 ", alignment: %" PRId64 ", name: %s, initial_value: %p, is_constant: %" PRId32 ", is_definition: %" PRId32 ", id: %" PRId32 "\n", address, address_space, declared_size, alignment, name, initial_value_ptr, is_constant, is_definition, id);
+ return address;
+}
+
+void __instrumentor_post_global(void *address, int32_t address_space, int64_t declared_size, int64_t alignment, char *name, int64_t initial_value, int8_t is_constant, int8_t is_definition, int32_t id) {
+ printf("global post -- address: %p, address_space: %" PRId32 ", declared_size: %" PRId64 ", alignment: %" PRId64 ", name: %s, initial_value: %" PRId64 ", is_constant: %" PRId32 ", is_definition: %" PRId32 ", id: %" PRId32 "\n", address, address_space, declared_size, alignment, name, initial_value, is_constant, is_definition, id);
+}
+
+void __instrumentor_post_global_ind(void *address, int32_t address_space, int64_t declared_size, int64_t alignment, char *name, int64_t *initial_value_ptr, int8_t is_constant, int8_t is_definition, int32_t id) {
+ printf("global post -- address: %p, address_space: %" PRId32 ", declared_size: %" PRId64 ", alignment: %" PRId64 ", name: %s, initial_value: %p, is_constant: %" PRId32 ", is_definition: %" PRId32 ", id: %" PRId32 "\n", address, address_space, declared_size, alignment, name, initial_value_ptr, is_constant, is_definition, id);
+}
+
+void __instrumentor_pre_function(void *address, char *name, int32_t num_arguments, void *arguments, int8_t is_main, int32_t id) {
+ printf("function pre -- address: %p, name: %s, num_arguments: %" PRId32 ", arguments: [value pack at %p], is_main: %" PRId32 ", id: %" PRId32 "\n", address, name, num_arguments, arguments, is_main, id);
+ ValuePackIterator iter_arguments;
+ initValuePackIterator(&iter_arguments, arguments, num_arguments);
+ while (iter_arguments.index < iter_arguments.count) {
+ ValuePackHeader header_arguments = getValuePackHeader(&iter_arguments);
+ const void *data_arguments = getValuePackData(&iter_arguments);
+ printf(" [%u] type=%s size=%u data=%p\n", iter_arguments.index, getLLVMTypeIDName(header_arguments.type_id), header_arguments.size, data_arguments);
+ nextValuePack(&iter_arguments);
+ }
+}
+
+void __instrumentor_post_function(void *address, char *name, int32_t num_arguments, void *arguments, int8_t is_main, int32_t id) {
+ printf("function post -- address: %p, name: %s, num_arguments: %" PRId32 ", arguments: [value pack at %p], is_main: %" PRId32 ", id: %" PRId32 "\n", address, name, num_arguments, arguments, is_main, id);
+ ValuePackIterator iter_arguments;
+ initValuePackIterator(&iter_arguments, arguments, num_arguments);
+ while (iter_arguments.index < iter_arguments.count) {
+ ValuePackHeader header_arguments = getValuePackHeader(&iter_arguments);
+ const void *data_arguments = getValuePackData(&iter_arguments);
+ printf(" [%u] type=%s size=%u data=%p\n", iter_arguments.index, getLLVMTypeIDName(header_arguments.type_id), header_arguments.size, data_arguments);
+ nextValuePack(&iter_arguments);
+ }
+}
+
+void __instrumentor_pre_unreachable(int32_t id) {
+ printf("unreachable pre -- id: %" PRId32 "\n", id);
+}
+
+void *__instrumentor_pre_load(void *pointer, int32_t pointer_as, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
+ printf("load pre -- pointer: %p, pointer_as: %" PRId32 ", value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %" PRId32 ", atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
+ return pointer;
+}
+
+int64_t __instrumentor_pre_alloca(int64_t size, int64_t alignment, int32_t id) {
+ printf("alloca pre -- size: %" PRId64 ", alignment: %" PRId64 ", id: %" PRId32 "\n", size, alignment, id);
+ return size;
+}
+
+void *__instrumentor_pre_store(void *pointer, int32_t pointer_as, int64_t value, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
+ printf("store pre -- pointer: %p, pointer_as: %" PRId32 ", value: %" PRId64 ", value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %" PRId32 ", atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, value, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
+ return pointer;
+}
+
+void *__instrumentor_pre_store_ind(void *pointer, int32_t pointer_as, int64_t *value_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
+ printf("store pre -- pointer: %p, pointer_as: %" PRId32 ", value: %p, value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %" PRId32 ", atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, value_ptr, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
+ return pointer;
+}
+
+int64_t __instrumentor_post_load(void *pointer, int32_t pointer_as, int64_t value, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
+ printf("load post -- pointer: %p, pointer_as: %" PRId32 ", value: %" PRId64 ", value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %" PRId32 ", atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, value, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
+ return value;
+}
+
+void __instrumentor_post_load_ind(void *pointer, int32_t pointer_as, int64_t *value_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
+ printf("load post -- pointer: %p, pointer_as: %" PRId32 ", value: %p, value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %" PRId32 ", atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, value_ptr, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
+}
+
+void *__instrumentor_post_alloca(void *address, int64_t size, int64_t alignment, int32_t id) {
+ printf("alloca post -- address: %p, size: %" PRId64 ", alignment: %" PRId64 ", id: %" PRId32 "\n", address, size, alignment, id);
+ return address;
+}
+
+void __instrumentor_post_store(void *pointer, int32_t pointer_as, int64_t value, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
+ printf("store post -- pointer: %p, pointer_as: %" PRId32 ", value: %" PRId64 ", value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %" PRId32 ", atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, value, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
+}
+
+void __instrumentor_post_store_ind(void *pointer, int32_t pointer_as, int64_t *value_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int8_t is_volatile, int32_t id) {
+ printf("store post -- pointer: %p, pointer_as: %" PRId32 ", value: %p, value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %" PRId32 ", atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, value_ptr, value_size, alignment, value_type_id, atomicity_ordering, sync_scope_id, is_volatile, id);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/llvm/test/Instrumentation/Instrumentor/default_rt.h b/llvm/test/Instrumentation/Instrumentor/default_rt.h
new file mode 100644
index 0000000000000..174e6a6934124
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/default_rt.h
@@ -0,0 +1,264 @@
+//===-- 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.
+//
+// Generated with runtime prefix: __instrumentor_
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INSTRUMENTOR_RUNTIME_H
+#define INSTRUMENTOR_RUNTIME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <string.h>
+
+#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 <typename T> const T &as() const {
+ return *static_cast<const T*>(data);
+ }
+ template <typename T> const T *ptr() const {
+ return static_cast<const T*>(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 <typename T>
+inline const T *getValueAs(const void *pack_ptr, uint32_t num_elements, uint32_t index) {
+ return static_cast<const T*>(getValuePackEntry(pack_ptr, num_elements, index, nullptr));
+}
+
+#endif // __cplusplus
+
+#endif // INSTRUMENTOR_RUNTIME_H
diff --git a/llvm/test/Instrumentation/Instrumentor/generate_rt.ll b/llvm/test/Instrumentation/Instrumentor/generate_rt.ll
index 9e6b444ba895c..533561b73ce39 100644
--- a/llvm/test/Instrumentation/Instrumentor/generate_rt.ll
+++ b/llvm/test/Instrumentation/Instrumentor/generate_rt.ll
@@ -1,3 +1,4 @@
; RUN: rm -rf %t && mkdir -p %t && cd %t
; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-files=%S/rt_config.json -S
-; RUN: diff -b rt.c %S/default_rt
+; RUN: diff -b default_rt.c %S/default_rt.c
+; RUN: diff -b default_rt.h %S/default_rt.h
diff --git a/llvm/test/Instrumentation/Instrumentor/lit.local.cfg b/llvm/test/Instrumentation/Instrumentor/lit.local.cfg
new file mode 100644
index 0000000000000..f400568be0c61
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/lit.local.cfg
@@ -0,0 +1 @@
+config.excludes = ["default_rt.c"]
diff --git a/llvm/test/Instrumentation/Instrumentor/rt_config.json b/llvm/test/Instrumentation/Instrumentor/rt_config.json
index 2af8f11eb9ad3..a55d75fd40597 100644
--- a/llvm/test/Instrumentation/Instrumentor/rt_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/rt_config.json
@@ -2,12 +2,147 @@
"configuration": {
"runtime_prefix": "__instrumentor_",
"runtime_prefix.description": "The runtime API prefix.",
- "runtime_stubs_file": "rt.c",
- "runtime_stubs_file.description": "The file into which runtime stubs should be written."
+ "runtime_stubs_file": "default_rt.c",
+ "runtime_stubs_file.description": "The file into which runtime stubs should be written.",
+ "target_regex": "",
+ "target_regex.description": "Regular expression to be matched against the module target. Only targets that match this regex will be instrumented.",
+ "function_regex": "",
+ "function_regex.description": "Regular expression to be matched against a function name. Only functions that match this regex will be instrumented.",
+ "demangle_function_names": true,
+ "demangle_function_names.description": "Demangle functions names passed to the runtime.",
+ "host_enabled": true,
+ "host_enabled.description": "Instrument non-GPU targets",
+ "gpu_enabled": true,
+ "gpu_enabled.description": "Instrument GPU targets"
+ },
+ "module_pre": {
+ "module": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "module_name": true,
+ "module_name.description": "The module/translation unit name.",
+ "target_triple": true,
+ "target_triple.description": "The target triple.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ },
+ "module_post": {
+ "module": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "module_name": true,
+ "module_name.description": "The module/translation unit name.",
+ "target_triple": true,
+ "target_triple.description": "The target triple.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ },
+ "global_pre": {
+ "global": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "address": true,
+ "address.replace": true,
+ "address.description": "The address of the global (replaceable for definitions).",
+ "address_space": true,
+ "address_space.description": "The address space of the global.",
+ "declared_size": true,
+ "declared_size.description": "The size of the declared type of the global.",
+ "alignment": true,
+ "alignment.description": "The allocation alignment.",
+ "name": true,
+ "name.description": "The name of the global.",
+ "initial_value": true,
+ "initial_value.description": "The initial value of the global.",
+ "is_constant": true,
+ "is_constant.description": "Flag to indicate constant globals.",
+ "is_definition": true,
+ "is_definition.description": "Flag to indicate global definitions.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ },
+ "global_post": {
+ "global": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "address": true,
+ "address.description": "The address of the global (replaceable for definitions).",
+ "address_space": true,
+ "address_space.description": "The address space of the global.",
+ "declared_size": true,
+ "declared_size.description": "The size of the declared type of the global.",
+ "alignment": true,
+ "alignment.description": "The allocation alignment.",
+ "name": true,
+ "name.description": "The name of the global.",
+ "initial_value": true,
+ "initial_value.description": "The initial value of the global.",
+ "is_constant": true,
+ "is_constant.description": "Flag to indicate constant globals.",
+ "is_definition": true,
+ "is_definition.description": "Flag to indicate global definitions.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ },
+ "function_pre": {
+ "function": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "address": true,
+ "address.description": "The function address.",
+ "name": true,
+ "name.description": "The function name.",
+ "num_arguments": true,
+ "num_arguments.description": "Number of function arguments (without varargs).",
+ "arguments": true,
+ "arguments.replace": true,
+ "arguments.description": "Description of the arguments.",
+ "is_main": true,
+ "is_main.description": "Flag to indicate it is the main function.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ },
+ "function_post": {
+ "function": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "address": true,
+ "address.description": "The function address.",
+ "name": true,
+ "name.description": "The function name.",
+ "num_arguments": true,
+ "num_arguments.description": "Number of function arguments (without varargs).",
+ "arguments": true,
+ "arguments.description": "Description of the arguments.",
+ "is_main": true,
+ "is_main.description": "Flag to indicate it is the main function.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
},
"instruction_pre": {
+ "unreachable": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
"load": {
"enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
"pointer": true,
"pointer.replace": true,
"pointer.description": "The accessed pointer.",
@@ -28,8 +163,31 @@
"id": true,
"id.description": "A unique ID associated with the given instrumentor call"
},
+ "ptrtoint": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "pointer": true,
+ "pointer.description": "Input pointer of the ptr to int.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
+ "alloca": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "size": true,
+ "size.replace": true,
+ "size.description": "The allocation size.",
+ "alignment": true,
+ "alignment.description": "The allocation alignment.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
"store": {
"enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
"pointer": true,
"pointer.replace": true,
"pointer.description": "The accessed pointer.",
@@ -56,6 +214,8 @@
"instruction_post": {
"load": {
"enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
"pointer": true,
"pointer.description": "The accessed pointer.",
"pointer_as": true,
@@ -78,8 +238,36 @@
"id": true,
"id.description": "A unique ID associated with the given instrumentor call"
},
+ "ptrtoint": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "pointer": true,
+ "pointer.description": "Input pointer of the ptr to int.",
+ "value": true,
+ "value.replace": true,
+ "value.description": "Result of the ptr to int.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
+ "alloca": {
+ "enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
+ "address": true,
+ "address.replace": true,
+ "address.description": "The allocated memory address.",
+ "size": true,
+ "size.description": "The allocation size.",
+ "alignment": true,
+ "alignment.description": "The allocation alignment.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
"store": {
"enabled": true,
+ "filter": "",
+ "filter.description": "Static property filter to exclude instrumentation.",
"pointer": true,
"pointer.description": "The accessed pointer.",
"pointer_as": true,
More information about the llvm-commits
mailing list