• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 "ark_inlining.h"
17 #include "llvm_compiler_options.h"
18 
19 #include <llvm/Analysis/InlineAdvisor.h>
20 #include <llvm/Analysis/ReplayInlineAdvisor.h>
21 
22 #include <llvm/IR/InstIterator.h>
23 #include <llvm/IR/Instructions.h>
24 #include <llvm/IR/IntrinsicInst.h>
25 #include <llvm/Demangle/Demangle.h>
26 
27 #include <vector>
28 
29 namespace ark::llvmbackend::passes {
30 
ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions * options)31 bool InlinePrepare::ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions *options)
32 {
33     return options->inlining;
34 }
35 
Create(LLVMArkInterface * arkInterface,const ark::llvmbackend::LLVMCompilerOptions * options)36 InlinePrepare InlinePrepare::Create([[maybe_unused]] LLVMArkInterface *arkInterface,
37                                     const ark::llvmbackend::LLVMCompilerOptions *options)
38 {
39     static constexpr int INLINING_THRESHOLD = 500;
40     auto inlineParams = llvm::getInlineParams(INLINING_THRESHOLD);
41     inlineParams.AllowRecursiveCall = options->recursiveInlining;
42     return InlinePrepare(inlineParams);
43 }
44 
run(llvm::Module & module,llvm::ModuleAnalysisManager & moduleAm)45 llvm::PreservedAnalyses InlinePrepare::run(llvm::Module &module, llvm::ModuleAnalysisManager &moduleAm)
46 {
47     auto &advisorResult = moduleAm.getResult<llvm::InlineAdvisorAnalysis>(module);
48     if (!advisorResult.tryCreate(
49             inlineParams_, llvm::InliningAdvisorMode::Default, {},  // CC-OFF(G.FMT.06-CPP) project code style
50             llvm::InlineContext {llvm::ThinOrFullLTOPhase::None, llvm::InlinePass::ModuleInliner})) {
51         module.getContext().emitError("Could not setup Inlining Advisor for the requested mode and/or options");
52     }
53     return llvm::PreservedAnalyses::all();
54 }
55 
ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions * options)56 bool IrtocInlineChecker::ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions *options)
57 {
58     return options->doIrtocInline;
59 }
60 
CheckShouldInline(llvm::CallBase * callBase)61 void IrtocInlineChecker::CheckShouldInline(llvm::CallBase *callBase)
62 {
63     using llvm::StringRef;
64     if (!callBase->hasFnAttr(llvm::Attribute::AlwaysInline)) {
65         return;
66     }
67     auto caller = callBase->getCaller();
68     auto callee = callBase->getCalledFunction();
69     std::string msg = "Unknown reason";
70     if (callBase->hasFnAttr("inline-remark")) {
71         msg = callBase->getFnAttr("inline-remark").getValueAsString();
72     }
73 
74     auto demCallerName = llvm::demangle(std::string(caller->getName()));
75     if (callee == nullptr) {
76         llvm::report_fatal_error(llvm::Twine("Can't inline with alwaysinline attr  'nullptr") + "' into '" +
77                                  demCallerName + " due to " + msg + "'");
78         return;
79     }
80     auto demCalleeName = llvm::demangle(std::string(callee->getName()));
81 #ifdef __SANITIZE_THREAD__
82     // The functions from EXCLUSIONS are come from panda runtime (array-inl.h and class.h)
83     // These function are recursive (Thay are optimized by tail recursive in normal way
84     // but not if PANDA_ENABLE_THREAD_SANITIZER)
85     static constexpr std::array EXCLUSIONS = {StringRef("ark::coretypes::Array::CreateMultiDimensionalArray"),
86                                               StringRef("ark::Class::IsAssignableFrom(ark::Class const*)")};
87     if (std::find_if(EXCLUSIONS.cbegin(), EXCLUSIONS.cend(), [demCalleeName](StringRef pat) {
88             return demCalleeName.find(pat) != std::string::npos;
89         }) == EXCLUSIONS.cend()) {
90         llvm::report_fatal_error(llvm::Twine("Can't inline with alwaysinline attr '") + demCalleeName + "' into '" +
91                                  demCallerName + "' due to '" + msg + "'");
92     }
93 #else
94     llvm::report_fatal_error(llvm::Twine("Can't inline with alwaysinline attr '") + demCalleeName + "' into '" +
95                              demCallerName + "' due to '" + msg + "'");
96 #endif
97 }
98 
run(llvm::LazyCallGraph::SCC & component,llvm::CGSCCAnalysisManager &,llvm::LazyCallGraph &,llvm::CGSCCUpdateResult &)99 llvm::PreservedAnalyses IrtocInlineChecker::run(llvm::LazyCallGraph::SCC &component,
100                                                 llvm::CGSCCAnalysisManager & /*unused*/,
101                                                 llvm::LazyCallGraph & /*unused*/, llvm::CGSCCUpdateResult & /*unused*/)
102 {
103     for (const auto &node : component) {
104         auto &func = node.getFunction();
105         if (func.isDeclaration()) {
106             continue;
107         }
108 
109         for (llvm::Instruction &inst : llvm::instructions(func)) {
110             auto *callBase = llvm::dyn_cast<llvm::CallBase>(&inst);
111             if (callBase == nullptr || llvm::isa<llvm::IntrinsicInst>(&inst)) {
112                 continue;
113             }
114             llvm::Function *callee = callBase->getCalledFunction();
115             if (callee == nullptr || callee->isDeclaration()) {
116                 continue;
117             }
118             CheckShouldInline(callBase);
119         }
120     }
121 
122     return llvm::PreservedAnalyses::all();
123 }
124 
125 }  // namespace ark::llvmbackend::passes
126