10b57cec5SDimitry Andric //===- ForceFunctionAttrs.cpp - Force function attrs for debugging --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
100b57cec5SDimitry Andric #include "llvm/IR/Function.h"
110b57cec5SDimitry Andric #include "llvm/IR/Module.h"
12480093f4SDimitry Andric #include "llvm/Support/CommandLine.h"
130b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
14*5f757f3fSDimitry Andric #include "llvm/Support/LineIterator.h"
15*5f757f3fSDimitry Andric #include "llvm/Support/MemoryBuffer.h"
160b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
170b57cec5SDimitry Andric using namespace llvm;
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric #define DEBUG_TYPE "forceattrs"
200b57cec5SDimitry Andric
21*5f757f3fSDimitry Andric static cl::list<std::string> ForceAttributes(
22*5f757f3fSDimitry Andric "force-attribute", cl::Hidden,
23*5f757f3fSDimitry Andric cl::desc(
24*5f757f3fSDimitry Andric "Add an attribute to a function. This can be a "
25*5f757f3fSDimitry Andric "pair of 'function-name:attribute-name', to apply an attribute to a "
26*5f757f3fSDimitry Andric "specific function. For "
27*5f757f3fSDimitry Andric "example -force-attribute=foo:noinline. Specifying only an attribute "
28*5f757f3fSDimitry Andric "will apply the attribute to every function in the module. This "
290b57cec5SDimitry Andric "option can be specified multiple times."));
300b57cec5SDimitry Andric
31e8d8bef9SDimitry Andric static cl::list<std::string> ForceRemoveAttributes(
32e8d8bef9SDimitry Andric "force-remove-attribute", cl::Hidden,
33*5f757f3fSDimitry Andric cl::desc("Remove an attribute from a function. This can be a "
34*5f757f3fSDimitry Andric "pair of 'function-name:attribute-name' to remove an attribute "
35*5f757f3fSDimitry Andric "from a specific function. For "
36*5f757f3fSDimitry Andric "example -force-remove-attribute=foo:noinline. Specifying only an "
37*5f757f3fSDimitry Andric "attribute will remove the attribute from all functions in the "
38*5f757f3fSDimitry Andric "module. This "
39e8d8bef9SDimitry Andric "option can be specified multiple times."));
40e8d8bef9SDimitry Andric
41*5f757f3fSDimitry Andric static cl::opt<std::string> CSVFilePath(
42*5f757f3fSDimitry Andric "forceattrs-csv-path", cl::Hidden,
43*5f757f3fSDimitry Andric cl::desc(
44*5f757f3fSDimitry Andric "Path to CSV file containing lines of function names and attributes to "
45*5f757f3fSDimitry Andric "add to them in the form of `f1,attr1` or `f2,attr2=str`."));
46*5f757f3fSDimitry Andric
470b57cec5SDimitry Andric /// If F has any forced attributes given on the command line, add them.
48e8d8bef9SDimitry Andric /// If F has any forced remove attributes given on the command line, remove
49e8d8bef9SDimitry Andric /// them. When both force and force-remove are given to a function, the latter
50e8d8bef9SDimitry Andric /// takes precedence.
forceAttributes(Function & F)51e8d8bef9SDimitry Andric static void forceAttributes(Function &F) {
52e8d8bef9SDimitry Andric auto ParseFunctionAndAttr = [&](StringRef S) {
53*5f757f3fSDimitry Andric StringRef AttributeText;
54*5f757f3fSDimitry Andric if (S.contains(':')) {
550b57cec5SDimitry Andric auto KV = StringRef(S).split(':');
560b57cec5SDimitry Andric if (KV.first != F.getName())
57*5f757f3fSDimitry Andric return Attribute::None;
58*5f757f3fSDimitry Andric AttributeText = KV.second;
59*5f757f3fSDimitry Andric } else {
60*5f757f3fSDimitry Andric AttributeText = S;
61*5f757f3fSDimitry Andric }
62*5f757f3fSDimitry Andric auto Kind = Attribute::getAttrKindFromName(AttributeText);
63fe6060f1SDimitry Andric if (Kind == Attribute::None || !Attribute::canUseAsFnAttr(Kind)) {
64*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "ForcedAttribute: " << AttributeText
65fe6060f1SDimitry Andric << " unknown or not a function attribute!\n");
660b57cec5SDimitry Andric }
67e8d8bef9SDimitry Andric return Kind;
68e8d8bef9SDimitry Andric };
69e8d8bef9SDimitry Andric
70349cc55cSDimitry Andric for (const auto &S : ForceAttributes) {
71e8d8bef9SDimitry Andric auto Kind = ParseFunctionAndAttr(S);
72e8d8bef9SDimitry Andric if (Kind == Attribute::None || F.hasFnAttribute(Kind))
730b57cec5SDimitry Andric continue;
740b57cec5SDimitry Andric F.addFnAttr(Kind);
750b57cec5SDimitry Andric }
76e8d8bef9SDimitry Andric
77349cc55cSDimitry Andric for (const auto &S : ForceRemoveAttributes) {
78e8d8bef9SDimitry Andric auto Kind = ParseFunctionAndAttr(S);
79e8d8bef9SDimitry Andric if (Kind == Attribute::None || !F.hasFnAttribute(Kind))
80e8d8bef9SDimitry Andric continue;
81e8d8bef9SDimitry Andric F.removeFnAttr(Kind);
82e8d8bef9SDimitry Andric }
83e8d8bef9SDimitry Andric }
84e8d8bef9SDimitry Andric
hasForceAttributes()85e8d8bef9SDimitry Andric static bool hasForceAttributes() {
86e8d8bef9SDimitry Andric return !ForceAttributes.empty() || !ForceRemoveAttributes.empty();
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
run(Module & M,ModuleAnalysisManager &)890b57cec5SDimitry Andric PreservedAnalyses ForceFunctionAttrsPass::run(Module &M,
900b57cec5SDimitry Andric ModuleAnalysisManager &) {
91*5f757f3fSDimitry Andric bool Changed = false;
92*5f757f3fSDimitry Andric if (!CSVFilePath.empty()) {
93*5f757f3fSDimitry Andric auto BufferOrError = MemoryBuffer::getFileOrSTDIN(CSVFilePath);
94*5f757f3fSDimitry Andric if (!BufferOrError)
95*5f757f3fSDimitry Andric report_fatal_error("Cannot open CSV file.");
96*5f757f3fSDimitry Andric StringRef Buffer = BufferOrError.get()->getBuffer();
97*5f757f3fSDimitry Andric auto MemoryBuffer = MemoryBuffer::getMemBuffer(Buffer);
98*5f757f3fSDimitry Andric line_iterator It(*MemoryBuffer);
99*5f757f3fSDimitry Andric for (; !It.is_at_end(); ++It) {
100*5f757f3fSDimitry Andric auto SplitPair = It->split(',');
101*5f757f3fSDimitry Andric if (SplitPair.second.empty())
102*5f757f3fSDimitry Andric continue;
103*5f757f3fSDimitry Andric Function *Func = M.getFunction(SplitPair.first);
104*5f757f3fSDimitry Andric if (Func) {
105*5f757f3fSDimitry Andric if (Func->isDeclaration())
106*5f757f3fSDimitry Andric continue;
107*5f757f3fSDimitry Andric auto SecondSplitPair = SplitPair.second.split('=');
108*5f757f3fSDimitry Andric if (!SecondSplitPair.second.empty()) {
109*5f757f3fSDimitry Andric Func->addFnAttr(SecondSplitPair.first, SecondSplitPair.second);
110*5f757f3fSDimitry Andric Changed = true;
111*5f757f3fSDimitry Andric } else {
112*5f757f3fSDimitry Andric auto AttrKind = Attribute::getAttrKindFromName(SplitPair.second);
113*5f757f3fSDimitry Andric if (AttrKind != Attribute::None &&
114*5f757f3fSDimitry Andric Attribute::canUseAsFnAttr(AttrKind)) {
115*5f757f3fSDimitry Andric // TODO: There could be string attributes without a value, we should
116*5f757f3fSDimitry Andric // support those, too.
117*5f757f3fSDimitry Andric Func->addFnAttr(AttrKind);
118*5f757f3fSDimitry Andric Changed = true;
119*5f757f3fSDimitry Andric } else
120*5f757f3fSDimitry Andric errs() << "Cannot add " << SplitPair.second
121*5f757f3fSDimitry Andric << " as an attribute name.\n";
122*5f757f3fSDimitry Andric }
123*5f757f3fSDimitry Andric } else {
124*5f757f3fSDimitry Andric errs() << "Function in CSV file at line " << It.line_number()
125*5f757f3fSDimitry Andric << " does not exist.\n";
126*5f757f3fSDimitry Andric // TODO: `report_fatal_error at end of pass for missing functions.
127*5f757f3fSDimitry Andric continue;
128*5f757f3fSDimitry Andric }
129*5f757f3fSDimitry Andric }
130*5f757f3fSDimitry Andric }
131*5f757f3fSDimitry Andric if (hasForceAttributes()) {
1320b57cec5SDimitry Andric for (Function &F : M.functions())
133e8d8bef9SDimitry Andric forceAttributes(F);
134*5f757f3fSDimitry Andric Changed = true;
135*5f757f3fSDimitry Andric }
136*5f757f3fSDimitry Andric // Just conservatively invalidate analyses if we've made any changes, this
137*5f757f3fSDimitry Andric // isn't likely to be important.
138*5f757f3fSDimitry Andric return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
1390b57cec5SDimitry Andric }
140