[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:12:58 PDT 2025
================
@@ -0,0 +1,212 @@
+//===-- 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/DiagnosticInfo.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.diagnose(DiagnosticInfoInstrumentation(
+ Twine("Failed to open instrumentor stub runtime file for writing: ") +
----------------
kevinsala wrote:
Updated with lowercase message, error instead of warning (using `LLVMContext::emitError`), and a new test checking that case.
https://github.com/llvm/llvm-project/pull/138978
More information about the llvm-branch-commits
mailing list