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:56
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.
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.
EnumeratedArray< MapVector< StringRef, InstrumentationOpportunity * >, InstrumentationLocation::KindTy > IChoices
The map registered instrumentation opportunities.
StringRef getRTName() const
Get the runtime prefix for the instrumentation runtime functions.