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. 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 85e8d8bef9SDimitry Andric static bool hasForceAttributes() { 86e8d8bef9SDimitry Andric return !ForceAttributes.empty() || !ForceRemoveAttributes.empty(); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 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