• 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 "graph.h"
17 #include "basicblock.h"
18 #include "inst.h"
19 #include "optimizer/analysis/dominators_tree.h"
20 #include "optimizer/analysis/rpo.h"
21 #include "optimizer/analysis/linear_order.h"
22 #include "optimizer/analysis/loop_analyzer.h"
23 
24 namespace panda::compiler {
MarkBlocksRec(Marker mrk,BasicBlock * block)25 static void MarkBlocksRec(Marker mrk, BasicBlock *block)
26 {
27     if (block->SetMarker(mrk)) {
28         return;
29     }
30     for (auto succ : block->GetSuccsBlocks()) {
31         MarkBlocksRec(mrk, succ);
32     }
33 }
34 
~Graph()35 Graph::~Graph()
36 {
37 }
38 
RemoveUnreachableBlocks()39 void Graph::RemoveUnreachableBlocks()
40 {
41     Marker mrk = NewMarker();
42     MarkBlocksRec(mrk, GetStartBlock());
43     // Remove unreachable blocks
44     for (auto &bb : *this) {
45         if (bb == nullptr) {
46             continue;
47         }
48         if (!bb->IsMarked(mrk)) {
49             RemovePredecessors(bb, false);
50             RemoveSuccessors(bb);
51             if (bb->IsTryBegin()) {
52                 EraseTryBeginBlock(bb);
53                 // Remove try_end mark from paired bb
54                 if (!bb->IsEmpty()) {
55                     GetTryBeginInst(bb)->GetTryEndBlock()->SetTryEnd(false);
56                 }
57             }
58             // Clear DF:
59             for (auto inst : bb->AllInsts()) {
60                 inst->RemoveInputs();
61                 if (IsInstThrowable(inst)) {
62                     RemoveThrowableInst(inst);
63                 }
64             }
65             EraseBlock(bb);
66         }
67     }
68     EraseMarker(mrk);
69 }
70 
AddConstInStartBlock(ConstantInst * const_inst)71 void Graph::AddConstInStartBlock(ConstantInst *const_inst)
72 {
73     GetStartBlock()->AppendInst(const_inst);
74 }
75 
AddNewParameter(uint16_t arg_number)76 ParameterInst *Graph::AddNewParameter(uint16_t arg_number)
77 {
78     ParameterInst *param = CreateInstParameter(arg_number);
79     GetStartBlock()->AppendInst(param);
80     return param;
81 }
82 
RemoveConstFromList(ConstantInst * const_inst)83 void Graph::RemoveConstFromList(ConstantInst *const_inst)
84 {
85     if (const_inst == first_const_inst_) {
86         first_const_inst_ = const_inst->GetNextConst();
87         const_inst->SetNextConst(nullptr);
88         return;
89     }
90     auto current = first_const_inst_;
91     auto next = current->GetNextConst();
92     while (next != nullptr && next != const_inst) {
93         current = next;
94         next = next->GetNextConst();
95     }
96     ASSERT(next != nullptr);
97     ASSERT(next == const_inst);
98     current->SetNextConst(const_inst->GetNextConst());
99     const_inst->SetNextConst(nullptr);
100 }
101 
InvalidateBlocksOrderAnalyzes(Graph * graph)102 void InvalidateBlocksOrderAnalyzes(Graph *graph)
103 {
104     graph->InvalidateAnalysis<Rpo>();
105     graph->InvalidateAnalysis<DominatorsTree>();
106     graph->InvalidateAnalysis<LinearOrder>();
107 }
108 
AddBlock(BasicBlock * block)109 void Graph::AddBlock(BasicBlock *block)
110 {
111     block->SetId(vector_bb_.size());
112     vector_bb_.push_back(block);
113     block->SetGraph(this);
114     InvalidateBlocksOrderAnalyzes(this);
115 }
116 
117 #ifndef NDEBUG
AddBlock(BasicBlock * block,uint32_t id)118 void Graph::AddBlock(BasicBlock *block, uint32_t id)
119 {
120     if (vector_bb_.size() <= id) {
121         // (id + 1) for adding a block with index 0
122         vector_bb_.resize((id + 1U) << 1U, nullptr);
123     }
124     ASSERT(vector_bb_[id] == nullptr);
125     block->SetId(id);
126     vector_bb_[id] = block;
127     InvalidateBlocksOrderAnalyzes(this);
128 }
129 #endif
130 
GetBlocksRPO() const131 const ArenaVector<BasicBlock *> &Graph::GetBlocksRPO() const
132 {
133     return GetValidAnalysis<Rpo>().GetBlocks();
134 }
135 
GetBlocksLinearOrder() const136 const ArenaVector<BasicBlock *> &Graph::GetBlocksLinearOrder() const
137 {
138     return GetValidAnalysis<LinearOrder>().GetBlocks();
139 }
140 
141 template <class Callback>
VisitAllInstructions(Callback callback)142 void Graph::VisitAllInstructions(Callback callback)
143 {
144     for (auto bb : GetBlocksRPO()) {
145         for (auto inst : bb->AllInsts()) {
146             callback(inst);
147         }
148     }
149 }
150 
CreateEmptyBlock(uint32_t guest_pc)151 BasicBlock *Graph::CreateEmptyBlock(uint32_t guest_pc)
152 {
153     auto block = GetAllocator()->New<BasicBlock>(this, guest_pc);
154     AddBlock(block);
155     return block;
156 }
157 
158 // Create empty block with base block's properties
CreateEmptyBlock(BasicBlock * base_block)159 BasicBlock *Graph::CreateEmptyBlock(BasicBlock *base_block)
160 {
161     ASSERT(base_block != nullptr);
162     auto block = CreateEmptyBlock();
163     block->SetGuestPc(base_block->GetGuestPc());
164     block->SetAllFields(base_block->GetAllFields());
165     block->SetTryId(base_block->GetTryId());
166     return block;
167 }
168 
169 #ifndef NDEBUG
CreateEmptyBlock(uint32_t id,uint32_t guest_pc)170 BasicBlock *Graph::CreateEmptyBlock(uint32_t id, uint32_t guest_pc)
171 {
172     auto block = GetAllocator()->New<BasicBlock>(this, guest_pc);
173     AddBlock(block, id);
174     return block;
175 }
176 #endif
177 
CreateStartBlock()178 BasicBlock *Graph::CreateStartBlock()
179 {
180     auto block = CreateEmptyBlock(0U);
181     SetStartBlock(block);
182     return block;
183 }
184 
CreateEndBlock(uint32_t guest_pc)185 BasicBlock *Graph::CreateEndBlock(uint32_t guest_pc)
186 {
187     auto block = CreateEmptyBlock(guest_pc);
188     SetEndBlock(block);
189     return block;
190 }
191 
RemovePredecessorUpdateDF(BasicBlock * block,BasicBlock * rm_pred)192 void RemovePredecessorUpdateDF(BasicBlock *block, BasicBlock *rm_pred)
193 {
194     constexpr auto IMM_2 = 2;
195     if (block->GetPredsBlocks().size() == IMM_2) {
196         for (auto phi : block->PhiInstsSafe()) {
197             auto rm_index = phi->CastToPhi()->GetPredBlockIndex(rm_pred);
198             auto remaining_inst = phi->GetInput(1 - rm_index).GetInst();
199             if (phi != remaining_inst && remaining_inst->GetBasicBlock() != nullptr) {
200                 phi->ReplaceUsers(remaining_inst);
201             }
202             block->RemoveInst(phi);
203         }
204     } else if (block->GetPredsBlocks().size() > IMM_2) {
205         for (auto phi : block->PhiInstsSafe()) {
206             auto rm_index = phi->CastToPhi()->GetPredBlockIndex(rm_pred);
207             phi->CastToPhi()->RemoveInput(rm_index);
208         }
209     } else {
210         ASSERT(block->GetPredsBlocks().size() == 1);
211     }
212     block->RemovePred(rm_pred);
213     InvalidateBlocksOrderAnalyzes(block->GetGraph());
214 }
215 
216 /*
217  * Remove edges between `block` and its successors and
218  * update phi-instructions in successors blocks
219  */
RemoveSuccessors(BasicBlock * block)220 void Graph::RemoveSuccessors(BasicBlock *block)
221 {
222     for (auto succ : block->GetSuccsBlocks()) {
223         RemovePredecessorUpdateDF(succ, block);
224     }
225     block->GetSuccsBlocks().clear();
226 }
227 
228 /*
229  * Remove edges between `block` and its predecessors,
230  * update last instructions in predecessors blocks
231  */
RemovePredecessors(BasicBlock * block,bool remove_last_inst)232 void Graph::RemovePredecessors(BasicBlock *block, bool remove_last_inst)
233 {
234     for (auto pred : block->GetPredsBlocks()) {
235         if (remove_last_inst && !pred->IsTryBegin() && !pred->IsTryEnd()) {
236             if (pred->GetSuccsBlocks().size() == 2U) {
237                 auto last = pred->GetLastInst();
238                 ASSERT(last->GetOpcode() == Opcode::If || last->GetOpcode() == Opcode::IfImm);
239                 pred->RemoveInst(last);
240             } else {
241                 ASSERT(pred->GetSuccsBlocks().size() == 1 && pred->GetSuccessor(0) == block);
242             }
243         }
244         if (std::find(pred->GetSuccsBlocks().begin(), pred->GetSuccsBlocks().end(), block) !=
245             pred->GetSuccsBlocks().end()) {
246             pred->RemoveSucc(block);
247         }
248     }
249     block->GetPredsBlocks().clear();
250 }
251 
252 // Helper for the next 2 methods
FinishBlockRemoval(BasicBlock * block)253 static void FinishBlockRemoval(BasicBlock *block)
254 {
255     auto graph = block->GetGraph();
256     graph->GetAnalysis<DominatorsTree>().SetValid(true);
257     auto dominator = block->GetDominator();
258     if (dominator != nullptr) {
259         dominator->RemoveDominatedBlock(block);
260         for (auto dom_block : block->GetDominatedBlocks()) {
261             ASSERT(dom_block->GetDominator() == block);
262             dominator->AddDominatedBlock(dom_block);
263             dom_block->SetDominator(dominator);
264         }
265     }
266     block->SetDominator(nullptr);
267 
268     block->SetGraph(nullptr);
269     if (graph->GetAnalysis<Rpo>().IsValid()) {
270         graph->GetAnalysis<Rpo>().RemoveBasicBlock(block);
271     }
272 }
273 
274 /**
275  * @param block - a block which is disconnecting from the graph with clearing control-flow and data-flow
276  */
DisconnectBlock(BasicBlock * block,bool remove_last_inst,bool fix_dom_tree)277 void Graph::DisconnectBlock(BasicBlock *block, bool remove_last_inst, bool fix_dom_tree)
278 {
279     ASSERT(IsAnalysisValid<DominatorsTree>() || !fix_dom_tree);
280     RemovePredecessors(block, remove_last_inst);
281     RemoveSuccessors(block);
282 
283     if (block->IsTryBegin()) {
284         EraseTryBeginBlock(block);
285     }
286 
287     // Remove all instructions from `block`
288     block->Clear();
289 
290     if (block->IsEndBlock()) {
291         SetEndBlock(nullptr);
292     }
293     if (fix_dom_tree) {
294         FinishBlockRemoval(block);
295     }
296     EraseBlock(block);
297     // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
298 }
299 
DisconnectBlockRec(BasicBlock * block,bool remove_last_inst,bool fix_dom_tree)300 void Graph::DisconnectBlockRec(BasicBlock *block, bool remove_last_inst, bool fix_dom_tree)
301 {
302     if (block->GetGraph() == nullptr) {
303         return;
304     }
305     bool loop_flag = false;
306     if (block->IsLoopHeader()) {
307         loop_flag = true;
308         auto loop = block->GetLoop();
309         for (auto pred : block->GetPredsBlocks()) {
310             loop_flag &= (std::find(loop->GetBackEdges().begin(), loop->GetBackEdges().end(), pred) !=
311                           loop->GetBackEdges().end());
312         }
313     }
314     if (block->GetPredsBlocks().empty() || loop_flag) {
315         ArenaVector<BasicBlock *> succs(block->GetSuccsBlocks(), GetLocalAllocator()->Adapter());
316         DisconnectBlock(block, remove_last_inst, fix_dom_tree);
317         for (auto succ : succs) {
318             DisconnectBlockRec(succ, remove_last_inst, fix_dom_tree);
319         }
320     }
321 }
322 
EraseBlock(BasicBlock * block)323 void Graph::EraseBlock(BasicBlock *block)
324 {
325     vector_bb_[block->GetId()] = nullptr;
326     if (GetEndBlock() == block) {
327         SetEndBlock(nullptr);
328     }
329     ASSERT(GetStartBlock() != block);
330     block->SetGraph(nullptr);
331 }
332 
RestoreBlock(BasicBlock * block)333 void Graph::RestoreBlock(BasicBlock *block)
334 {
335     ASSERT(vector_bb_[block->GetId()] == nullptr);
336     vector_bb_[block->GetId()] = block;
337     block->SetGraph(this);
338     InvalidateBlocksOrderAnalyzes(this);
339 }
340 
341 /**
342  * @param block - same for block without instructions at all
343  */
RemoveEmptyBlock(BasicBlock * block)344 void Graph::RemoveEmptyBlock(BasicBlock *block)
345 {
346     ASSERT(IsAnalysisValid<DominatorsTree>());
347     ASSERT(block->GetLastInst() == nullptr);
348     ASSERT(block->GetPredsBlocks().empty());
349     ASSERT(block->GetSuccsBlocks().empty());
350 
351     FinishBlockRemoval(block);
352     EraseBlock(block);
353     // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
354 }
355 
356 /**
357  * @param block - same for block without instructions, may have Phi(s)
358  */
RemoveEmptyBlockWithPhis(BasicBlock * block,bool irr_loop)359 void Graph::RemoveEmptyBlockWithPhis(BasicBlock *block, bool irr_loop)
360 {
361     ASSERT(IsAnalysisValid<DominatorsTree>());
362     ASSERT(block->IsEmpty());
363 
364     ASSERT(!block->GetSuccsBlocks().empty());
365     ASSERT(!block->GetPredsBlocks().empty());
366     block->RemoveEmptyBlock(irr_loop);
367 
368     FinishBlockRemoval(block);
369     EraseBlock(block);
370 }
371 
FindConstant(DataType::Type type,uint64_t value)372 ConstantInst *Graph::FindConstant(DataType::Type type, uint64_t value)
373 {
374     for (auto constant = GetFirstConstInst(); constant != nullptr; constant = constant->GetNextConst()) {
375         if (constant->GetType() != type) {
376             continue;
377         }
378         if (IsBytecodeOptimizer() && IsInt32Bit(type) && (constant->GetInt32Value() == static_cast<uint32_t>(value))) {
379             return constant;
380         }
381         if (constant->IsEqualConst(type, value)) {
382             return constant;
383         }
384     }
385     return nullptr;
386 }
387 
FindOrAddConstant(ConstantInst * inst)388 ConstantInst *Graph::FindOrAddConstant(ConstantInst *inst)
389 {
390     auto existing_const = FindConstant(inst->GetType(), inst->GetRawValue());
391     if (existing_const != nullptr) {
392         return existing_const;
393     }
394     AddConstInStartBlock(inst);
395     inst->SetNextConst(first_const_inst_);
396     first_const_inst_ = inst;
397     return inst;
398 }
399 
ResetParameterInfo()400 void Graph::ResetParameterInfo()
401 {
402     param_info_ = nullptr;
403     return;
404 }
405 
HasLoop() const406 bool Graph::HasLoop() const
407 {
408     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
409     return !GetRootLoop()->GetInnerLoops().empty();
410 }
411 
HasIrreducibleLoop() const412 bool Graph::HasIrreducibleLoop() const
413 {
414     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
415     return FlagIrredicibleLoop::Get(bit_fields_);
416 }
417 
HasInfiniteLoop() const418 bool Graph::HasInfiniteLoop() const
419 {
420     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
421     return FlagInfiniteLoop::Get(bit_fields_);
422 }
423 
HasFloatRegs() const424 bool Graph::HasFloatRegs() const
425 {
426     ASSERT(IsRegAllocApplied());
427     return FlagFloatRegs::Get(bit_fields_);
428 }
429 
430 /*
431  * Mark blocks, which have successor from external loop
432  */
MarkLoopExits(const Graph * graph,Marker marker)433 void MarkLoopExits(const Graph *graph, Marker marker)
434 {
435     for (auto block : graph->GetBlocksRPO()) {
436         if (block->GetSuccsBlocks().size() == MAX_SUCCS_NUM) {
437             if (block->GetSuccessor(0)->GetLoop() != block->GetSuccessor(1)->GetLoop()) {
438                 block->SetMarker(marker);
439             }
440         } else if (block->GetSuccsBlocks().size() > MAX_SUCCS_NUM) {
441             ASSERT(block->IsTryEnd() || block->IsTryBegin());
442             auto loop = block->GetSuccessor(0)->GetLoop();
443             for (size_t i = 1; i < block->GetSuccsBlocks().size(); i++) {
444                 if (loop != block->GetSuccessor(i)->GetLoop()) {
445                     block->SetMarker(marker);
446                 }
447             }
448         }
449     }
450 }
451 
GetMethodFullName(const Graph * graph,RuntimeInterface::MethodPtr method)452 std::string GetMethodFullName(const Graph *graph, RuntimeInterface::MethodPtr method)
453 {
454     std::stringstream sstream;
455     sstream << graph->GetRuntime()->GetClassNameFromMethod(method)
456             << "::" << graph->GetRuntime()->GetMethodName(method);
457     return sstream.str();
458 }
459 
460 // NOLINTNEXTLINE(readability-identifier-naming,-warnings-as-errors)
begin()461 Graph::ParameterList::Iterator Graph::ParameterList::begin()
462 {
463     auto start_bb = graph_->GetStartBlock();
464     Iterator it(start_bb->GetFirstInst());
465     if (*it != nullptr && it->GetOpcode() != Opcode::Parameter) {
466         ++it;
467     }
468     return it;
469 }
470 
RemoveThrowableInst(const Inst * inst)471 void Graph::RemoveThrowableInst(const Inst *inst)
472 {
473     ASSERT(IsInstThrowable(inst));
474     for (auto catch_handler : throwable_insts_.at(inst)) {
475         for (auto catch_inst : catch_handler->AllInsts()) {
476             if (!catch_inst->IsCatchPhi() || catch_inst->CastToCatchPhi()->IsAcc()) {
477                 continue;
478             }
479             auto catch_phi = catch_inst->CastToCatchPhi();
480             const auto &vregs = catch_phi->GetThrowableInsts();
481             auto it = std::find(vregs->begin(), vregs->end(), inst);
482             if (it != vregs->end()) {
483                 int index = std::distance(vregs->begin(), it);
484                 catch_phi->RemoveInput(index);
485             }
486         }
487     }
488     throwable_insts_.erase(inst);
489 }
490 
ReplaceThrowableInst(Inst * old_inst,Inst * new_inst)491 void Graph::ReplaceThrowableInst(Inst *old_inst, Inst *new_inst)
492 {
493     auto it = throwable_insts_.emplace(new_inst, GetAllocator()->Adapter()).first;
494     it->second = std::move(throwable_insts_.at(old_inst));
495 
496     for (auto catch_handler : it->second) {
497         for (auto catch_inst : catch_handler->AllInsts()) {
498             if (!catch_inst->IsCatchPhi() || catch_inst->CastToCatchPhi()->IsAcc()) {
499                 continue;
500             }
501             auto catch_phi = catch_inst->CastToCatchPhi();
502             const auto &vregs = catch_phi->GetThrowableInsts();
503             auto iter = std::find(vregs->begin(), vregs->end(), old_inst);
504             if (iter != vregs->end()) {
505                 catch_phi->ReplaceThrowableInst(old_inst, new_inst);
506             }
507         }
508     }
509     throwable_insts_.erase(old_inst);
510 }
511 
DumpThrowableInsts(std::ostream * out) const512 void Graph::DumpThrowableInsts(std::ostream *out) const
513 {
514     for (auto &[inst, handlers] : throwable_insts_) {
515         (*out) << "Throwable Inst";
516         inst->Dump(out);
517         (*out) << "Catch handlers:";
518         auto sep = " ";
519         for (auto bb : handlers) {
520             (*out) << sep << "BB " << bb->GetId();
521             sep = ", ";
522         }
523         (*out) << std::endl;
524     }
525 }
526 
InitDefaultLocations()527 void Graph::InitDefaultLocations()
528 {
529     if (IsDefaultLocationsInit()) {
530         return;
531     }
532     VisitAllInstructions([this](Inst *inst) {
533         if (!inst->IsOperandsDynamic() || inst->IsPhi()) {
534             return;
535         }
536         [[maybe_unused]] LocationsInfo *locations = GetAllocator()->New<LocationsInfo>(GetAllocator(), inst);
537         for (size_t i = 0; i < inst->GetInputsCount(); i++) {
538             if (inst->GetInputType(i) != DataType::NO_TYPE) {
539                 locations->SetLocation(i, Location::RequireRegister());
540             }
541         }
542     });
543     SetDefaultLocationsInit();
544 }
545 
GetBranchCounter(const BasicBlock * block,bool true_succ)546 int64_t Graph::GetBranchCounter(const BasicBlock *block, bool true_succ)
547 {
548     ASSERT(block->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
549     auto last_inst = block->GetLastInst();
550     RuntimeInterface::MethodPtr method;
551     if (last_inst->GetOpcode() == Opcode::IfImm) {
552         method = last_inst->CastToIfImm()->GetMethod();
553     } else if (last_inst->GetOpcode() == Opcode::If) {
554         method = last_inst->CastToIf()->GetMethod();
555     } else {
556         return 0;
557     }
558 
559     if (method == nullptr) {
560         // corresponded branch instruction was not present in bytecode, e.g. IfImmInst was created while inlining
561         return 0;
562     }
563 
564     return block->IsInverted() == 0;
565 }
566 
GetParametersSlotsCount() const567 uint32_t Graph::GetParametersSlotsCount() const
568 {
569     uint32_t max_slot = 0;
570     for (auto param_inst : GetParameters()) {
571         auto location = param_inst->CastToParameter()->GetLocationData().GetSrc();
572         if (location.IsStackParameter()) {
573             max_slot = location.GetValue() + 1U;
574         }
575     }
576     return max_slot;
577 }
578 
Dump(std::ostream & stm)579 void GraphMode::Dump(std::ostream &stm)
580 {
581     const char *sep = "";
582 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
583 #define DUMP_MODE(name)      \
584     if (Is##name()) {        \
585         stm << sep << #name; \
586         sep = ", ";          \
587     }
588 
589     DUMP_MODE(Osr);
590     DUMP_MODE(BytecodeOpt);
591     DUMP_MODE(DynamicMethod);
592     DUMP_MODE(Native);
593     DUMP_MODE(FastPath);
594     DUMP_MODE(Boundary);
595     DUMP_MODE(Interpreter);
596     DUMP_MODE(InterpreterEntry);
597 }
598 
599 }  // namespace panda::compiler
600