LLVM 24.0.0git
ForceFunctionAttrs.cpp
Go to the documentation of this file.
1//===- ForceFunctionAttrs.cpp - Force function attrs for debugging --------===//
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
10#include "IPOOptions.h"
11#include "llvm/IR/Function.h"
12#include "llvm/IR/Module.h"
14#include "llvm/Support/Debug.h"
18using namespace llvm;
19
20#define DEBUG_TYPE "forceattrs"
21
23 "force-attribute", cl::Hidden,
25 "Add an attribute to a function. This can be a "
26 "pair of 'function-name:attribute-name', to apply an attribute to a "
27 "specific function. For "
28 "example -force-attribute=foo:noinline. Specifying only an attribute "
29 "will apply the attribute to every function in the module. This "
30 "option can be specified multiple times."));
31
33 "force-remove-attribute", cl::Hidden,
34 cl::desc("Remove an attribute from a function. This can be a "
35 "pair of 'function-name:attribute-name' to remove an attribute "
36 "from a specific function. For "
37 "example -force-remove-attribute=foo:noinline. Specifying only an "
38 "attribute will remove the attribute from all functions in the "
39 "module. This "
40 "option can be specified multiple times."));
41
43 switch (Kind) {
44 case Attribute::AlwaysInline:
45 return F.hasFnAttribute(Attribute::NoInline) ||
46 F.hasFnAttribute(Attribute::OptimizeNone);
47
48 case Attribute::NoInline:
49 return F.hasFnAttribute(Attribute::AlwaysInline);
50
51 case Attribute::OptimizeNone:
52 return F.hasFnAttribute(Attribute::AlwaysInline) ||
53 F.hasFnAttribute(Attribute::MinSize) ||
54 F.hasFnAttribute(Attribute::OptimizeForSize) ||
55 F.hasFnAttribute(Attribute::OptimizeForDebugging);
56
57 case Attribute::MinSize:
58 return F.hasFnAttribute(Attribute::OptimizeNone) ||
59 F.hasFnAttribute(Attribute::OptimizeForDebugging);
60
61 case Attribute::OptimizeForSize:
62 return F.hasFnAttribute(Attribute::OptimizeNone) ||
63 F.hasFnAttribute(Attribute::OptimizeForDebugging);
64
65 case Attribute::OptimizeForDebugging:
66 return F.hasFnAttribute(Attribute::OptimizeNone) ||
67 F.hasFnAttribute(Attribute::MinSize) ||
68 F.hasFnAttribute(Attribute::OptimizeForSize);
69
70 default:
71 return false;
72 }
73}
74
76 if (Kind == Attribute::OptimizeNone && !F.hasFnAttribute(Attribute::NoInline))
77 F.addFnAttr(Attribute::NoInline);
78}
79
81 if (Kind == Attribute::NoInline && F.hasFnAttribute(Attribute::OptimizeNone))
82 return true;
83 return false;
84}
85
86/// If F has any forced attributes given on the command line, add them.
87/// If F has any forced remove attributes given on the command line, remove
88/// them. When both force and force-remove are given to a function, the latter
89/// takes precedence.
90static void forceAttributes(Function &F) {
91 auto ParseFunctionAndAttr = [&](StringRef S) {
92 StringRef AttributeText;
93 if (S.contains(':')) {
94 auto KV = StringRef(S).split(':');
95 if (KV.first != F.getName())
96 return Attribute::None;
97 AttributeText = KV.second;
98 } else {
99 AttributeText = S;
100 }
101 auto Kind = Attribute::getAttrKindFromName(AttributeText);
102 if (Kind == Attribute::None || !Attribute::canUseAsFnAttr(Kind)) {
103 LLVM_DEBUG(dbgs() << "ForcedAttribute: " << AttributeText
104 << " unknown or not a function attribute!\n");
105 }
106 return Kind;
107 };
108
109 for (const auto &S : ForceAttributes) {
110 auto Kind = ParseFunctionAndAttr(S);
111 if (Kind == Attribute::None || F.hasFnAttribute(Kind) ||
112 hasConflictingFnAttr(Kind, F))
113 continue;
114 addRequiredFnAttrs(Kind, F);
115 F.addFnAttr(Kind);
116 }
117
118 for (const auto &S : ForceRemoveAttributes) {
119 auto Kind = ParseFunctionAndAttr(S);
120 if (Kind == Attribute::None || !F.hasFnAttribute(Kind) ||
122 continue;
123 F.removeFnAttr(Kind);
124 }
125}
126
127static bool hasForceAttributes() {
128 return !ForceAttributes.empty() || !ForceRemoveAttributes.empty();
129}
130
133 const IPOOptions &Opts = getIPOOptions(M);
134 bool Changed = false;
135 if (!Opts.forceattrs_csv_path.empty()) {
136 auto BufferOrError = MemoryBuffer::getFileOrSTDIN(Opts.forceattrs_csv_path);
137 if (!BufferOrError) {
138 std::error_code EC = BufferOrError.getError();
139 M.getContext().emitError("cannot open CSV file: " + EC.message());
140 return PreservedAnalyses::all();
141 }
142
143 StringRef Buffer = BufferOrError.get()->getBuffer();
146 for (; !It.is_at_end(); ++It) {
147 auto SplitPair = It->split(',');
148 if (SplitPair.second.empty())
149 continue;
150 Function *Func = M.getFunction(SplitPair.first);
151 if (Func) {
152 if (Func->isDeclaration())
153 continue;
154 auto SecondSplitPair = SplitPair.second.split('=');
155 if (!SecondSplitPair.second.empty()) {
156 Func->addFnAttr(SecondSplitPair.first, SecondSplitPair.second);
157 Changed = true;
158 } else {
159 auto AttrKind = Attribute::getAttrKindFromName(SplitPair.second);
160 if (AttrKind != Attribute::None &&
161 Attribute::canUseAsFnAttr(AttrKind) &&
162 !hasConflictingFnAttr(AttrKind, *Func)) {
163 // TODO: There could be string attributes without a value, we should
164 // support those, too.
165 addRequiredFnAttrs(AttrKind, *Func);
166 Func->addFnAttr(AttrKind);
167 Changed = true;
168 } else
169 errs() << "Cannot add " << SplitPair.second
170 << " as an attribute name.\n";
171 }
172 } else {
173 errs() << "Function in CSV file at line " << It.line_number()
174 << " does not exist.\n";
175 // TODO: `report_fatal_error at end of pass for missing functions.
176 continue;
177 }
178 }
179 }
180 if (hasForceAttributes()) {
181 for (Function &F : M.functions())
183 Changed = true;
184 }
185 // Just conservatively invalidate analyses if we've made any changes, this
186 // isn't likely to be important.
188}
static void forceAttributes(Function &F)
If F has any forced attributes given on the command line, add them.
static bool wouldRemoveRequiredFnAttr(Attribute::AttrKind Kind, Function &F)
static bool hasConflictingFnAttr(Attribute::AttrKind Kind, Function &F)
static void addRequiredFnAttrs(Attribute::AttrKind Kind, Function &F)
static bool hasForceAttributes()
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."))
Super simple passes to force specific function attrs from the commandline into the IR for debugging p...
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define LLVM_DEBUG(...)
Definition Debug.h:119
static LLVM_ABI Attribute::AttrKind getAttrKindFromName(StringRef AttrName)
static LLVM_ABI bool canUseAsFnAttr(AttrKind Kind)
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
Definition Attributes.h:125
@ None
No attributes have been set.
Definition Attributes.h:127
This interface provides simple read-only access to a block of memory, and provides simple methods for...
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
A forward iterator which reads text lines from a buffer.
int64_t line_number() const
Return the current line number. May return any number at EOF.
bool is_at_end() const
Return true if we're an "end" iterator or have reached EOF.
This is an optimization pass for GlobalISel generic memory operations.
const IPOOptions & getIPOOptions(const LLVMContext &C)
Definition IPOOptions.h:33
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &)