• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "pipeline.h"
17 #include "compiler_options.h"
18 #include "inplace_task_runner.h"
19 #include "background_task_runner.h"
20 #include "compiler_task_runner.h"
21 
22 #include "optimizer/code_generator/codegen.h"
23 #include "optimizer/code_generator/codegen_native.h"
24 #include "optimizer/code_generator/method_properties.h"
25 #include "optimizer/ir/graph.h"
26 #include "optimizer/ir/visualizer_printer.h"
27 #include "optimizer/analysis/alias_analysis.h"
28 #include "optimizer/analysis/linear_order.h"
29 #include "optimizer/analysis/monitor_analysis.h"
30 #include "optimizer/analysis/rpo.h"
31 #include "optimizer/optimizations/balance_expressions.h"
32 #include "optimizer/optimizations/branch_elimination.h"
33 #include "optimizer/optimizations/checks_elimination.h"
34 #include "optimizer/optimizations/code_sink.h"
35 #include "optimizer/optimizations/deoptimize_elimination.h"
36 #include "optimizer/optimizations/cleanup.h"
37 #include "optimizer/optimizations/escape.h"
38 #include "optimizer/optimizations/if_conversion.h"
39 #include "optimizer/optimizations/inlining.h"
40 #include "optimizer/optimizations/licm.h"
41 #include "optimizer/optimizations/licm_conditions.h"
42 #include "optimizer/optimizations/loop_idioms.h"
43 #include "optimizer/optimizations/loop_peeling.h"
44 #include "optimizer/optimizations/loop_unswitch.h"
45 #include "optimizer/optimizations/loop_unroll.h"
46 #include "optimizer/optimizations/lowering.h"
47 #include "optimizer/optimizations/lse.h"
48 #include "optimizer/optimizations/memory_barriers.h"
49 #include "optimizer/optimizations/memory_coalescing.h"
50 #include "optimizer/optimizations/peepholes.h"
51 #include "optimizer/optimizations/phi_type_resolving.h"
52 #include "optimizer/optimizations/redundant_loop_elimination.h"
53 #include "optimizer/optimizations/regalloc/reg_alloc.h"
54 #include "optimizer/optimizations/scheduler.h"
55 #include "optimizer/optimizations/simplify_string_builder.h"
56 #include "optimizer/optimizations/try_catch_resolving.h"
57 #include "optimizer/optimizations/inline_intrinsics.h"
58 #include "optimizer/optimizations/vn.h"
59 #include "optimizer/optimizations/cse.h"
60 #include "optimizer/optimizations/move_constants.h"
61 #include "optimizer/optimizations/adjust_arefs.h"
62 #include "optimizer/optimizations/if_merging.h"
63 
64 #include "plugins/create_pipeline_includes.h"
65 
66 namespace panda::compiler {
67 
Create(Graph * graph)68 std::unique_ptr<Pipeline> Pipeline::Create(Graph *graph)
69 {
70     switch (graph->GetLanguage()) {
71 #include "plugins/create_pipeline.h"
72         default:
73             return std::make_unique<Pipeline>(graph);
74     }
75 }
76 
RunCodegenPass(Graph * graph)77 static inline bool RunCodegenPass(Graph *graph)
78 {
79     if (graph->GetMethodProperties().GetRequireFrameSetup()) {
80         return graph->RunPass<Codegen>();
81     }
82     return graph->RunPass<CodegenNative>();
83 }
84 
85 /* static */
86 template <TaskRunnerMode RUNNER_MODE>
Run(CompilerTaskRunner<RUNNER_MODE> taskRunner)87 void Pipeline::Run(CompilerTaskRunner<RUNNER_MODE> taskRunner)
88 {
89     auto pipeline = taskRunner.GetContext().GetPipeline();
90     auto *graph = pipeline->GetGraph();
91 #if !defined(NDEBUG) && !defined(PANDA_TARGET_MOBILE)
92     if (g_options.IsCompilerVisualizerDump()) {
93         graph->GetPassManager()->InitialDumpVisualizerGraph();
94     }
95 #endif  // NDEBUG && PANDA_TARGET_MOBILE
96 
97     taskRunner.AddFinalize(
98         [](CompilerContext<RUNNER_MODE> &compilerCtx) { compilerCtx.GetGraph()->GetPassManager()->Finalize(); });
99 
100     if (g_options.WasSetCompilerRegallocRegMask()) {
101         COMPILER_LOG(DEBUG, REGALLOC) << "Regalloc mask force set to " << std::hex
102                                       << g_options.GetCompilerRegallocRegMask() << "\n";
103         graph->SetArchUsedRegs(g_options.GetCompilerRegallocRegMask());
104     }
105 
106     if (!g_options.IsCompilerNonOptimizing()) {
107         taskRunner.SetTaskOnSuccess([](CompilerTaskRunner<RUNNER_MODE> nextRunner) {
108             Pipeline::RunRegAllocAndCodeGenPass<RUNNER_MODE>(std::move(nextRunner));
109         });
110         bool success = pipeline->RunOptimizations();
111         CompilerTaskRunner<RUNNER_MODE>::EndTask(std::move(taskRunner), success);
112         return;
113     }
114     // TryCatchResolving is needed in the non-optimizing mode since it removes unreachable for compiler
115     // catch-handlers; After supporting catch-handlers' compilation, this pass can be run in the optimizing mode
116     // only.
117     graph->template RunPass<TryCatchResolving>();
118     if (!graph->template RunPass<MonitorAnalysis>()) {
119         LOG(WARNING, COMPILER) << "Compiler detected incorrect monitor policy";
120         CompilerTaskRunner<RUNNER_MODE>::EndTask(std::move(taskRunner), false);
121         return;
122     }
123     Pipeline::RunRegAllocAndCodeGenPass<RUNNER_MODE>(std::move(taskRunner));
124 }
125 
126 /* static */
127 template <TaskRunnerMode RUNNER_MODE>
RunRegAllocAndCodeGenPass(CompilerTaskRunner<RUNNER_MODE> taskRunner)128 void Pipeline::RunRegAllocAndCodeGenPass(CompilerTaskRunner<RUNNER_MODE> taskRunner)
129 {
130     auto *graph = taskRunner.GetContext().GetPipeline()->GetGraph();
131     bool fatalOnErr = !g_options.IsCompilerAllowBackendFailures();
132     // Do not try to encode too large graph
133     auto instSize = graph->GetCurrentInstructionId();
134     auto instsPerByte = graph->GetEncoder()->MaxArchInstPerEncoded();
135     auto maxBitsInInst = GetInstructionSizeBits(graph->GetArch());
136     if ((instSize * instsPerByte * maxBitsInInst) > g_options.GetCompilerMaxGenCodeSize()) {
137         if (fatalOnErr) {
138             LOG(FATAL, COMPILER) << "RunOptimizations failed: code predicted size too big";
139         }
140         CompilerTaskRunner<RUNNER_MODE>::EndTask(std::move(taskRunner), false);
141         return;
142     }
143     graph->template RunPass<Cleanup>();
144 
145     taskRunner.SetTaskOnSuccess([fatalOnErr](CompilerTaskRunner<RUNNER_MODE> nextRunner) {
146         nextRunner.AddCallbackOnFail([fatalOnErr]([[maybe_unused]] CompilerContext<RUNNER_MODE> &compilerCtx) {
147             if (fatalOnErr) {
148                 LOG(FATAL, COMPILER) << "RunOptimizations failed: code generation error";
149             }
150         });
151         bool success = RunCodegenPass(nextRunner.GetContext().GetPipeline()->GetGraph());
152         CompilerTaskRunner<RUNNER_MODE>::EndTask(std::move(nextRunner), success);
153     });
154     bool success = RegAlloc(graph);
155     if (!success && fatalOnErr) {
156         LOG(FATAL, COMPILER) << "RunOptimizations failed: register allocation error";
157     }
158     CompilerTaskRunner<RUNNER_MODE>::EndTask(std::move(taskRunner), success);
159 }
160 
RunOptimizations()161 bool Pipeline::RunOptimizations()
162 {
163     auto graph = GetGraph();
164 
165     /* peepholer and branch elimination have some parts that have
166      * to be delayed up until loop unrolling is done, however, if
167      * loop unrolling is not going to be run we don't have to delay */
168     if (!g_options.IsCompilerLoopUnroll()) {
169         graph->SetUnrollComplete();
170     }
171     graph->RunPass<Peepholes>();
172     graph->RunPass<BranchElimination>();
173     graph->RunPass<SimplifyStringBuilder>();
174     graph->RunPass<Cleanup>();
175 
176     // The problem with inlining in OSR mode can be found in `bitops-nsieve-bits` benchmark and it is in the
177     // following: we inline the method that has user X within a loop, then peepholes optimize datflow and def of
178     // the X become another instruction within inlined method, but SaveStateOsr didn't take it into account, thus,
179     // we don't restore value of this new definition.
180     // NOTE(msherstennikov): find way to inline in OSR mode
181     if (!graph->IsOsrMode()) {
182         graph->RunPass<Inlining>();
183     }
184     graph->RunPass<CatchInputs>();
185     graph->RunPass<TryCatchResolving>();
186     if (!graph->RunPass<MonitorAnalysis>()) {
187         LOG(WARNING, COMPILER) << "Compiler detected incorrect monitor policy";
188         return false;
189     }
190     graph->RunPass<Peepholes>();
191     graph->RunPass<BranchElimination>();
192     graph->RunPass<ValNum>();
193     graph->RunPass<IfMerging>();
194     graph->RunPass<Cleanup>(false);
195     graph->RunPass<Peepholes>();
196     if (graph->IsAotMode()) {
197         graph->RunPass<Cse>();
198     }
199     if (graph->IsDynamicMethod()) {
200         graph->RunPass<InlineIntrinsics>();
201         graph->RunPass<PhiTypeResolving>();
202         graph->RunPass<Peepholes>();
203         graph->RunPass<BranchElimination>();
204         graph->RunPass<ValNum>();
205         graph->RunPass<Cleanup>(false);
206     }
207     graph->RunPass<ChecksElimination>();
208     graph->RunPass<Licm>(g_options.GetCompilerLicmHoistLimit());
209     graph->RunPass<LicmConditions>();
210     graph->RunPass<RedundantLoopElimination>();
211     graph->RunPass<LoopPeeling>();
212     graph->RunPass<LoopUnswitch>(g_options.GetCompilerLoopUnswitchMaxLevel(),
213                                  g_options.GetCompilerLoopUnswitchMaxInsts());
214     graph->RunPass<Lse>();
215     graph->RunPass<ValNum>();
216     if (graph->RunPass<Peepholes>() && graph->RunPass<BranchElimination>()) {
217         graph->RunPass<Peepholes>();
218         graph->RunPass<ValNum>();
219     }
220     graph->RunPass<Cleanup>();
221     if (graph->IsAotMode()) {
222         graph->RunPass<Cse>();
223     }
224     graph->RunPass<EscapeAnalysis>();
225     graph->RunPass<LoopIdioms>();
226     graph->RunPass<ChecksElimination>();
227     graph->RunPass<LoopUnroll>(g_options.GetCompilerLoopUnrollInstLimit(), g_options.GetCompilerLoopUnrollFactor());
228 #include <plugins/optimizations_after_unroll.h>
229 
230     /* to be removed once generic loop unrolling is implemented */
231     ASSERT(graph->IsUnrollComplete());
232 
233     graph->RunPass<Peepholes>();
234     graph->RunPass<BranchElimination>();
235     graph->RunPass<BalanceExpressions>();
236     graph->RunPass<ValNum>();
237     if (graph->IsAotMode()) {
238         graph->RunPass<Cse>();
239     }
240     if (graph->RunPass<DeoptimizeElimination>()) {
241         graph->RunPass<Peepholes>();
242     }
243 
244 #ifndef NDEBUG
245     graph->SetLowLevelInstructionsEnabled();
246 #endif  // NDEBUG
247     graph->RunPass<Cleanup>(false);
248     graph->RunPass<Lowering>();
249     graph->RunPass<Cleanup>(false);
250     graph->RunPass<CodeSink>();
251     graph->RunPass<MemoryCoalescing>(g_options.IsCompilerMemoryCoalescingAligned());
252     graph->RunPass<IfConversion>(g_options.GetCompilerIfConversionLimit());
253     graph->RunPass<Scheduler>();
254     // Perform MoveConstants after Scheduler because Scheduler can rearrange constants
255     // and cause spillfill in reg alloc
256     graph->RunPass<MoveConstants>();
257     if (graph->RunPass<AdjustRefs>()) {
258         graph->RunPass<ValNum>();
259         graph->RunPass<Cleanup>(false);
260     }
261     graph->RunPass<OptimizeMemoryBarriers>();
262 
263     return true;
264 }
265 
266 template void Pipeline::Run<BACKGROUND_MODE>(CompilerTaskRunner<BACKGROUND_MODE>);
267 template void Pipeline::Run<INPLACE_MODE>(CompilerTaskRunner<INPLACE_MODE>);
268 template void Pipeline::RunRegAllocAndCodeGenPass<BACKGROUND_MODE>(CompilerTaskRunner<BACKGROUND_MODE>);
269 template void Pipeline::RunRegAllocAndCodeGenPass<INPLACE_MODE>(CompilerTaskRunner<INPLACE_MODE>);
270 
271 }  // namespace panda::compiler
272