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 9 #include "llvm/Transforms/IPO/ForceFunctionAttrs.h" 10 #include "llvm/IR/Function.h" 11 #include "llvm/IR/LLVMContext.h" 12 #include "llvm/IR/Module.h" 13 #include "llvm/InitializePasses.h" 14 #include "llvm/Pass.h" 15 #include "llvm/Support/CommandLine.h" 16 #include "llvm/Support/Debug.h" 17 #include "llvm/Support/raw_ostream.h" 18 using namespace llvm; 19 20 #define DEBUG_TYPE "forceattrs" 21 22 static cl::list<std::string> 23 ForceAttributes("force-attribute", cl::Hidden, 24 cl::desc("Add an attribute to a function. This should be a " 25 "pair of 'function-name:attribute-name', for " 26 "example -force-attribute=foo:noinline. This " 27 "option can be specified multiple times.")); 28 29 static cl::list<std::string> ForceRemoveAttributes( 30 "force-remove-attribute", cl::Hidden, 31 cl::desc("Remove an attribute from a function. This should be a " 32 "pair of 'function-name:attribute-name', for " 33 "example -force-remove-attribute=foo:noinline. This " 34 "option can be specified multiple times.")); 35 36 /// If F has any forced attributes given on the command line, add them. 37 /// If F has any forced remove attributes given on the command line, remove 38 /// them. When both force and force-remove are given to a function, the latter 39 /// takes precedence. 40 static void forceAttributes(Function &F) { 41 auto ParseFunctionAndAttr = [&](StringRef S) { 42 auto Kind = Attribute::None; 43 auto KV = StringRef(S).split(':'); 44 if (KV.first != F.getName()) 45 return Kind; 46 Kind = Attribute::getAttrKindFromName(KV.second); 47 if (Kind == Attribute::None || !Attribute::canUseAsFnAttr(Kind)) { 48 LLVM_DEBUG(dbgs() << "ForcedAttribute: " << KV.second 49 << " unknown or not a function attribute!\n"); 50 } 51 return Kind; 52 }; 53 54 for (const auto &S : ForceAttributes) { 55 auto Kind = ParseFunctionAndAttr(S); 56 if (Kind == Attribute::None || F.hasFnAttribute(Kind)) 57 continue; 58 F.addFnAttr(Kind); 59 } 60 61 for (const auto &S : ForceRemoveAttributes) { 62 auto Kind = ParseFunctionAndAttr(S); 63 if (Kind == Attribute::None || !F.hasFnAttribute(Kind)) 64 continue; 65 F.removeFnAttr(Kind); 66 } 67 } 68 69 static bool hasForceAttributes() { 70 return !ForceAttributes.empty() || !ForceRemoveAttributes.empty(); 71 } 72 73 PreservedAnalyses ForceFunctionAttrsPass::run(Module &M, 74 ModuleAnalysisManager &) { 75 if (!hasForceAttributes()) 76 return PreservedAnalyses::all(); 77 78 for (Function &F : M.functions()) 79 forceAttributes(F); 80 81 // Just conservatively invalidate analyses, this isn't likely to be important. 82 return PreservedAnalyses::none(); 83 } 84 85 namespace { 86 struct ForceFunctionAttrsLegacyPass : public ModulePass { 87 static char ID; // Pass identification, replacement for typeid 88 ForceFunctionAttrsLegacyPass() : ModulePass(ID) { 89 initializeForceFunctionAttrsLegacyPassPass( 90 *PassRegistry::getPassRegistry()); 91 } 92 93 bool runOnModule(Module &M) override { 94 if (!hasForceAttributes()) 95 return false; 96 97 for (Function &F : M.functions()) 98 forceAttributes(F); 99 100 // Conservatively assume we changed something. 101 return true; 102 } 103 }; 104 } 105 106 char ForceFunctionAttrsLegacyPass::ID = 0; 107 INITIALIZE_PASS(ForceFunctionAttrsLegacyPass, "forceattrs", 108 "Force set function attributes", false, false) 109 110 Pass *llvm::createForceFunctionAttrsLegacyPass() { 111 return new ForceFunctionAttrsLegacyPass(); 112 } 113