1 //===- InferFunctionAttrs.cpp - Infer implicit function attributes --------===// 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/InferFunctionAttrs.h" 10 #include "llvm/Analysis/TargetLibraryInfo.h" 11 #include "llvm/IR/Function.h" 12 #include "llvm/IR/LLVMContext.h" 13 #include "llvm/IR/Module.h" 14 #include "llvm/InitializePasses.h" 15 #include "llvm/Support/Debug.h" 16 #include "llvm/Support/raw_ostream.h" 17 #include "llvm/Transforms/Utils/BuildLibCalls.h" 18 using namespace llvm; 19 20 #define DEBUG_TYPE "inferattrs" 21 22 /// If we can infer one attribute from another on the declaration of a 23 /// function, explicitly materialize the maximal set for readability in the IR. 24 /// Doing this also allows our CGSCC inference to avoid needing to duplicate 25 /// this logic on all calls to declarations (as declarations aren't explicitly 26 /// visited by CGSCC passes in the new pass manager.) 27 static bool inferAttributesFromOthers(Function &F) { 28 // Note: We explicitly check for attributes rather than using cover functions 29 // because some of the cover functions include the logic being implemented. 30 31 bool Changed = false; 32 // readnone + not convergent implies nosync 33 if (!F.hasFnAttribute(Attribute::NoSync) && 34 F.doesNotAccessMemory() && !F.isConvergent()) { 35 F.setNoSync(); 36 Changed = true; 37 } 38 39 // readonly implies nofree 40 if (!F.hasFnAttribute(Attribute::NoFree) && F.onlyReadsMemory()) { 41 F.setDoesNotFreeMemory(); 42 Changed = true; 43 } 44 45 // willreturn implies mustprogress 46 if (!F.hasFnAttribute(Attribute::MustProgress) && F.willReturn()) { 47 F.setMustProgress(); 48 Changed = true; 49 } 50 51 // TODO: There are a bunch of cases of restrictive memory effects we 52 // can infer by inspecting arguments of argmemonly-ish functions. 53 54 return Changed; 55 } 56 57 static bool inferAllPrototypeAttributes( 58 Module &M, function_ref<TargetLibraryInfo &(Function &)> GetTLI) { 59 bool Changed = false; 60 61 for (Function &F : M.functions()) 62 // We only infer things using the prototype and the name; we don't need 63 // definitions. 64 if (F.isDeclaration() && !F.hasOptNone()) { 65 Changed |= inferLibFuncAttributes(F, GetTLI(F)); 66 Changed |= inferAttributesFromOthers(F); 67 } 68 69 return Changed; 70 } 71 72 PreservedAnalyses InferFunctionAttrsPass::run(Module &M, 73 ModuleAnalysisManager &AM) { 74 FunctionAnalysisManager &FAM = 75 AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 76 auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & { 77 return FAM.getResult<TargetLibraryAnalysis>(F); 78 }; 79 80 if (!inferAllPrototypeAttributes(M, GetTLI)) 81 // If we didn't infer anything, preserve all analyses. 82 return PreservedAnalyses::all(); 83 84 // Otherwise, we may have changed fundamental function attributes, so clear 85 // out all the passes. 86 return PreservedAnalyses::none(); 87 } 88 89 namespace { 90 struct InferFunctionAttrsLegacyPass : public ModulePass { 91 static char ID; // Pass identification, replacement for typeid 92 InferFunctionAttrsLegacyPass() : ModulePass(ID) { 93 initializeInferFunctionAttrsLegacyPassPass( 94 *PassRegistry::getPassRegistry()); 95 } 96 97 void getAnalysisUsage(AnalysisUsage &AU) const override { 98 AU.addRequired<TargetLibraryInfoWrapperPass>(); 99 } 100 101 bool runOnModule(Module &M) override { 102 if (skipModule(M)) 103 return false; 104 105 auto GetTLI = [this](Function &F) -> TargetLibraryInfo & { 106 return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); 107 }; 108 return inferAllPrototypeAttributes(M, GetTLI); 109 } 110 }; 111 } 112 113 char InferFunctionAttrsLegacyPass::ID = 0; 114 INITIALIZE_PASS_BEGIN(InferFunctionAttrsLegacyPass, "inferattrs", 115 "Infer set function attributes", false, false) 116 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) 117 INITIALIZE_PASS_END(InferFunctionAttrsLegacyPass, "inferattrs", 118 "Infer set function attributes", false, false) 119 120 Pass *llvm::createInferFunctionAttrsLegacyPass() { 121 return new InferFunctionAttrsLegacyPass(); 122 } 123