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
17#include "llvm/ADT/StringRef.h"
18#include "llvm/IR/LLVMContext.h"
20
21#include <cassert>
22#include <string>
23#include <system_error>
24
25namespace llvm {
26namespace instrumentor {
27
28/// Get the string representation of an argument with type \p Ty. Two strings
29/// are returned: one for direct arguments and another for indirect arguments.
30/// The flags in \p Flags describe the properties of the argument. See
31/// IRTArg::IRArgFlagTy.
32static std::pair<std::string, std::string> getAsCType(Type *Ty,
33 unsigned Flags) {
34 if (Ty->isIntegerTy()) {
35 auto BW = Ty->getIntegerBitWidth();
36 if (BW == 1)
37 return {"bool ", "bool *"};
38 auto S = "int" + std::to_string(BW) + "_t ";
39 return {S, S + "*"};
40 }
41 if (Ty->isPointerTy())
42 return {Flags & IRTArg::STRING ? "char *" : "void *", "void **"};
43 if (Ty->isFloatTy())
44 return {"float ", "float *"};
45 if (Ty->isDoubleTy())
46 return {"double ", "double *"};
47 return {"<>", "<>"};
48}
49
50/// Get the string representation of the C printf format of an argument with
51/// type \p Ty. The flags in \p Flags describe the properties of the argument.
52/// See IRTArg::IRArgFlagTy.
53static std::string getPrintfFormatString(Type *Ty, unsigned Flags) {
54 if (Ty->isIntegerTy()) {
55 if (Ty->getIntegerBitWidth() > 32) {
56 assert(Ty->getIntegerBitWidth() == 64);
57 return "%lli";
58 }
59 return "%i";
60 }
61 if (Ty->isPointerTy())
62 return Flags & IRTArg::STRING ? "%s" : "%p";
63 if (Ty->isFloatTy())
64 return "%f";
65 if (Ty->isDoubleTy())
66 return "%lf";
67 return "<>";
68}
69
70std::pair<std::string, std::string> IRTCallDescription::createCBodies() const {
71 std::string DirectFormat = "printf(\"" + IO.getName().str() +
72 (IO.IP.isPRE() ? " pre" : " post") + " -- ";
73 std::string IndirectFormat = DirectFormat;
74 std::string DirectArg, IndirectArg, DirectReturnValue, IndirectReturnValue;
75
76 auto AddToFormats = [&](Twine S) {
77 DirectFormat += S.str();
78 IndirectFormat += S.str();
79 };
80 auto AddToArgs = [&](Twine S) {
81 DirectArg += S.str();
82 IndirectArg += S.str();
83 };
84 bool First = true;
85 for (auto &IRArg : IO.IRTArgs) {
86 if (!IRArg.Enabled)
87 continue;
88 if (!First)
89 AddToFormats(", ");
90 First = false;
91 AddToArgs(", " + IRArg.Name);
92 AddToFormats(IRArg.Name + ": ");
93 if (NumReplaceableArgs == 1 && (IRArg.Flags & IRTArg::REPLACABLE)) {
94 DirectReturnValue = IRArg.Name;
95 if (!isPotentiallyIndirect(IRArg))
96 IndirectReturnValue = IRArg.Name;
97 }
98 if (!isPotentiallyIndirect(IRArg)) {
99 AddToFormats(getPrintfFormatString(IRArg.Ty, IRArg.Flags));
100 } else {
101 DirectFormat += getPrintfFormatString(IRArg.Ty, IRArg.Flags);
102 IndirectFormat += "%p";
103 IndirectArg += "_ptr";
104 // Add the indirect argument size
105 if (!(IRArg.Flags & IRTArg::INDIRECT_HAS_SIZE)) {
106 IndirectFormat += ", " + IRArg.Name.str() + "_size: %i";
107 IndirectArg += ", " + IRArg.Name.str() + "_size";
108 }
109 }
110 }
111
112 std::string DirectBody = DirectFormat + "\\n\"" + DirectArg + ");\n";
113 std::string IndirectBody = IndirectFormat + "\\n\"" + IndirectArg + ");\n";
114 if (RetTy)
115 IndirectReturnValue = DirectReturnValue = "0";
116 if (!DirectReturnValue.empty())
117 DirectBody += " return " + DirectReturnValue + ";\n";
118 if (!IndirectReturnValue.empty())
119 IndirectBody += " return " + IndirectReturnValue + ";\n";
120 return {DirectBody, IndirectBody};
121}
122
123std::pair<std::string, std::string>
125 SmallVector<std::string> DirectArgs, IndirectArgs;
126 std::string DirectRetTy = "void ", IndirectRetTy = "void ";
127 for (auto &IRArg : IO.IRTArgs) {
128 if (!IRArg.Enabled)
129 continue;
130 const auto &[DirectArgTy, IndirectArgTy] =
131 getAsCType(IRArg.Ty, IRArg.Flags);
132 std::string DirectArg = DirectArgTy + IRArg.Name.str();
133 std::string IndirectArg = IndirectArgTy + IRArg.Name.str() + "_ptr";
134 std::string IndirectArgSize = "int32_t " + IRArg.Name.str() + "_size";
135 DirectArgs.push_back(DirectArg);
136 if (NumReplaceableArgs == 1 && (IRArg.Flags & IRTArg::REPLACABLE)) {
137 DirectRetTy = DirectArgTy;
138 if (!isPotentiallyIndirect(IRArg))
139 IndirectRetTy = DirectArgTy;
140 }
141 if (!isPotentiallyIndirect(IRArg)) {
142 IndirectArgs.push_back(DirectArg);
143 } else {
144 IndirectArgs.push_back(IndirectArg);
145 if (!(IRArg.Flags & IRTArg::INDIRECT_HAS_SIZE))
146 IndirectArgs.push_back(IndirectArgSize);
147 }
148 }
149
150 auto DirectName =
151 IConf.getRTName(IO.IP.isPRE() ? "pre_" : "post_", IO.getName(), "");
152 auto IndirectName =
153 IConf.getRTName(IO.IP.isPRE() ? "pre_" : "post_", IO.getName(), "_ind");
154 auto MakeSignature = [&](std::string &RetTy, std::string &Name,
156 return RetTy + Name + "(" + join(Args, ", ") + ")";
157 };
158
159 if (RetTy) {
160 auto UserRetTy = getAsCType(RetTy, 0).first;
161 assert((DirectRetTy == UserRetTy || DirectRetTy == "void ") &&
162 (IndirectRetTy == UserRetTy || IndirectRetTy == "void ") &&
163 "Explicit return type but also implicit one!");
164 IndirectRetTy = DirectRetTy = UserRetTy;
165 }
167 return {"", MakeSignature(IndirectRetTy, IndirectName, IndirectArgs)};
169 return {MakeSignature(DirectRetTy, DirectName, DirectArgs), ""};
170 return {MakeSignature(DirectRetTy, DirectName, DirectArgs),
171 MakeSignature(IndirectRetTy, IndirectName, IndirectArgs)};
172}
173
175 StringRef StubRuntimeName, LLVMContext &Ctx) {
176 if (StubRuntimeName.empty())
177 return;
178
179 std::error_code EC;
180 raw_fd_ostream OS(StubRuntimeName, EC);
181 if (EC) {
182 Ctx.emitError(
183 Twine("failed to open instrumentor stub runtime file for writing: ") +
184 EC.message());
185 return;
186 }
187
188 OS << "// LLVM Instrumentor stub runtime\n\n";
189 OS << "#include <stdint.h>\n";
190 OS << "#include <stdio.h>\n\n";
191
192 for (auto &ChoiceMap : IConf.IChoices) {
193 for (auto &[_, IO] : ChoiceMap) {
194 if (!IO->Enabled)
195 continue;
196 IRTCallDescription IRTCallDesc(*IO, IO->getRetTy(Ctx));
197 const auto Signatures = IRTCallDesc.createCSignature(IConf);
198 const auto Bodies = IRTCallDesc.createCBodies();
199 if (!Signatures.first.empty()) {
200 OS << Signatures.first << " {\n";
201 OS << " " << Bodies.first << "}\n\n";
202 }
203 if (!Signatures.second.empty()) {
204 OS << Signatures.second << " {\n";
205 OS << " " << Bodies.second << "}\n\n";
206 }
207 }
208 }
209}
210
211} // end namespace instrumentor
212} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define _
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:55
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:140
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.
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...
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.
StringRef getRTName() const
Get the runtime prefix for the instrumentation runtime functions.
EnumeratedArray< StringMap< InstrumentationOpportunity * >, InstrumentationLocation::KindTy > IChoices
The map registered instrumentation opportunities.