• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "llvm_compiler_options.h"
17 #include "transforms/passes/inline_devirt.h"
18 #include "transforms/transform_utils.h"
19 #include <llvm/Analysis/CGSCCPassManager.h>
20 #include <llvm/ADT/PriorityWorklist.h>
21 
22 namespace ark::llvmbackend {
23 struct LLVMCompilerOptions;
24 }  // namespace ark::llvmbackend
25 
26 namespace ark::llvmbackend::passes {
27 
Create(LLVMArkInterface * arkInterface,const ark::llvmbackend::LLVMCompilerOptions * options)28 InlineDevirt InlineDevirt::Create(LLVMArkInterface *arkInterface, const ark::llvmbackend::LLVMCompilerOptions *options)
29 {
30     return InlineDevirt(arkInterface, options->doVirtualInline);
31 }
32 
ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions * options)33 bool InlineDevirt::ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions *options)
34 {
35     return options->inlining;
36 }
37 
InlineDevirt(LLVMArkInterface * arkInterface,bool doVirtualInline)38 InlineDevirt::InlineDevirt(LLVMArkInterface *arkInterface, bool doVirtualInline)
39     : arkInterface_ {arkInterface}, doVirtualInline_ {doVirtualInline}
40 {
41 }
42 
RunCheckExternal(ark::llvmbackend::passes::CheckExternal & externalPass)43 void InlineDevirt::RunCheckExternal(ark::llvmbackend::passes::CheckExternal &externalPass)
44 {
45     for (auto &node : *currentSCC_) {
46         auto &func = node.getFunction();
47         if (func.isDeclaration()) {
48             continue;
49         }
50         [[maybe_unused]] auto shouldRunExternal =
51             passInstrumentation_->runBeforePass<llvm::Function>(externalPass, func);
52         ASSERT(shouldRunExternal);
53 
54         auto preservedAnalysesExternal = externalPass.run(func, *functionAnalysisManager_);
55         passInstrumentation_->runAfterPass<llvm::Function>(externalPass, func, preservedAnalysesExternal);
56 
57         if (!preservedAnalysesExternal.areAllPreserved()) {
58             currentSCC_ = &llvm::updateCGAndAnalysisManagerForCGSCCPass(
59                 *callGraph_, *currentSCC_, node, *analysisManager_, *updateResult_, *functionAnalysisManager_);
60             functionAnalysisManager_->invalidate(func, preservedAnalysesExternal);
61             preservedAnalyses_.intersect(std::move(preservedAnalysesExternal));
62         }
63     }
64 }
65 
RunInlining(llvm::InlinerPass & inlinePass,llvm::SmallPtrSetImpl<llvm::Function * > & changedFunctions)66 bool InlineDevirt::RunInlining(llvm::InlinerPass &inlinePass, llvm::SmallPtrSetImpl<llvm::Function *> &changedFunctions)
67 {
68     [[maybe_unused]] auto shouldRunInlining =
69         passInstrumentation_->runBeforePass<llvm::LazyCallGraph::SCC>(inlinePass, *currentSCC_);
70     ASSERT(shouldRunInlining);
71 
72     auto preservedAnalysesInline = inlinePass.run(*currentSCC_, *analysisManager_, *callGraph_, *updateResult_);
73     passInstrumentation_->runAfterPass<llvm::LazyCallGraph::SCC>(inlinePass, *currentSCC_, preservedAnalysesInline);
74 
75     ASSERT(updateResult_->InvalidatedSCCs.count(currentSCC_) == 0);
76     if (!preservedAnalysesInline.areAllPreserved()) {
77         for (auto &f : *currentSCC_) {
78             changedFunctions.insert(&f.getFunction());
79         }
80         if (updateResult_->UpdatedC != nullptr && updateResult_->UpdatedC != currentSCC_) {
81             currentSCC_ = updateResult_->UpdatedC;
82         }
83         // Function analyses get invalidated in inlinePass.run
84         auto *resultFAMCP =
85             &analysisManager_->getResult<llvm::FunctionAnalysisManagerCGSCCProxy>(*currentSCC_, *callGraph_);
86         resultFAMCP->updateFAM(*functionAnalysisManager_);
87         analysisManager_->invalidate(*currentSCC_, preservedAnalysesInline);
88         preservedAnalyses_.intersect(std::move(preservedAnalysesInline));
89         return true;
90     }
91     return false;
92 }
93 
RunDevirt(ark::llvmbackend::passes::Devirt & devirtPass)94 bool InlineDevirt::RunDevirt(ark::llvmbackend::passes::Devirt &devirtPass)
95 {
96     auto devirtChanged = false;
97     for (auto &node : *currentSCC_) {
98         auto &func = node.getFunction();
99         if (func.isDeclaration()) {
100             continue;
101         }
102         [[maybe_unused]] auto shouldRunDevirt = passInstrumentation_->runBeforePass<llvm::Function>(devirtPass, func);
103         ASSERT(shouldRunDevirt);
104 
105         auto preservedAnalysesDevirt = devirtPass.run(func, *functionAnalysisManager_);
106         passInstrumentation_->runAfterPass<llvm::Function>(devirtPass, func, preservedAnalysesDevirt);
107 
108         if (!preservedAnalysesDevirt.areAllPreserved()) {
109             devirtChanged = true;
110             currentSCC_ = &llvm::updateCGAndAnalysisManagerForCGSCCPass(
111                 *callGraph_, *currentSCC_, node, *analysisManager_, *updateResult_, *functionAnalysisManager_);
112             functionAnalysisManager_->invalidate(func, preservedAnalysesDevirt);
113             preservedAnalyses_.intersect(std::move(preservedAnalysesDevirt));
114         }
115     }
116     return devirtChanged;
117 }
118 
run(llvm::LazyCallGraph::SCC & initialSCC,llvm::CGSCCAnalysisManager & analysisManager,llvm::LazyCallGraph & callGraph,llvm::CGSCCUpdateResult & updateResult)119 llvm::PreservedAnalyses InlineDevirt::run(llvm::LazyCallGraph::SCC &initialSCC,
120                                           llvm::CGSCCAnalysisManager &analysisManager, llvm::LazyCallGraph &callGraph,
121                                           llvm::CGSCCUpdateResult &updateResult)
122 {
123     passInstrumentation_ = &analysisManager.getResult<llvm::PassInstrumentationAnalysis>(initialSCC, callGraph);
124     functionAnalysisManager_ =
125         &analysisManager.getResult<llvm::FunctionAnalysisManagerCGSCCProxy>(initialSCC, callGraph).getManager();
126     preservedAnalyses_ = llvm::PreservedAnalyses::all();
127     updateResult_ = &updateResult;
128     currentSCC_ = &initialSCC;
129     analysisManager_ = &analysisManager;
130     callGraph_ = &callGraph;
131 
132     llvm::InlinerPass inlinePass(false);
133     ark::llvmbackend::passes::Devirt devirtPass(arkInterface_);
134     ark::llvmbackend::passes::CheckExternal externalPass;
135     static constexpr auto CHANGED_FUNCTIONS_SIZE = 16U;
136     llvm::SmallPtrSet<llvm::Function *, CHANGED_FUNCTIONS_SIZE> changedFunctions;
137 
138     static constexpr auto MAX_ITERATIONS = 8U;
139     for (uint32_t i = 0; i < MAX_ITERATIONS; i++) {
140         RunCheckExternal(externalPass);
141         auto inlineChanged = RunInlining(inlinePass, changedFunctions);
142         auto devirtChanged = doVirtualInline_ && RunDevirt(devirtPass);
143         // run CheckExternal and Devirt once more only if IR has changed
144         if (!inlineChanged && !devirtChanged) {
145             break;
146         }
147     }
148 
149     for (auto func : changedFunctions) {
150         for (auto user : func->users()) {
151             auto call = llvm::dyn_cast<llvm::CallInst>(user);
152             if (call != nullptr && call->getCalledFunction() == func && call->getFunction() != func &&
153                 arkInterface_->IsExternal(call)) {
154                 auto parent = call->getFunction();
155                 auto pnode = callGraph_->lookup(*parent);
156                 ASSERT(pnode != nullptr);
157                 auto pscc = callGraph_->lookupSCC(*pnode);
158                 ASSERT(pscc != nullptr);
159                 updateResult.CWorklist.insert(pscc);
160             }
161         }
162     }
163     return preservedAnalyses_;
164 }
165 
166 }  // namespace ark::llvmbackend::passes
167