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
|
//===- 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)
report_fatal_error("Cannot open CSV file.");
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();
}
|