• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_optimizer.h"
17 
18 #include "passes/ark_inlining.h"
19 #include "passes/ark_speculation.h"
20 #include "passes/expand_atomics.h"
21 
22 #include "passes/inline_ir/cleanup_inline_module.h"
23 #include "passes/inline_ir/discard_inline_module.h"
24 #include "passes/inline_ir/mark_always_inline.h"
25 #include "passes/inline_ir/mark_inline_module.h"
26 #include "passes/inline_ir/remove_unused_functions.h"
27 
28 #include "llvm_ark_interface.h"
29 
30 #include <llvm/Analysis/AliasAnalysis.h>
31 #include <llvm/Analysis/GlobalsModRef.h>
32 #include <llvm/Analysis/TargetLibraryInfo.h>
33 #include <llvm/Analysis/ProfileSummaryInfo.h>
34 #include <llvm/Transforms/Utils/CanonicalizeAliases.h>
35 #include <llvm/Transforms/Utils/NameAnonGlobals.h>
36 #include <llvm/Passes/PassBuilder.h>
37 #include <llvm/Passes/StandardInstrumentations.h>
38 #include <llvm/IR/Verifier.h>
39 #include <llvm/Target/TargetMachine.h>
40 
41 #include <fstream>
42 #include <streambuf>
43 #include <type_traits>
44 
45 #include "transforms/transform_utils.h"
46 
47 namespace {
48 
49 template <typename PassManagerT, typename PassT>
AddPassIf(PassManagerT & passManager,PassT && pass,bool needInsert=true)50 void AddPassIf(PassManagerT &passManager, PassT &&pass, bool needInsert = true)
51 {
52     if (!needInsert) {
53         return;
54     }
55     passManager.addPass(std::forward<PassT>(pass));
56 #ifndef NDEBUG
57     // VerifierPass can be insterted only in ModulePassManager or FunctionPassManager
58     constexpr auto IS_MODULE_PM = std::is_same_v<llvm::ModulePassManager, PassManagerT>;
59     constexpr auto IS_FUNCTION_PM = std::is_same_v<llvm::FunctionPassManager, PassManagerT>;
60     // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
61     // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
62     if constexpr (IS_MODULE_PM || IS_FUNCTION_PM) {  // NOLINT(bugprone-suspicious-semicolon)
63         passManager.addPass(llvm::VerifierPass());
64     }
65 #endif
66 }
67 
PreprocessPipelineFile(const std::string & filename)68 std::string PreprocessPipelineFile(const std::string &filename)
69 {
70     std::ifstream file(filename);
71     if (!file.is_open()) {
72         llvm::report_fatal_error(llvm::Twine("Cant open pipeline file: `") + filename + "`", false);
73     }
74     std::string rawData((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
75 
76     // Remove comments
77     size_t insertPos = 0;
78     size_t copyPos = 0;
79     constexpr auto COMMENT_SYMBOL = '#';
80     constexpr auto ENDLINE_SYMBOL = '\n';
81     while (copyPos < rawData.size()) {
82         while (copyPos < rawData.size() && rawData[copyPos] != COMMENT_SYMBOL) {
83             rawData[insertPos++] = rawData[copyPos++];
84         }
85         while (copyPos < rawData.size() && rawData[copyPos] != ENDLINE_SYMBOL) {
86             copyPos++;
87         }
88     }
89     rawData.resize(insertPos);
90 
91     // Remove space symbols
92     auto predicate = [](char sym) { return std::isspace(sym); };
93     rawData.erase(std::remove_if(rawData.begin(), rawData.end(), predicate), rawData.end());
94 
95     return rawData;
96 }
97 
98 #include <pipeline_irtoc_gen.inc>
99 
GetOptimizationPipeline(const std::string & filename)100 std::string GetOptimizationPipeline(const std::string &filename)
101 {
102     std::string pipeline;
103     if (!filename.empty()) {
104         pipeline = PreprocessPipelineFile(filename);
105     } else {
106         // PIPELINE_IRTOC variable is defined in pipeline_irtoc_gen.inc
107         pipeline = std::string {PIPELINE_IRTOC};
108     }
109     return pipeline;
110 }
111 
112 }  // namespace
113 
114 #include <llvm_passes.inl>
115 
116 namespace panda::llvmbackend {
117 
LLVMOptimizer(panda::llvmbackend::LLVMCompilerOptions options,LLVMArkInterface * arkInterface,std::shared_ptr<llvm::TargetMachine> targetMachine)118 LLVMOptimizer::LLVMOptimizer(panda::llvmbackend::LLVMCompilerOptions options, LLVMArkInterface *arkInterface,
119                              std::shared_ptr<llvm::TargetMachine> targetMachine)
120     : options_(std::move(options)), arkInterface_(arkInterface), targetMachine_(std::move(targetMachine))
121 {
122 }
123 
ProcessInlineModule(llvm::Module * inlineModule) const124 void LLVMOptimizer::ProcessInlineModule(llvm::Module *inlineModule) const
125 {
126     namespace pass = panda::llvmbackend::passes;
127     llvm::ModulePassManager modulePm;
128     llvm::LoopAnalysisManager loopAm;
129     llvm::FunctionAnalysisManager functionAm;
130     llvm::CGSCCAnalysisManager cgsccAm;
131     llvm::ModuleAnalysisManager moduleAm;
132 
133     llvm::PassBuilder passBuilder(targetMachine_.get());
134     passBuilder.registerModuleAnalyses(moduleAm);
135     passBuilder.registerCGSCCAnalyses(cgsccAm);
136     passBuilder.registerFunctionAnalyses(functionAm);
137     passBuilder.registerLoopAnalyses(loopAm);
138     passBuilder.crossRegisterProxies(loopAm, functionAm, cgsccAm, moduleAm);
139 
140     AddPassIf(modulePm, llvm::CanonicalizeAliasesPass(), true);
141     AddPassIf(modulePm, llvm::NameAnonGlobalPass(), true);
142     AddPassIf(modulePm, pass::MarkInlineModule(), true);
143     AddPassIf(modulePm, pass::CleanupInlineModule(), true);
144 
145     modulePm.run(*inlineModule, moduleAm);
146 }
147 
OptimizeModule(llvm::Module * module) const148 void LLVMOptimizer::OptimizeModule(llvm::Module *module) const
149 {
150     ASSERT(arkInterface_ != nullptr);
151 
152     if (options_.dumpModuleBeforeOptimizations) {
153         llvm::errs() << "; =========================================\n";
154         llvm::errs() << "; LLVM IR module BEFORE LLVM optimizations:\n";
155         llvm::errs() << "; =========================================\n";
156         llvm::errs() << *module << '\n';
157     }
158 
159     DoOptimizeModule(module);
160 
161     if (options_.dumpModuleAfterOptimizations) {
162         llvm::errs() << "; =========================================\n";
163         llvm::errs() << "; LLVM IR module AFTER LLVM optimizations: \n";
164         llvm::errs() << "; =========================================\n";
165         llvm::errs() << *module << '\n';
166     }
167 }
168 
DoOptimizeModule(llvm::Module * module) const169 void LLVMOptimizer::DoOptimizeModule(llvm::Module *module) const
170 {
171     // Create the analysis managers.
172     llvm::LoopAnalysisManager loopAm;
173     llvm::FunctionAnalysisManager functionAm;
174     llvm::CGSCCAnalysisManager cgsccAm;
175     llvm::ModuleAnalysisManager moduleAm;
176 
177     llvm::StandardInstrumentations instrumentation(false);
178     llvm::PassInstrumentationCallbacks passInstrumentation;
179     instrumentation.registerCallbacks(passInstrumentation);
180     panda::libllvmbackend::RegisterPasses(passInstrumentation);
181 
182     llvm::PassBuilder passBuilder(targetMachine_.get(), llvm::PipelineTuningOptions(), llvm::None,
183                                   &passInstrumentation);
184 
185     // Register the AA manager first so that our version is the one used.
186     functionAm.registerPass([&passBuilder] { return passBuilder.buildDefaultAAPipeline(); });
187     // Register the target library analysis directly.
188     functionAm.registerPass(
189         [&] { return llvm::TargetLibraryAnalysis(llvm::TargetLibraryInfoImpl(targetMachine_->getTargetTriple())); });
190     // Register all the basic analyses with the managers.
191     passBuilder.registerModuleAnalyses(moduleAm);
192     passBuilder.registerCGSCCAnalyses(cgsccAm);
193     passBuilder.registerFunctionAnalyses(functionAm);
194     passBuilder.registerLoopAnalyses(loopAm);
195     passBuilder.crossRegisterProxies(loopAm, functionAm, cgsccAm, moduleAm);
196 
197     panda::libllvmbackend::PassParser passParser(arkInterface_);
198     passParser.RegisterParserCallbacks(passBuilder, options_);
199 
200     llvm::ModulePassManager modulePm;
201     if (options_.optimize) {
202         cantFail(passBuilder.parsePassPipeline(modulePm, GetOptimizationPipeline(options_.pipelineFile)));
203     } else {
204         namespace pass = panda::llvmbackend::passes;
205         llvm::FunctionPassManager functionPm;
206         AddPassIf(functionPm, pass::ExpandAtomics());
207         modulePm.addPass(createModuleToFunctionPassAdaptor(std::move(functionPm)));
208     }
209     modulePm.run(*module, moduleAm);
210 }
211 
212 }  // namespace panda::llvmbackend
213