• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "compiler_logger.h"
17 #include "optimizer/analysis/alias_analysis.h"
18 #include "optimizer/analysis/dominators_tree.h"
19 #include "deoptimize_elimination.h"
20 
21 namespace panda::compiler {
22 
RunImpl()23 bool DeoptimizeElimination::RunImpl()
24 {
25     uint64_t insts_number = VisitGraphAndCount();
26 
27     ReplaceDeoptimizeIfByUnconditionalDeoptimize();
28 
29     if (!HaveCalls() && insts_number <= options.GetCompilerSafepointEliminationLimit()) {
30         RemoveSafePoints();
31     }
32 
33     return IsApplied();
34 }
35 
ReplaceDeoptimizeIfByUnconditionalDeoptimize()36 void DeoptimizeElimination::ReplaceDeoptimizeIfByUnconditionalDeoptimize()
37 {
38     for (auto &inst : deoptimize_must_throw_) {
39         auto block = inst->GetBasicBlock();
40         if (block != nullptr) {
41             block->ReplaceInstByDeoptimize(inst);
42             SetApplied();
43         }
44     }
45 }
46 
RemoveSafePoints()47 void DeoptimizeElimination::RemoveSafePoints()
48 {
49     auto block = GetGraph()->GetStartBlock();
50     ASSERT(block != nullptr && block->IsStartBlock());
51     for (auto sp : block->Insts()) {
52         if (sp->GetOpcode() == Opcode::SafePoint) {
53             sp->ClearFlag(inst_flags::NO_DCE);
54             SetApplied();
55             COMPILER_LOG(DEBUG, DEOPTIMIZE_ELIM) << "SafePoint " << sp->GetId() << " is deleted from start block";
56             block->GetGraph()->GetEventWriter().EventDeoptimizeElimination(GetOpcodeString(sp->GetOpcode()),
57                                                                            sp->GetId(), sp->GetPc());
58         }
59     }
60 }
61 
RequireRegMap(Inst * inst)62 bool DeoptimizeElimination::RequireRegMap(Inst *inst)
63 {
64     for (auto &user : inst->GetUsers()) {
65         auto user_inst = user.GetInst();
66         if (user_inst->RequireRegMap()) {
67             return true;
68         }
69         if (user_inst->GetOpcode() == Opcode::CallStatic || user_inst->GetOpcode() == Opcode::CallVirtual) {
70             // Inlined method can contain Deoptimize or DeoptimizeIf
71             if (static_cast<CallInst *>(user_inst)->IsInlined()) {
72                 return true;
73             }
74         }
75     }
76     return false;
77 }
78 
VisitDefault(Inst * inst)79 void DeoptimizeElimination::VisitDefault(Inst *inst)
80 {
81     if (inst->GetType() != DataType::REFERENCE) {
82         return;
83     }
84     for (auto &user : inst->GetUsers()) {
85         auto user_inst = user.GetInst();
86         if (!user_inst->IsSaveState()) {
87             return;
88         }
89         if (user_inst->GetOpcode() == Opcode::SafePoint) {
90             continue;
91         }
92         if (RequireRegMap(user_inst)) {
93             return;
94         }
95     }
96 
97     inst->RemoveUsers<true>();
98 
99     SetApplied();
100     COMPILER_LOG(DEBUG, DEOPTIMIZE_ELIM) << "All users the instructions " << inst->GetId() << " are SaveStates";
101     inst->GetBasicBlock()->GetGraph()->GetEventWriter().EventDeoptimizeElimination(GetOpcodeString(inst->GetOpcode()),
102                                                                                    inst->GetId(), inst->GetPc());
103 }
104 
VisitSaveState(GraphVisitor * v,Inst * inst)105 void DeoptimizeElimination::VisitSaveState(GraphVisitor *v, Inst *inst)
106 {
107     auto visitor = static_cast<DeoptimizeElimination *>(v);
108     if (visitor->TryToRemoveRedundantSaveState(inst)) {
109         return;
110     }
111 
112     if (visitor->RequireRegMap(inst)) {
113         return;
114     }
115 
116     auto ss = inst->CastToSaveState();
117     if (ss->RemoveNumericInputs()) {
118         visitor->SetApplied();
119         COMPILER_LOG(DEBUG, DEOPTIMIZE_ELIM) << "SaveState " << ss->GetId() << " numeric inputs were deleted";
120         ss->GetBasicBlock()->GetGraph()->GetEventWriter().EventDeoptimizeElimination(GetOpcodeString(ss->GetOpcode()),
121                                                                                      ss->GetId(), ss->GetPc());
122 #ifndef NDEBUG
123         ss->SetInputsWereDeleted();
124 #endif
125     }
126 }
127 
VisitSaveStateDeoptimize(GraphVisitor * v,Inst * inst)128 void DeoptimizeElimination::VisitSaveStateDeoptimize(GraphVisitor *v, Inst *inst)
129 {
130     static_cast<DeoptimizeElimination *>(v)->TryToRemoveRedundantSaveState(inst);
131 }
132 
VisitDeoptimizeIf(GraphVisitor * v,Inst * inst)133 void DeoptimizeElimination::VisitDeoptimizeIf(GraphVisitor *v, Inst *inst)
134 {
135     auto input = inst->GetInput(0).GetInst();
136     auto block = inst->GetBasicBlock();
137     auto graph = block->GetGraph();
138     auto visitor = static_cast<DeoptimizeElimination *>(v);
139     if (input->IsConst()) {
140         if (input->CastToConstant()->GetIntValue() == 0) {
141             visitor->RemoveDeoptimizeIf(inst);
142         } else {
143             visitor->PushNewDeoptimizeIf(inst);
144         }
145     } else if (input->GetOpcode() == Opcode::IsMustDeoptimize) {
146         if (visitor->CanRemoveGuard(input)) {
147             visitor->RemoveGuard(input);
148         }
149     } else {
150         for (auto &user : input->GetUsers()) {
151             auto user_inst = user.GetInst();
152             if (user_inst != inst && user_inst->GetOpcode() == Opcode::DeoptimizeIf &&
153                 !(graph->IsOsrMode() && block->GetLoop() != user_inst->GetBasicBlock()->GetLoop()) &&
154                 inst->InSameBlockOrDominate(user_inst)) {
155                 ASSERT(inst->IsDominate(user_inst));
156                 visitor->RemoveDeoptimizeIf(user_inst);
157             }
158         }
159     }
160 }
161 
TryToRemoveRedundantSaveState(Inst * inst)162 bool DeoptimizeElimination::TryToRemoveRedundantSaveState(Inst *inst)
163 {
164     if (inst->GetUsers().Empty()) {
165         auto block = inst->GetBasicBlock();
166         block->ReplaceInst(inst, block->GetGraph()->CreateInstNOP());
167         inst->RemoveInputs();
168         SetApplied();
169         COMPILER_LOG(DEBUG, DEOPTIMIZE_ELIM) << "SaveState " << inst->GetId() << " without users is deleted";
170         block->GetGraph()->GetEventWriter().EventDeoptimizeElimination(GetOpcodeString(inst->GetOpcode()),
171                                                                        inst->GetId(), inst->GetPc());
172         return true;
173     }
174     return false;
175 }
176 
CanRemoveGuard(Inst * guard)177 bool DeoptimizeElimination::CanRemoveGuard(Inst *guard)
178 {
179     auto guard_block = guard->GetBasicBlock();
180     auto it = InstSafeIterator<IterationType::INST, IterationDirection::BACKWARD>(*guard_block, guard);
181     for (++it; it != guard_block->InstsSafeReverse().end(); ++it) {
182         auto inst = *it;
183         if (inst->IsRuntimeCall()) {
184             return false;
185         }
186         if (inst->GetOpcode() == Opcode::IsMustDeoptimize) {
187             return true;
188         }
189     }
190     auto mrk = guard_block->GetGraph()->NewMarker();
191     auto remove_mrk = guard_block->GetGraph()->NewMarker();
192 
193     /*
194      * Run search recursively from current block to start block.
195      * We can remove guard, if guard is met in all ways and there should be no call instructions between current
196      * guard and found guards.
197      */
198     bool can_remove = true;
199     for (auto succ_block : guard_block->GetPredsBlocks()) {
200         can_remove &= CanRemoveGuardRec(succ_block, guard, mrk, remove_mrk);
201         if (!can_remove) {
202             break;
203         }
204     }
205     guard_block->GetGraph()->EraseMarker(mrk);
206     guard_block->GetGraph()->EraseMarker(remove_mrk);
207     return can_remove;
208 }
209 
CanRemoveGuardRec(BasicBlock * block,Inst * guard,const Marker & mrk,const Marker & remove_mrk)210 bool DeoptimizeElimination::CanRemoveGuardRec(BasicBlock *block, Inst *guard, const Marker &mrk,
211                                               const Marker &remove_mrk)
212 {
213     if (block->IsStartBlock()) {
214         return false;
215     }
216     auto block_type = GetBlockType(block);
217     if (block->SetMarker(mrk)) {
218         return block->IsMarked(remove_mrk);
219     }
220     if (block_type == BlockType::INVALID) {
221         for (auto inst : block->InstsSafeReverse()) {
222             if (inst->IsRuntimeCall()) {
223                 PushNewBlockType(block, BlockType::RUNTIME_CALL);
224                 return false;
225             }
226             if (inst->GetOpcode() == Opcode::IsMustDeoptimize) {
227                 [[maybe_unused]] auto result = block->SetMarker(remove_mrk);
228                 ASSERT(!result);
229                 PushNewBlockType(block, BlockType::GUARD);
230                 return true;
231             }
232         }
233         PushNewBlockType(block, BlockType::NOTHING);
234     } else if (block_type != BlockType::NOTHING) {
235         if (block_type == BlockType::GUARD) {
236             [[maybe_unused]] auto result = block->SetMarker(remove_mrk);
237             ASSERT(!result);
238             return true;
239         }
240         return false;
241     }
242     for (const auto &succ_block : block->GetPredsBlocks()) {
243         if (!CanRemoveGuardRec(succ_block, guard, mrk, remove_mrk)) {
244             return false;
245         }
246     }
247     [[maybe_unused]] auto result = block->SetMarker(remove_mrk);
248     ASSERT(!result);
249     return true;
250 }
251 
RemoveGuard(Inst * guard)252 void DeoptimizeElimination::RemoveGuard(Inst *guard)
253 {
254     ASSERT(guard->GetOpcode() == Opcode::IsMustDeoptimize);
255     ASSERT(guard->HasSingleUser());
256 
257     auto deopt = guard->GetNext();
258     ASSERT(deopt->GetOpcode() == Opcode::DeoptimizeIf);
259     auto block = guard->GetBasicBlock();
260     auto graph = block->GetGraph();
261     guard->RemoveInputs();
262     block->ReplaceInst(guard, graph->CreateInstNOP());
263 
264     COMPILER_LOG(DEBUG, DEOPTIMIZE_ELIM) << "Dublicated Guard " << guard->GetId() << " is deleted";
265     graph->GetEventWriter().EventDeoptimizeElimination(GetOpcodeString(guard->GetOpcode()), guard->GetId(),
266                                                        guard->GetPc());
267     RemoveDeoptimizeIf(deopt);
268 }
269 
RemoveDeoptimizeIf(Inst * inst)270 void DeoptimizeElimination::RemoveDeoptimizeIf(Inst *inst)
271 {
272     auto block = inst->GetBasicBlock();
273     auto graph = block->GetGraph();
274     auto savestate = inst->GetInput(1).GetInst();
275 
276     inst->RemoveInputs();
277     block->ReplaceInst(inst, graph->CreateInstNOP());
278 
279     COMPILER_LOG(DEBUG, DEOPTIMIZE_ELIM) << "Dublicated or redundant DeoptimizeIf " << inst->GetId() << " is deleted";
280     graph->GetEventWriter().EventDeoptimizeElimination(GetOpcodeString(inst->GetOpcode()), inst->GetId(),
281                                                        inst->GetPc());
282 
283     if (savestate->GetUsers().Empty()) {
284         savestate->GetBasicBlock()->ReplaceInst(savestate, graph->CreateInstNOP());
285         savestate->RemoveInputs();
286 
287         COMPILER_LOG(DEBUG, DEOPTIMIZE_ELIM) << "SaveState " << savestate->GetId() << " without users is deleted";
288         graph->GetEventWriter().EventDeoptimizeElimination(GetOpcodeString(savestate->GetOpcode()), savestate->GetId(),
289                                                            savestate->GetPc());
290     }
291     SetApplied();
292 }
293 
InvalidateAnalyses()294 void DeoptimizeElimination::InvalidateAnalyses()
295 {
296     GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
297     GetGraph()->InvalidateAnalysis<DominatorsTree>();
298     GetGraph()->InvalidateAnalysis<BoundsAnalysis>();
299     GetGraph()->InvalidateAnalysis<AliasAnalysis>();
300 }
301 }  // namespace panda::compiler
302