1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
//===- ForceFunctionAttrs.cpp - Force function attrs for debugging --------===//
//
// 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/ForceFunctionAttrs.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "forceattrs"
static cl::list<std::string> ForceAttributes(
"force-attribute", cl::Hidden,
cl::desc(
"Add an attribute to a function. This can be a "
"pair of 'function-name:attribute-name', to apply an attribute to a "
"specific function. For "
"example -force-attribute=foo:noinline. Specifying only an attribute "
"will apply the attribute to every function in the module. This "
"option can be specified multiple times."));
static cl::list<std::string> ForceRemoveAttributes(
"force-remove-attribute", cl::Hidden,
cl::desc("Remove an attribute from a function. This can be a "
"pair of 'function-name:attribute-name' to remove an attribute "
"from a specific function. For "
"example -force-remove-attribute=foo:noinline. Specifying only an "
"attribute will remove the attribute from all functions in the "
"module. This "
"option can be specified multiple times."));
static cl::opt<std::string> CSVFilePath(
"forceattrs-csv-path", cl::Hidden,
cl::desc(
"Path to CSV file containing lines of function names and attributes to "
"add to them in the form of `f1,attr1` or `f2,attr2=str`."));
/// If F has any forced attributes given on the command line, add them.
/// If F has any forced remove attributes given on the command line, remove
/// them. When both force and force-remove are given to a function, the latter
/// takes precedence.
static void forceAttributes(Function &F) {
auto ParseFunctionAndAttr = [&](StringRef S) {
StringRef AttributeText;
if (S.contains(':')) {
auto KV = StringRef(S).split(':');
if (KV.first != F.getName())
return Attribute::None;
AttributeText = KV.second;
} else {
AttributeText = S;
}
auto Kind = Attribute::getAttrKindFromName(AttributeText);
if (Kind == Attribute::None || !Attribute::canUseAsFnAttr(Kind)) {
LLVM_DEBUG(dbgs() << "ForcedAttribute: " << AttributeText
<< " unknown or not a function attribute!\n");
}
return Kind;
};
for (const auto &S : ForceAttributes) {
auto Kind = ParseFunctionAndAttr(S);
if (Kind == Attribute::None || F.hasFnAttribute(Kind))
continue;
F.addFnAttr(Kind);
}
for (const auto &S : ForceRemoveAttributes) {
auto Kind = ParseFunctionAndAttr(S);
if (Kind == Attribute::None || !F.hasFnAttribute(Kind))
continue;
F.removeFnAttr(Kind);
}
}
static bool hasForceAttributes() {
return !ForceAttributes.empty() || !ForceRemoveAttributes.empty();
}
PreservedAnalyses ForceFunctionAttrsPass::run(Module &M,
ModuleAnalysisManager &) {
bool Changed = false;
if (!CSVFilePath.empty()) {
auto BufferOrError = MemoryBuffer::getFileOrSTDIN(CSVFilePath);
if (!BufferOrError) {
std::error_code EC = BufferOrError.getError();
M.getContext().emitError("cannot open CSV file: " + EC.message());
return PreservedAnalyses::all();
}
StringRef Buffer = BufferOrError.get()->getBuffer();
auto MemoryBuffer = MemoryBuffer::getMemBuffer(Buffer);
line_iterator It(*MemoryBuffer);
for (; !It.is_at_end(); ++It) {
auto SplitPair = It->split(',');
if (SplitPair.second.empty())
continue;
Function *Func = M.getFunction(SplitPair.first);
if (Func) {
if (Func->isDeclaration())
continue;
auto SecondSplitPair = SplitPair.second.split('=');
if (!SecondSplitPair.second.empty()) {
Func->addFnAttr(SecondSplitPair.first, SecondSplitPair.second);
Changed = true;
} else {
auto AttrKind = Attribute::getAttrKindFromName(SplitPair.second);
if (AttrKind != Attribute::None &&
Attribute::canUseAsFnAttr(AttrKind)) {
// TODO: There could be string attributes without a value, we should
// support those, too.
Func->addFnAttr(AttrKind);
Changed = true;
} else
errs() << "Cannot add " << SplitPair.second
<< " as an attribute name.\n";
}
} else {
errs() << "Function in CSV file at line " << It.line_number()
<< " does not exist.\n";
// TODO: `report_fatal_error at end of pass for missing functions.
continue;
}
}
}
if (hasForceAttributes()) {
for (Function &F : M.functions())
forceAttributes(F);
Changed = true;
}
// Just conservatively invalidate analyses if we've made any changes, this
// isn't likely to be important.
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
}
|