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
47 case Attribute::NoInline:
48 return F.hasFnAttribute(Attribute::AlwaysInline);
49
50 case Attribute::OptimizeNone:
51 return F.hasFnAttribute(Attribute::MinSize) ||
52 F.hasFnAttribute(Attribute::OptimizeForSize) ||
53 F.hasFnAttribute(Attribute::OptimizeForDebugging);
54
55 case Attribute::MinSize:
56 return F.hasFnAttribute(Attribute::OptimizeNone) ||
57 F.hasFnAttribute(Attribute::OptimizeForDebugging);
58
59 case Attribute::OptimizeForSize:
60 return F.hasFnAttribute(Attribute::OptimizeNone) ||
61 F.hasFnAttribute(Attribute::OptimizeForDebugging);
62
63 case Attribute::OptimizeForDebugging:
64 return F.hasFnAttribute(Attribute::OptimizeNone) ||
65 F.hasFnAttribute(Attribute::MinSize) ||
66 F.hasFnAttribute(Attribute::OptimizeForSize);
67
68 default:
69 return false;
70 }
71}
72
73/// If F has any forced attributes given on the command line, add them.
74/// If F has any forced remove attributes given on the command line, remove
75/// them. When both force and force-remove are given to a function, the latter
76/// takes precedence.
77static void forceAttributes(Function &F) {
78 auto ParseFunctionAndAttr = [&](StringRef S) {
79 StringRef AttributeText;
80 if (S.contains(':')) {
81 auto KV = StringRef(S).split(':');
82 if (KV.first != F.getName())
83 return Attribute::None;
84 AttributeText = KV.second;
85 } else {
86 AttributeText = S;
87 }
88 auto Kind = Attribute::getAttrKindFromName(AttributeText);
89 if (Kind == Attribute::None || !Attribute::canUseAsFnAttr(Kind)) {
90 LLVM_DEBUG(dbgs() << "ForcedAttribute: " << AttributeText
91 << " unknown or not a function attribute!\n");
92 }
93 return Kind;
94 };
95
96 for (const auto &S : ForceAttributes) {
97 auto Kind = ParseFunctionAndAttr(S);
98 if (Kind == Attribute::None || F.hasFnAttribute(Kind) ||
100 continue;
101 F.addFnAttr(Kind);
102 }
103
104 for (const auto &S : ForceRemoveAttributes) {
105 auto Kind = ParseFunctionAndAttr(S);
106 if (Kind == Attribute::None || !F.hasFnAttribute(Kind))
107 continue;
108 F.removeFnAttr(Kind);
109 }
110}
111
112static bool hasForceAttributes() {
113 return !ForceAttributes.empty() || !ForceRemoveAttributes.empty();
114}
115
118 const IPOOptions &Opts = getIPOOptions(M);
119 bool Changed = false;
120 if (!Opts.forceattrs_csv_path.empty()) {
121 auto BufferOrError = MemoryBuffer::getFileOrSTDIN(Opts.forceattrs_csv_path);
122 if (!BufferOrError) {
123 std::error_code EC = BufferOrError.getError();
124 M.getContext().emitError("cannot open CSV file: " + EC.message());
125 return PreservedAnalyses::all();
126 }
127
128 StringRef Buffer = BufferOrError.get()->getBuffer();
131 for (; !It.is_at_end(); ++It) {
132 auto SplitPair = It->split(',');
133 if (SplitPair.second.empty())
134 continue;
135 Function *Func = M.getFunction(SplitPair.first);
136 if (Func) {
137 if (Func->isDeclaration())
138 continue;
139 auto SecondSplitPair = SplitPair.second.split('=');
140 if (!SecondSplitPair.second.empty()) {
141 Func->addFnAttr(SecondSplitPair.first, SecondSplitPair.second);
142 Changed = true;
143 } else {
144 auto AttrKind = Attribute::getAttrKindFromName(SplitPair.second);
145 if (AttrKind != Attribute::None &&
146 Attribute::canUseAsFnAttr(AttrKind) &&
147 !hasConflictingFnAttr(AttrKind, *Func)) {
148 // TODO: There could be string attributes without a value, we should
149 // support those, too.
150 Func->addFnAttr(AttrKind);
151 Changed = true;
152 } else
153 errs() << "Cannot add " << SplitPair.second
154 << " as an attribute name.\n";
155 }
156 } else {
157 errs() << "Function in CSV file at line " << It.line_number()
158 << " does not exist.\n";
159 // TODO: `report_fatal_error at end of pass for missing functions.
160 continue;
161 }
162 }
163 }
164 if (hasForceAttributes()) {
165 for (Function &F : M.functions())
167 Changed = true;
168 }
169 // Just conservatively invalidate analyses if we've made any changes, this
170 // isn't likely to be important.
172}
static void forceAttributes(Function &F)
If F has any forced attributes given on the command line, add them.
static bool hasConflictingFnAttr(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:126
@ None
No attributes have been set.
Definition Attributes.h:128
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:36
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 &)