[llvm-branch-commits] [llvm] [Instrumentor] Allow printing a runtime stub (PR #138978)
Kevin Sala Penades via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Jul 6 22:07:49 PDT 2025
https://github.com/kevinsala updated https://github.com/llvm/llvm-project/pull/138978
>From 371483a750a456459d054a56787b40e946ab2890 Mon Sep 17 00:00:00 2001
From: Kevin Sala <salapenades1 at llnl.gov>
Date: Tue, 6 May 2025 22:48:41 -0700
Subject: [PATCH] [Instrumentor] Allow printing a runtime stub
---
.../llvm/Transforms/IPO/Instrumentor.h | 16 ++
.../Transforms/IPO/InstrumentorStubPrinter.h | 32 +++
llvm/lib/Transforms/IPO/CMakeLists.txt | 1 +
llvm/lib/Transforms/IPO/Instrumentor.cpp | 3 +
.../IPO/InstrumentorStubPrinter.cpp | 210 ++++++++++++++++++
.../Instrumentor/bad_rt_config.json | 105 +++++++++
.../Instrumentor/default_config.json | 2 +
.../Instrumentation/Instrumentor/default_rt | 37 +++
.../Instrumentor/generate_bad_rt.ll | 3 +
.../Instrumentor/generate_rt.ll | 2 +
.../Instrumentor/load_store_config.json | 2 +-
.../load_store_noreplace_config.json | 2 +-
.../Instrumentor/rt_config.json | 105 +++++++++
13 files changed, 518 insertions(+), 2 deletions(-)
create mode 100644 llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h
create mode 100644 llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp
create mode 100644 llvm/test/Instrumentation/Instrumentor/bad_rt_config.json
create mode 100644 llvm/test/Instrumentation/Instrumentor/default_rt
create mode 100644 llvm/test/Instrumentation/Instrumentor/generate_bad_rt.ll
create mode 100644 llvm/test/Instrumentation/Instrumentor/generate_rt.ll
create mode 100644 llvm/test/Instrumentation/Instrumentor/rt_config.json
diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
index 26445d221d00f..e6d5f717072a2 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -116,6 +116,18 @@ struct IRTCallDescription {
InstrumentorIRBuilderTy &IIRB, const DataLayout &DL,
InstrumentationCaches &ICaches);
+ /// Create a string representation of the function declaration in C. Two
+ /// strings are returned: the function definition with direct arguments and
+ /// the function with any indirect argument.
+ std::pair<std::string, std::string>
+ createCSignature(const InstrumentationConfig &IConf) const;
+
+ /// Create a string representation of the function definition in C. The
+ /// function body implements a stub and only prints the passed arguments. Two
+ /// strings are returned: the function definition with direct arguments and
+ /// the function with any indirect argument.
+ std::pair<std::string, std::string> createCBodies() const;
+
/// Return whether the \p IRTA argument can be replaced.
bool isReplacable(IRTArg &IRTA) const {
return (IRTA.Flags & (IRTArg::REPLACABLE | IRTArg::REPLACABLE_CUSTOM));
@@ -334,6 +346,9 @@ struct InstrumentationConfig {
InstrumentationConfig() : SS(StringAllocator) {
RuntimePrefix = BaseConfigurationOption::getStringOption(
*this, "runtime_prefix", "The runtime API prefix.", "__instrumentor_");
+ RuntimeStubsFile = BaseConfigurationOption::getStringOption(
+ *this, "runtime_stubs_file",
+ "The file into which runtime stubs should be written.", "");
TargetRegex = BaseConfigurationOption::getStringOption(
*this, "target_regex",
"Regular expression to be matched against the module target. "
@@ -380,6 +395,7 @@ struct InstrumentationConfig {
/// The base configuration options.
BaseConfigurationOption *RuntimePrefix;
+ BaseConfigurationOption *RuntimeStubsFile;
BaseConfigurationOption *TargetRegex;
BaseConfigurationOption *HostEnabled;
BaseConfigurationOption *GPUEnabled;
diff --git a/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h b/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h
new file mode 100644
index 0000000000000..6e1e24d5fef9e
--- /dev/null
+++ b/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h
@@ -0,0 +1,32 @@
+//===- Transforms/IPO/InstrumentorStubPrinter.h ---------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A generator of Instrumentor's runtime stubs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_IPO_INSTRUMENTOR_STUB_PRINTER_H
+#define LLVM_TRANSFORMS_IPO_INSTRUMENTOR_STUB_PRINTER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Transforms/IPO/Instrumentor.h"
+
+namespace llvm {
+namespace instrumentor {
+
+/// Print a runtime stub file with the implementation of the instrumentation
+/// runtime functions corresponding to the instrumentation opportunities
+/// enabled.
+void printRuntimeStub(const InstrumentationConfig &IConf,
+ StringRef StubRuntimeName, LLVMContext &Ctx);
+
+} // end namespace instrumentor
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_IPO_INSTRUMENTOR_STUB_PRINTER_H
diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt
index 824dff527a672..d1d132c51dca9 100644
--- a/llvm/lib/Transforms/IPO/CMakeLists.txt
+++ b/llvm/lib/Transforms/IPO/CMakeLists.txt
@@ -29,6 +29,7 @@ add_llvm_component_library(LLVMipo
Inliner.cpp
Instrumentor.cpp
InstrumentorConfigFile.cpp
+ InstrumentorStubPrinter.cpp
Internalize.cpp
LoopExtractor.cpp
LowerTypeTests.cpp
diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp
index a28a40bdcb90e..4545af75ca8ac 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -10,6 +10,7 @@
#include "llvm/Transforms/IPO/Instrumentor.h"
#include "llvm/Transforms/IPO/InstrumentorConfigFile.h"
+#include "llvm/Transforms/IPO/InstrumentorStubPrinter.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -261,6 +262,8 @@ PreservedAnalyses InstrumentorPass::run(Module &M, InstrumentationConfig &IConf,
writeConfigToJSON(IConf, WriteConfigFile, IIRB.Ctx);
+ printRuntimeStub(IConf, IConf.RuntimeStubsFile->getString(), IIRB.Ctx);
+
bool Changed = Impl.instrument();
if (!Changed)
return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp b/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp
new file mode 100644
index 0000000000000..bab8726f03b0d
--- /dev/null
+++ b/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp
@@ -0,0 +1,210 @@
+//===-- InstrumentorStubPrinter.cpp ---------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/IPO/Instrumentor.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cassert>
+#include <string>
+#include <system_error>
+
+namespace llvm {
+namespace instrumentor {
+
+/// Get the string representation of an argument with type \p Ty. Two strings
+/// are returned: one for direct arguments and another for indirect arguments.
+/// The flags in \p Flags describe the properties of the argument. See
+/// IRTArg::IRArgFlagTy.
+static std::pair<std::string, std::string> getAsCType(Type *Ty,
+ unsigned Flags) {
+ if (Ty->isIntegerTy()) {
+ auto BW = Ty->getIntegerBitWidth();
+ if (BW == 1)
+ return {"bool ", "bool *"};
+ auto S = "int" + std::to_string(BW) + "_t ";
+ return {S, S + "*"};
+ }
+ if (Ty->isPointerTy())
+ return {Flags & IRTArg::STRING ? "char *" : "void *", "void **"};
+ if (Ty->isFloatTy())
+ return {"float ", "float *"};
+ if (Ty->isDoubleTy())
+ return {"double ", "double *"};
+ return {"<>", "<>"};
+}
+
+/// Get the string representation of the C printf format of an argument with
+/// type \p Ty. The flags in \p Flags describe the properties of the argument.
+/// See IRTArg::IRArgFlagTy.
+static std::string getPrintfFormatString(Type *Ty, unsigned Flags) {
+ if (Ty->isIntegerTy()) {
+ if (Ty->getIntegerBitWidth() > 32) {
+ assert(Ty->getIntegerBitWidth() == 64);
+ return "%lli";
+ }
+ return "%i";
+ }
+ if (Ty->isPointerTy())
+ return Flags & IRTArg::STRING ? "%s" : "%p";
+ if (Ty->isFloatTy())
+ return "%f";
+ if (Ty->isDoubleTy())
+ return "%lf";
+ return "<>";
+}
+
+std::pair<std::string, std::string> IRTCallDescription::createCBodies() const {
+ std::string DirectFormat = "printf(\"" + IO.getName().str() +
+ (IO.IP.isPRE() ? " pre" : " post") + " -- ";
+ std::string IndirectFormat = DirectFormat;
+ std::string DirectArg, IndirectArg, DirectReturnValue, IndirectReturnValue;
+
+ auto AddToFormats = [&](Twine S) {
+ DirectFormat += S.str();
+ IndirectFormat += S.str();
+ };
+ auto AddToArgs = [&](Twine S) {
+ DirectArg += S.str();
+ IndirectArg += S.str();
+ };
+ bool First = true;
+ for (auto &IRArg : IO.IRTArgs) {
+ if (!IRArg.Enabled)
+ continue;
+ if (!First)
+ AddToFormats(", ");
+ First = false;
+ AddToArgs(", " + IRArg.Name);
+ AddToFormats(IRArg.Name + ": ");
+ if (NumReplaceableArgs == 1 && (IRArg.Flags & IRTArg::REPLACABLE)) {
+ DirectReturnValue = IRArg.Name;
+ if (!isPotentiallyIndirect(IRArg))
+ IndirectReturnValue = IRArg.Name;
+ }
+ if (!isPotentiallyIndirect(IRArg)) {
+ AddToFormats(getPrintfFormatString(IRArg.Ty, IRArg.Flags));
+ } else {
+ DirectFormat += getPrintfFormatString(IRArg.Ty, IRArg.Flags);
+ IndirectFormat += "%p";
+ IndirectArg += "_ptr";
+ // Add the indirect argument size
+ if (!(IRArg.Flags & IRTArg::INDIRECT_HAS_SIZE)) {
+ IndirectFormat += ", " + IRArg.Name.str() + "_size: %i";
+ IndirectArg += ", " + IRArg.Name.str() + "_size";
+ }
+ }
+ }
+
+ std::string DirectBody = DirectFormat + "\\n\"" + DirectArg + ");\n";
+ std::string IndirectBody = IndirectFormat + "\\n\"" + IndirectArg + ");\n";
+ if (RetTy)
+ IndirectReturnValue = DirectReturnValue = "0";
+ if (!DirectReturnValue.empty())
+ DirectBody += " return " + DirectReturnValue + ";\n";
+ if (!IndirectReturnValue.empty())
+ IndirectBody += " return " + IndirectReturnValue + ";\n";
+ return {DirectBody, IndirectBody};
+}
+
+std::pair<std::string, std::string>
+IRTCallDescription::createCSignature(const InstrumentationConfig &IConf) const {
+ SmallVector<std::string> DirectArgs, IndirectArgs;
+ std::string DirectRetTy = "void ", IndirectRetTy = "void ";
+ for (auto &IRArg : IO.IRTArgs) {
+ if (!IRArg.Enabled)
+ continue;
+ const auto &[DirectArgTy, IndirectArgTy] =
+ getAsCType(IRArg.Ty, IRArg.Flags);
+ std::string DirectArg = DirectArgTy + IRArg.Name.str();
+ std::string IndirectArg = IndirectArgTy + IRArg.Name.str() + "_ptr";
+ std::string IndirectArgSize = "int32_t " + IRArg.Name.str() + "_size";
+ DirectArgs.push_back(DirectArg);
+ if (NumReplaceableArgs == 1 && (IRArg.Flags & IRTArg::REPLACABLE)) {
+ DirectRetTy = DirectArgTy;
+ if (!isPotentiallyIndirect(IRArg))
+ IndirectRetTy = DirectArgTy;
+ }
+ if (!isPotentiallyIndirect(IRArg)) {
+ IndirectArgs.push_back(DirectArg);
+ } else {
+ IndirectArgs.push_back(IndirectArg);
+ if (!(IRArg.Flags & IRTArg::INDIRECT_HAS_SIZE))
+ IndirectArgs.push_back(IndirectArgSize);
+ }
+ }
+
+ auto DirectName =
+ IConf.getRTName(IO.IP.isPRE() ? "pre_" : "post_", IO.getName(), "");
+ auto IndirectName =
+ IConf.getRTName(IO.IP.isPRE() ? "pre_" : "post_", IO.getName(), "_ind");
+ auto MakeSignature = [&](std::string &RetTy, std::string &Name,
+ SmallVectorImpl<std::string> &Args) {
+ return RetTy + Name + "(" + join(Args, ", ") + ")";
+ };
+
+ if (RetTy) {
+ auto UserRetTy = getAsCType(RetTy, 0).first;
+ assert((DirectRetTy == UserRetTy || DirectRetTy == "void ") &&
+ (IndirectRetTy == UserRetTy || IndirectRetTy == "void ") &&
+ "Explicit return type but also implicit one!");
+ IndirectRetTy = DirectRetTy = UserRetTy;
+ }
+ if (RequiresIndirection)
+ return {"", MakeSignature(IndirectRetTy, IndirectName, IndirectArgs)};
+ if (!MightRequireIndirection)
+ return {MakeSignature(DirectRetTy, DirectName, DirectArgs), ""};
+ return {MakeSignature(DirectRetTy, DirectName, DirectArgs),
+ MakeSignature(IndirectRetTy, IndirectName, IndirectArgs)};
+}
+
+void printRuntimeStub(const InstrumentationConfig &IConf,
+ StringRef StubRuntimeName, LLVMContext &Ctx) {
+ if (StubRuntimeName.empty())
+ return;
+
+ std::error_code EC;
+ raw_fd_ostream OS(StubRuntimeName, EC);
+ if (EC) {
+ Ctx.emitError(
+ Twine("failed to open instrumentor stub runtime file for writing: ") +
+ EC.message());
+ return;
+ }
+
+ OS << "// LLVM Instrumentor stub runtime\n\n";
+ OS << "#include <stdint.h>\n";
+ OS << "#include <stdio.h>\n\n";
+
+ for (auto &ChoiceMap : IConf.IChoices) {
+ for (auto &[_, IO] : ChoiceMap) {
+ if (!IO->Enabled)
+ continue;
+ IRTCallDescription IRTCallDesc(*IO, IO->getRetTy(Ctx));
+ const auto Signatures = IRTCallDesc.createCSignature(IConf);
+ const auto Bodies = IRTCallDesc.createCBodies();
+ if (!Signatures.first.empty()) {
+ OS << Signatures.first << " {\n";
+ OS << " " << Bodies.first << "}\n\n";
+ }
+ if (!Signatures.second.empty()) {
+ OS << Signatures.second << " {\n";
+ OS << " " << Bodies.second << "}\n\n";
+ }
+ }
+ }
+}
+
+} // end namespace instrumentor
+} // end namespace llvm
diff --git a/llvm/test/Instrumentation/Instrumentor/bad_rt_config.json b/llvm/test/Instrumentation/Instrumentor/bad_rt_config.json
new file mode 100644
index 0000000000000..d36966c0451a9
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/bad_rt_config.json
@@ -0,0 +1,105 @@
+{
+ "configuration": {
+ "runtime_prefix": "__instrumentor_",
+ "runtime_prefix.description": "The runtime API prefix.",
+ "runtime_stubs_file": ".",
+ "runtime_stubs_file.description": "The file into which runtime stubs should be written."
+ },
+ "instruction_pre": {
+ "load": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.replace": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value_size": true,
+ "value_size.description": "The size of the loaded value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the loaded value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the load.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the load.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile load.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
+ "store": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.replace": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value": true,
+ "value.description": "The stored value.",
+ "value_size": true,
+ "value_size.description": "The size of the stored value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the stored value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the store.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the store.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile store.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ },
+ "instruction_post": {
+ "load": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value": true,
+ "value.replace": true,
+ "value.description": "The loaded value.",
+ "value_size": true,
+ "value_size.description": "The size of the loaded value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the loaded value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the load.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the load.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile load.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
+ "store": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value": true,
+ "value.description": "The stored value.",
+ "value_size": true,
+ "value_size.description": "The size of the stored value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the stored value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the store.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the store.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile store.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/default_config.json b/llvm/test/Instrumentation/Instrumentor/default_config.json
index 2765d5c0116d2..263ab58e2566d 100644
--- a/llvm/test/Instrumentation/Instrumentor/default_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/default_config.json
@@ -2,6 +2,8 @@
"configuration": {
"runtime_prefix": "__instrumentor_",
"runtime_prefix.description": "The runtime API prefix.",
+ "runtime_stubs_file": "",
+ "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",
"host_enabled": true,
diff --git a/llvm/test/Instrumentation/Instrumentor/default_rt b/llvm/test/Instrumentation/Instrumentor/default_rt
new file mode 100644
index 0000000000000..1e9750b2f6874
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/default_rt
@@ -0,0 +1,37 @@
+// 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/generate_bad_rt.ll b/llvm/test/Instrumentation/Instrumentor/generate_bad_rt.ll
new file mode 100644
index 0000000000000..2254f4fc2bd2a
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/generate_bad_rt.ll
@@ -0,0 +1,3 @@
+; RUN: not opt < %s -passes=instrumentor -instrumentor-read-config-file=%S/bad_rt_config.json 2>&1 | FileCheck %s
+
+; CHECK: error: failed to open instrumentor stub runtime file for writing: Is a directory
diff --git a/llvm/test/Instrumentation/Instrumentor/generate_rt.ll b/llvm/test/Instrumentation/Instrumentor/generate_rt.ll
new file mode 100644
index 0000000000000..645a1f935165b
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/generate_rt.ll
@@ -0,0 +1,2 @@
+; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-file=%S/rt_config.json -S
+; RUN: diff rt.c %S/default_rt
diff --git a/llvm/test/Instrumentation/Instrumentor/load_store_config.json b/llvm/test/Instrumentation/Instrumentor/load_store_config.json
index b96a02a4e09ea..1cc1f0e152543 100644
--- a/llvm/test/Instrumentation/Instrumentor/load_store_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/load_store_config.json
@@ -2,7 +2,7 @@
"configuration": {
"runtime_prefix": "__instrumentor_",
"runtime_prefix.description": "The runtime API prefix.",
- "runtime_stubs_file": "rt.c",
+ "runtime_stubs_file": "",
"runtime_stubs_file.description": "The file into which runtime stubs should be written.",
"demangle_function_names": true,
"demangle_function_names.description": "Demangle functions names passed to the runtime."
diff --git a/llvm/test/Instrumentation/Instrumentor/load_store_noreplace_config.json b/llvm/test/Instrumentation/Instrumentor/load_store_noreplace_config.json
index f59de1c010adf..251148e075008 100644
--- a/llvm/test/Instrumentation/Instrumentor/load_store_noreplace_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/load_store_noreplace_config.json
@@ -2,7 +2,7 @@
"configuration": {
"runtime_prefix": "__instrumentor_",
"runtime_prefix.description": "The runtime API prefix.",
- "runtime_stubs_file": "rt.c",
+ "runtime_stubs_file": "",
"runtime_stubs_file.description": "The file into which runtime stubs should be written.",
"demangle_function_names": true,
"demangle_function_names.description": "Demangle functions names passed to the runtime."
diff --git a/llvm/test/Instrumentation/Instrumentor/rt_config.json b/llvm/test/Instrumentation/Instrumentor/rt_config.json
new file mode 100644
index 0000000000000..2af8f11eb9ad3
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/rt_config.json
@@ -0,0 +1,105 @@
+{
+ "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."
+ },
+ "instruction_pre": {
+ "load": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.replace": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value_size": true,
+ "value_size.description": "The size of the loaded value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the loaded value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the load.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the load.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile load.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
+ "store": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.replace": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value": true,
+ "value.description": "The stored value.",
+ "value_size": true,
+ "value_size.description": "The size of the stored value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the stored value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the store.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the store.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile store.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ },
+ "instruction_post": {
+ "load": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value": true,
+ "value.replace": true,
+ "value.description": "The loaded value.",
+ "value_size": true,
+ "value_size.description": "The size of the loaded value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the loaded value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the load.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the load.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile load.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
+ "store": {
+ "enabled": true,
+ "pointer": true,
+ "pointer.description": "The accessed pointer.",
+ "pointer_as": true,
+ "pointer_as.description": "The address space of the accessed pointer.",
+ "value": true,
+ "value.description": "The stored value.",
+ "value_size": true,
+ "value_size.description": "The size of the stored value.",
+ "alignment": true,
+ "alignment.description": "The known access alignment.",
+ "value_type_id": true,
+ "value_type_id.description": "The type id of the stored value.",
+ "atomicity_ordering": true,
+ "atomicity_ordering.description": "The atomicity ordering of the store.",
+ "sync_scope_id": true,
+ "sync_scope_id.description": "The sync scope id of the store.",
+ "is_volatile": true,
+ "is_volatile.description": "Flag indicating a volatile store.",
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ }
+}
More information about the llvm-branch-commits
mailing list