-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Instrumentor] Allow printing a runtime stub #138978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kevinsala
wants to merge
1
commit into
users/kevinsala/instrumentor-base-pr
Choose a base branch
from
users/kevinsala/instrumentor-stub-rt-pr
base: users/kevinsala/instrumentor-base-pr
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[Instrumentor] Allow printing a runtime stub #138978
kevinsala
wants to merge
1
commit into
users/kevinsala/instrumentor-base-pr
from
users/kevinsala/instrumentor-stub-rt-pr
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-llvm-transforms Author: Kevin Sala Penades (kevinsala) ChangesThis PR extends the Instrumentor the option Full diff: https://github.com/llvm/llvm-project/pull/138978.diff 8 Files Affected:
diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
index 6fb5a06305096..7caa2448b70dd 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -174,6 +174,11 @@ struct InstrumentationCaches {
struct IRTCallDescription {
IRTCallDescription(InstrumentationOpportunity &IConf, Type *RetTy = nullptr);
+ std::pair<std::string, std::string> createCBodies() const;
+
+ std::pair<std::string, std::string>
+ createCSignature(const InstrumentationConfig &IConf) const;
+
FunctionType *createLLVMSignature(InstrumentationConfig &IConf,
LLVMContext &Ctx, const DataLayout &DL,
bool ForceIndirection);
@@ -346,6 +351,9 @@ struct InstrumentationConfig {
InstrumentationConfig() : SS(StringAllocator) {
RuntimePrefix = BaseConfigurationOpportunity::getStringOption(
*this, "runtime_prefix", "The runtime API prefix.", "__instrumentor_");
+ RuntimeStubsFile = BaseConfigurationOpportunity::getStringOption(
+ *this, "runtime_stubs_file",
+ "The file into which runtime stubs should be written.", "test.c");
TargetRegex = BaseConfigurationOpportunity::getStringOption(
*this, "target_regex",
"Regular expression to be matched against the module target. "
@@ -373,6 +381,7 @@ struct InstrumentationConfig {
SmallVector<BaseConfigurationOpportunity *> BaseConfigurationOpportunities;
BaseConfigurationOpportunity *RuntimePrefix;
+ BaseConfigurationOpportunity *RuntimeStubsFile;
BaseConfigurationOpportunity *TargetRegex;
BaseConfigurationOpportunity *HostEnabled;
BaseConfigurationOpportunity *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..65cd120d001e8
--- /dev/null
+++ b/llvm/include/llvm/Transforms/IPO/InstrumentorStubPrinter.h
@@ -0,0 +1,30 @@
+//===- 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 stub.
+//
+//===----------------------------------------------------------------------===//
+
+#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 enabled instrumentation opportunities.
+void printRuntimeStub(const InstrumentationConfig &IConf,
+ StringRef StubRuntimeName, const Module &M);
+
+} // 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 17657cfae8fb5..9ba92b67085a7 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"
@@ -256,6 +257,8 @@ PreservedAnalyses InstrumentorPass::run(Module &M, FunctionAnalysisManager &FAM,
writeConfigToJSON(IConf, WriteJSONConfig);
+ printRuntimeStub(IConf, IConf.RuntimeStubsFile->getString(), M);
+
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..d9252cc1008e9
--- /dev/null
+++ b/llvm/lib/Transforms/IPO/InstrumentorStubPrinter.cpp
@@ -0,0 +1,214 @@
+//===-- 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/Module.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cassert>
+#include <string>
+#include <system_error>
+
+namespace llvm {
+namespace instrumentor {
+
+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 {"<>", "<>"};
+}
+
+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)};
+}
+
+static raw_fd_ostream *createOutputStream(StringRef Name) {
+ std::error_code EC;
+ auto *Out = new raw_fd_ostream(Name, EC);
+ if (EC) {
+ errs() << "WARNING: Failed to open instrumentor stub runtime file for "
+ "writing: "
+ << EC.message() << "\n";
+ delete Out;
+ Out = nullptr;
+ } else {
+ *Out << "// LLVM Instrumentor stub runtime\n\n";
+ *Out << "#include <stdint.h>\n";
+ *Out << "#include <stdio.h>\n\n";
+ }
+
+ return Out;
+}
+
+void printRuntimeStub(const InstrumentationConfig &IConf,
+ StringRef StubRuntimeName, const Module &M) {
+ if (StubRuntimeName.empty())
+ return;
+
+ auto *Out = createOutputStream(StubRuntimeName);
+ if (!Out)
+ return;
+
+ for (auto &ChoiceMap : IConf.IChoices) {
+ for (auto &[_, IO] : ChoiceMap) {
+ if (!IO->Enabled)
+ continue;
+ IRTCallDescription IRTCallDesc(*IO, IO->getRetTy(M.getContext()));
+ const auto Signatures = IRTCallDesc.createCSignature(IConf);
+ const auto Bodies = IRTCallDesc.createCBodies();
+ if (!Signatures.first.empty()) {
+ *Out << Signatures.first << " {\n";
+ *Out << " " << Bodies.first << "}\n\n";
+ }
+ if (!Signatures.second.empty()) {
+ *Out << Signatures.second << " {\n";
+ *Out << " " << Bodies.second << "}\n\n";
+ }
+ }
+ }
+
+ delete Out;
+}
+
+} // end namespace instrumentor
+} // end namespace llvm
diff --git a/llvm/test/Instrumentation/Instrumentor/default_config.json b/llvm/test/Instrumentation/Instrumentor/default_config.json
index 2765d5c0116d2..69420fd0b01b8 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": "test.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",
"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/rt.ll b/llvm/test/Instrumentation/Instrumentor/rt.ll
new file mode 100644
index 0000000000000..6a8c56084edce
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/rt.ll
@@ -0,0 +1,3 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instrumentor
+; RUN: diff test.c %S/default_rt
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR extends the Instrumentor the option
configuration.runtime_stubs_file
to generate a runtime stub file with the configured instrumentation. The stub prints all parameters passed to each enabled instrumentation function.