1 /**
2 * Copyright (c) 2021-2022 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 <iomanip>
17 #include "optimizer/pass_manager.h"
18 #include "compiler_options.h"
19 #include "trace/trace.h"
20 #include "optimizer_run.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/graph_checker.h"
27 #include "optimizer/analysis/alias_analysis.h"
28 #include "optimizer/analysis/bounds_analysis.h"
29 #include "optimizer/analysis/dominators_tree.h"
30 #include "optimizer/analysis/linear_order.h"
31 #include "optimizer/analysis/loop_analyzer.h"
32 #include "optimizer/analysis/rpo.h"
33 #include "optimizer/optimizations/balance_expressions.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/if_conversion.h"
38 #include "optimizer/optimizations/loop_peeling.h"
39 #include "optimizer/optimizations/loop_unroll.h"
40 #include "optimizer/optimizations/lowering.h"
41 #include "optimizer/optimizations/memory_barriers.h"
42 #include "optimizer/optimizations/memory_coalescing.h"
43 #include "optimizer/optimizations/redundant_loop_elimination.h"
44 #include "optimizer/optimizations/regalloc/reg_alloc.h"
45 #include "optimizer/optimizations/scheduler.h"
46 #include "optimizer/optimizations/try_catch_resolving.h"
47 #include "optimizer/optimizations/types_resolving.h"
48 #include "optimizer/optimizations/vn.h"
49 #include "optimizer/optimizations/move_constants.h"
50 #include "optimizer/optimizations/adjust_arefs.h"
51
52 namespace panda::compiler {
53
RunCodegenPass(Graph * graph)54 static inline bool RunCodegenPass(Graph *graph)
55 {
56 if (graph->GetMethodProperties().GetRequireFrameSetup()) {
57 return graph->RunPass<Codegen>();
58 }
59 return graph->RunPass<CodegenNative>();
60 }
61
RunOptimizations(Graph * graph)62 bool RunOptimizations(Graph *graph)
63 {
64 auto finalizer = [graph](void * /* unused */) { graph->GetPassManager()->Finalize(); };
65 std::unique_ptr<void, decltype(finalizer)> pp(&finalizer, finalizer);
66
67 if (options.WasSetCompilerRegallocRegMask()) {
68 COMPILER_LOG(DEBUG, REGALLOC) << "Regalloc mask force set to " << std::hex
69 << options.GetCompilerRegallocRegMask() << "\n";
70 graph->SetArchUsedRegs(options.GetCompilerRegallocRegMask());
71 }
72
73 if (!options.IsCompilerNonOptimizing()) {
74 // Run optimizations
75
76 // The problem with inlining in OSR mode can be found in `bitops-nsieve-bits` benchmark and it is in the
77 // following: we inline the method that has user X within a loop, then peepholes optimize datflow and def of
78 // the X become another instruction within inlined method, but SaveStateOsr didn't take it into account, thus,
79 // we don't restore value of this new definition.
80 // TODO(msherstennikov): find way to inline in OSR mode
81 if (!graph->IsOsrMode()) {
82 graph->RunPass<Inlining>();
83 }
84 graph->RunPass<TryCatchResolving>();
85 graph->RunPass<Peepholes>();
86 graph->RunPass<BranchElimination>();
87 graph->RunPass<ValNum>();
88 graph->RunPass<Cleanup>();
89 if (graph->IsAotMode()) {
90 graph->RunPass<Cse>();
91 }
92 if (graph->IsDynamicMethod()) {
93 graph->RunPass<TypesResolving>();
94 }
95 graph->RunPass<Licm>(options.GetCompilerLicmHoistLimit());
96 graph->RunPass<RedundantLoopElimination>();
97 graph->RunPass<LoopPeeling>();
98 graph->RunPass<Lse>();
99 graph->RunPass<ValNum>();
100 if (graph->RunPass<Peepholes>() && graph->RunPass<BranchElimination>()) {
101 graph->RunPass<Peepholes>();
102 }
103 graph->RunPass<Cleanup>();
104 if (graph->IsAotMode()) {
105 graph->RunPass<Cse>();
106 }
107 graph->RunPass<LoopUnroll>(options.GetCompilerLoopUnrollInstLimit(), options.GetCompilerLoopUnrollFactor());
108 graph->RunPass<BalanceExpressions>();
109 if (graph->RunPass<Peepholes>()) {
110 graph->RunPass<BranchElimination>();
111 }
112 graph->RunPass<ValNum>();
113 if (graph->IsAotMode()) {
114 graph->RunPass<Cse>();
115 }
116 if (graph->RunPass<DeoptimizeElimination>()) {
117 graph->RunPass<Peepholes>();
118 }
119
120 #ifndef NDEBUG
121 graph->SetLowLevelInstructionsEnabled();
122 #endif // NDEBUG
123 graph->RunPass<Cleanup>();
124 graph->RunPass<Lowering>();
125 graph->RunPass<CodeSink>();
126 graph->RunPass<MemoryCoalescing>(options.IsCompilerMemoryCoalescingAligned());
127 graph->RunPass<IfConversion>(options.GetCompilerIfConversionLimit());
128 graph->RunPass<Scheduler>();
129 // Perform MoveConstants after Scheduler because Scheduler can rearrange constants
130 // and cause spillfill in reg alloc
131 graph->RunPass<MoveConstants>();
132 graph->RunPass<AdjustRefs>();
133 graph->RunPass<OptimizeMemoryBarriers>();
134 } else {
135 // TryCatchResolving is needed in the non-optimizing mode since it removes unreachable for compiler
136 // catch-handlers; After supporting catch-handlers' compilation, this pass can be run in the optimizing mode
137 // only.
138 graph->RunPass<TryCatchResolving>();
139 }
140
141 bool fatal_on_err = !options.IsCompilerAllowBackendFailures();
142 // Do not try to encode too large graph
143 auto inst_size = graph->GetCurrentInstructionId();
144 auto insts_per_byte = graph->GetEncoder()->MaxArchInstPerEncoded();
145 auto max_bits_in_inst = GetInstructionSizeBits(graph->GetArch());
146 if ((inst_size * insts_per_byte * max_bits_in_inst) > options.GetCompilerMaxGenCodeSize()) {
147 if (fatal_on_err) {
148 LOG(FATAL, COMPILER) << "RunOptimizations failed: code predicted size too big";
149 }
150 return false;
151 }
152 graph->RunPass<Cleanup>();
153 if (!RegAlloc(graph)) {
154 if (fatal_on_err) {
155 LOG(FATAL, COMPILER) << "RunOptimizations failed: register allocation error";
156 }
157 return false;
158 }
159
160 if (!RunCodegenPass(graph)) {
161 if (fatal_on_err) {
162 LOG(FATAL, COMPILER) << "RunOptimizations failed: code generation error";
163 }
164 return false;
165 }
166
167 return true;
168 }
169
170 } // namespace panda::compiler
171