//===- 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 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 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 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(); }