LLVM 23.0.0git
InstrumentorStubPrinter.cpp
Go to the documentation of this file.
1//===-- InstrumentorStubPrinter.cpp ---------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The implementation of a generator of Instrumentor's runtime stubs.
10//
11//===----------------------------------------------------------------------===//
12
14#include "llvm/Transforms/IPO/InstrumentorVariables.inc"
15
18#include "llvm/ADT/StringRef.h"
19#include "llvm/IR/LLVMContext.h"
20#include "llvm/Support/Path.h"
22
23#include <cassert>
24#include <string>
25#include <system_error>
26
27namespace llvm {
28namespace instrumentor {
29
30/// Get the string representation of an argument with type \p Ty. Two strings
31/// are returned: one for direct arguments and another for indirect arguments.
32/// The flags in \p Flags describe the properties of the argument. See
33/// IRTArg::IRArgFlagTy.
34static std::pair<std::string, std::string> getAsCType(Type *Ty,
35 unsigned Flags) {
36 if (Ty->isIntegerTy()) {
37 auto BW = Ty->getIntegerBitWidth();
38 if (BW == 1)
39 return {"bool ", "bool *"};
40 auto S = "int" + std::to_string(BW) + "_t ";
41 return {S, S + "*"};
42 }
43 if (Ty->isPointerTy())
44 return {Flags & IRTArg::STRING ? "char *" : "void *", "void **"};
45 if (Ty->isFloatTy())
46 return {"float ", "float *"};
47 if (Ty->isDoubleTy())
48 return {"double ", "double *"};
49 return {"<>", "<>"};
50}
51
52/// Get the string representation of the C printf format of an argument with
53/// type \p Ty. The flags in \p Flags describe the properties of the argument.
54/// See IRTArg::IRArgFlagTy.
55static std::string getPrintfFormatString(Type *Ty, unsigned Flags) {
56 if (Ty->isIntegerTy()) {
57 if (Ty->getIntegerBitWidth() > 32) {
58 assert(Ty->getIntegerBitWidth() == 64);
59 return "%\" PRId64 \"";
60 }
61 return "%\" PRId32 \"";
62 }
63 if (Ty->isPointerTy())
64 return Flags & IRTArg::STRING ? "%s" : "%p";
65 if (Ty->isFloatTy())
66 return "%f";
67 if (Ty->isDoubleTy())
68 return "%lf";
69 return "<>";
70}
71
72std::pair<std::string, std::string> IRTCallDescription::createCBodies() const {
73 std::string DirectFormat = "printf(\"" + IO.getName().str() +
74 (IO.IP.isPRE() ? " pre" : " post") + " -- ";
75 std::string IndirectFormat = DirectFormat;
76 std::string DirectArg, IndirectArg, DirectReturnValue, IndirectReturnValue;
77
78 auto AddToFormats = [&](Twine S) {
79 DirectFormat += S.str();
80 IndirectFormat += S.str();
81 };
82 auto AddToArgs = [&](Twine S) {
83 DirectArg += S.str();
84 IndirectArg += S.str();
85 };
86 bool First = true;
87 for (auto &IRArg : IO.IRTArgs) {
88 if (!IRArg.Enabled)
89 continue;
90 if (!First)
91 AddToFormats(", ");
92 First = false;
93 AddToArgs(", " + IRArg.Name);
94 AddToFormats(IRArg.Name + ": ");
95 if (NumReplaceableArgs == 1 && (IRArg.Flags & IRTArg::REPLACABLE)) {
96 DirectReturnValue = IRArg.Name;
97 if (!isPotentiallyIndirect(IRArg))
98 IndirectReturnValue = IRArg.Name;
99 }
100
101 // Handle value pack arguments specially
102 if (IRArg.Flags & IRTArg::VALUE_PACK) {
103 DirectFormat += "[value pack at %p]";
104 IndirectFormat += "[value pack at %p]";
105 continue;
106 }
107
108 if (!isPotentiallyIndirect(IRArg)) {
109 AddToFormats(getPrintfFormatString(IRArg.Ty, IRArg.Flags));
110 } else {
111 DirectFormat += getPrintfFormatString(IRArg.Ty, IRArg.Flags);
112 IndirectFormat += "%p";
113 IndirectArg += "_ptr";
114 // Add the indirect argument size
115 if (!(IRArg.Flags & IRTArg::INDIRECT_HAS_SIZE)) {
116 IndirectFormat += ", " + IRArg.Name.str() + "_size: %\" PRId32 \"";
117 IndirectArg += ", " + IRArg.Name.str() + "_size";
118 }
119 }
120 }
121
122 std::string DirectBody = DirectFormat + "\\n\"" + DirectArg + ");\n";
123 std::string IndirectBody = IndirectFormat + "\\n\"" + IndirectArg + ");\n";
124
125 // Add value pack element printing
126 for (size_t ArgIdx = 0; ArgIdx < IO.IRTArgs.size(); ++ArgIdx) {
127 auto &IRArg = IO.IRTArgs[ArgIdx];
128 if (!IRArg.Enabled || !(IRArg.Flags & IRTArg::VALUE_PACK))
129 continue;
130
131 // Find the count parameter - it should be the previous enabled argument
132 std::string CountParam;
133 for (int PrevIdx = ArgIdx - 1; PrevIdx >= 0; --PrevIdx) {
134 if (IO.IRTArgs[PrevIdx].Enabled &&
135 IO.IRTArgs[PrevIdx].Name.equals_insensitive(
136 ("num_" + IRArg.Name).str())) {
137 CountParam = IO.IRTArgs[PrevIdx].Name.str();
138 break;
139 }
140 }
141
142 // If no count parameter found, use 0 (will skip iteration)
143 if (CountParam.empty())
144 CountParam = "0 /* count not enabled! */";
145
146 auto AddToBodies = [&](Twine T) {
147 DirectBody += T.str();
148 IndirectBody += T.str();
149 };
150
151 // Direct version: iterate through the value pack at the pointer
152 AddToBodies(" ValuePackIterator iter_" + IRArg.Name.str() + ";\n");
153 AddToBodies(" initValuePackIterator(&iter_" + IRArg.Name.str() + ", " +
154 IRArg.Name.str() + ", " + CountParam + ");\n");
155 AddToBodies(" while (iter_" + IRArg.Name.str() + ".index < iter_" +
156 IRArg.Name.str() + ".count) {\n");
157 AddToBodies(" ValuePackHeader header_" + IRArg.Name.str() +
158 " = getValuePackHeader(&iter_" + IRArg.Name.str() + ");\n");
159 AddToBodies(" const void *data_" + IRArg.Name.str() +
160 " = getValuePackData(&iter_" + IRArg.Name.str() + ");\n");
161 AddToBodies(" printf(\" [%" PRIu32 "] type=%s size=%" PRIu32
162 " data=%p\\n\", iter_" +
163 IRArg.Name.str() + ".index, getLLVMTypeIDName(header_" +
164 IRArg.Name.str() + ".type_id), header_" + IRArg.Name.str() +
165 ".size, data_" + IRArg.Name.str() + ");\n");
166 AddToBodies(" nextValuePack(&iter_" + IRArg.Name.str() + ");\n");
167 AddToBodies(" }\n");
168 }
169
170 if (RetTy)
171 IndirectReturnValue = DirectReturnValue = "0";
172 if (!DirectReturnValue.empty())
173 DirectBody += " return " + DirectReturnValue + ";\n";
174 if (!IndirectReturnValue.empty())
175 IndirectBody += " return " + IndirectReturnValue + ";\n";
176 return {DirectBody, IndirectBody};
177}
178
179std::pair<std::string, std::string>
181 SmallVector<std::string> DirectArgs, IndirectArgs;
182 std::string DirectRetTy = "void ", IndirectRetTy = "void ";
183 for (auto &IRArg : IO.IRTArgs) {
184 if (!IRArg.Enabled)
185 continue;
186 const auto &[DirectArgTy, IndirectArgTy] =
187 getAsCType(IRArg.Ty, IRArg.Flags);
188 std::string DirectArg = DirectArgTy + IRArg.Name.str();
189 std::string IndirectArg = IndirectArgTy + IRArg.Name.str() + "_ptr";
190 std::string IndirectArgSize = "int32_t " + IRArg.Name.str() + "_size";
191 DirectArgs.push_back(DirectArg);
192 if (NumReplaceableArgs == 1 && (IRArg.Flags & IRTArg::REPLACABLE)) {
193 DirectRetTy = DirectArgTy;
194 if (!isPotentiallyIndirect(IRArg))
195 IndirectRetTy = DirectArgTy;
196 }
197 if (!isPotentiallyIndirect(IRArg)) {
198 IndirectArgs.push_back(DirectArg);
199 } else {
200 IndirectArgs.push_back(IndirectArg);
201 if (!(IRArg.Flags & IRTArg::INDIRECT_HAS_SIZE))
202 IndirectArgs.push_back(IndirectArgSize);
203 }
204 }
205
206 auto DirectName =
207 IConf.getRTName(IO.IP.isPRE() ? "pre_" : "post_", IO.getName(), "");
208 auto IndirectName =
209 IConf.getRTName(IO.IP.isPRE() ? "pre_" : "post_", IO.getName(), "_ind");
210 auto MakeSignature = [&](std::string &RetTy, std::string &Name,
212 return RetTy + Name + "(" + join(Args, ", ") + ")";
213 };
214
215 if (RetTy) {
216 auto UserRetTy = getAsCType(RetTy, 0).first;
217 assert((DirectRetTy == UserRetTy || DirectRetTy == "void ") &&
218 (IndirectRetTy == UserRetTy || IndirectRetTy == "void ") &&
219 "Explicit return type but also implicit one!");
220 IndirectRetTy = DirectRetTy = UserRetTy;
221 }
223 return {"", MakeSignature(IndirectRetTy, IndirectName, IndirectArgs)};
225 return {MakeSignature(DirectRetTy, DirectName, DirectArgs), ""};
226 return {MakeSignature(DirectRetTy, DirectName, DirectArgs),
227 MakeSignature(IndirectRetTy, IndirectName, IndirectArgs)};
228}
229
231 StringRef HeaderFileName, LLVMContext &Ctx) {
232 if (HeaderFileName.empty())
233 return;
234
235 std::error_code EC;
236 raw_fd_ostream OS(HeaderFileName, EC);
237 if (EC) {
238 Ctx.emitError(
239 Twine("failed to open instrumentor runtime header file for writing: ") +
240 EC.message());
241 return;
242 }
243
244 StringRef Prefix = IConf.getRTName();
245
246 OS << InstrumentorRuntimeHelper;
247 OS << "\n// Generated with runtime prefix: " << Prefix << "\n";
248}
249
251 StringRef StubRuntimeName, LLVMContext &Ctx) {
252 if (StubRuntimeName.empty())
253 return;
254
255 std::error_code EC;
256 raw_fd_ostream OS(StubRuntimeName, EC);
257 if (EC) {
258 Ctx.emitError(
259 Twine("failed to open instrumentor stub runtime file for writing: ") +
260 EC.message());
261 return;
262 }
263
264 // Generate the header file alongside the stub
265 StringRef Prefix = IConf.getRTName();
266 std::string HeaderFileName = StubRuntimeName.str();
267 size_t DotPos = HeaderFileName.rfind('.');
268 if (DotPos != std::string::npos)
269 HeaderFileName = HeaderFileName.substr(0, DotPos);
270 HeaderFileName += ".h";
271 printRuntimeHeader(IConf, HeaderFileName, Ctx);
272
273 OS << "//===-- Instrumentor Runtime Stub "
274 "-----------------------------------------===//\n";
275 OS << "//\n";
276 OS << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
277 "Exceptions.\n";
278 OS << "// See https://llvm.org/LICENSE.txt for license information.\n";
279 OS << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n";
280 OS << "//\n";
281 OS << "//"
282 "===-------------------------------------------------------------------"
283 "---===//\n";
284 OS << "//\n";
285 OS << "// This file is auto-generated by the LLVM Instrumentor pass.\n";
286 OS << "// It provides stub implementations of instrumentation runtime "
287 "functions\n";
288 OS << "// that print human-readable information about instrumentation "
289 "events.\n";
290 OS << "//\n";
291 OS << "// Generated with runtime prefix: " << Prefix << "\n";
292 OS << "//\n";
293 OS << "//"
294 "===-------------------------------------------------------------------"
295 "---===//\n\n";
296 OS << "#include <inttypes.h>\n";
297 OS << "#include <stdint.h>\n";
298 OS << "#include <stdio.h>\n";
299 OS << "#include \"" << llvm::sys::path::filename(HeaderFileName) << "\"\n\n";
300 OS << "#ifdef __cplusplus\n";
301 OS << "extern \"C\" {\n";
302 OS << "#endif\n\n";
303
304 for (auto &ChoiceMap : IConf.IChoices) {
305 for (auto &[_, IO] : ChoiceMap) {
306 if (!IO->Enabled)
307 continue;
308 IRTCallDescription IRTCallDesc(*IO, IO->getRetTy(Ctx));
309 const auto Signatures = IRTCallDesc.createCSignature(IConf);
310 const auto Bodies = IRTCallDesc.createCBodies();
311 if (!Signatures.first.empty()) {
312 OS << Signatures.first << " {\n";
313 OS << " " << Bodies.first << "}\n\n";
314 }
315 if (!Signatures.second.empty()) {
316 OS << Signatures.second << " {\n";
317 OS << " " << Bodies.second << "}\n\n";
318 }
319 }
320 }
321
322 OS << "#ifdef __cplusplus\n";
323 OS << "}\n";
324 OS << "#endif\n";
325}
326
327} // end namespace instrumentor
328} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define _
#define T
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
A raw_ostream that writes to a file descriptor.
static std::string getPrintfFormatString(Type *Ty, unsigned Flags)
Get the string representation of the C printf format of an argument with type Ty.
void printRuntimeHeader(const InstrumentationConfig &IConf, StringRef HeaderFileName, LLVMContext &Ctx)
Print the runtime header file that provides helper structures and functions for reading data generate...
static std::pair< std::string, std::string > getAsCType(Type *Ty, unsigned Flags)
Get the string representation of an argument with type Ty.
void printRuntimeStub(const InstrumentationConfig &IConf, StringRef StubRuntimeName, LLVMContext &Ctx)
Print a runtime stub file with the implementation of the instrumentation runtime functions correspond...
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:594
This is an optimization pass for GlobalISel generic memory operations.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
Helper to represent an instrumentation runtime function that is related to an instrumentation opportu...
bool MightRequireIndirection
Whether any argument may require indirection.
std::pair< std::string, std::string > createCBodies() const
Create a string representation of the function definition in C.
Type * RetTy
The return type of the instrumentation function.
InstrumentationOpportunity & IO
The instrumentation opportunity which it is linked to.
std::pair< std::string, std::string > createCSignature(const InstrumentationConfig &IConf) const
Create a string representation of the function declaration in C.
unsigned NumReplaceableArgs
The number of arguments that can be replaced.
bool RequiresIndirection
Whether the function requires indirection in some argument.
bool isPotentiallyIndirect(IRTArg &IRTA) const
Return whether the function may have any indirect argument.
The class that contains the configuration for the instrumentor.
EnumeratedArray< MapVector< StringRef, InstrumentationOpportunity * >, InstrumentationLocation::KindTy > IChoices
The map registered instrumentation opportunities.
StringRef getRTName() const
Get the runtime prefix for the instrumentation runtime functions.