• 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 "optimizer/ir/basicblock.h"
17 #include "optimizer/ir/graph.h"
18 #include "liveness_analyzer.h"
19 #include "optimizer/analysis/dominators_tree.h"
20 #include "optimizer/analysis/loop_analyzer.h"
21 
22 namespace panda::compiler {
LivenessAnalyzer(Graph * graph)23 LivenessAnalyzer::LivenessAnalyzer(Graph *graph)
24     : Analysis(graph),
25       allocator_(graph->GetAllocator()),
26       linear_blocks_(graph->GetAllocator()->Adapter()),
27       inst_life_numbers_(graph->GetAllocator()->Adapter()),
28       inst_life_intervals_(graph->GetAllocator()->Adapter()),
29       insts_by_life_number_(graph->GetAllocator()->Adapter()),
30       block_live_ranges_(graph->GetAllocator()->Adapter()),
31       block_live_sets_(graph->GetLocalAllocator()->Adapter()),
32       pending_catch_phi_inputs_(graph->GetAllocator()->Adapter()),
33       physical_general_intervals_(graph->GetAllocator()->Adapter()),
34       physical_vector_intervals_(graph->GetAllocator()->Adapter())
35 {
36 }
37 
RunImpl()38 bool LivenessAnalyzer::RunImpl()
39 {
40     GetGraph()->RunPass<DominatorsTree>();
41     GetGraph()->RunPass<LoopAnalyzer>();
42     ResetLiveness();
43     BuildBlocksLinearOrder();
44     BuildInstLifeNumbers();
45     BuildInstLifeIntervals();
46     if (!pending_catch_phi_inputs_.empty()) {
47         COMPILER_LOG(ERROR, LIVENESS_ANALYZER)
48             << "Graph contains CatchPhi instructions whose inputs were not processed";
49         return false;
50     }
51     std::copy_if(physical_general_intervals_.begin(), physical_general_intervals_.end(),
52                  std::back_inserter(inst_life_intervals_), [](auto li) { return li != nullptr; });
53     std::copy_if(physical_vector_intervals_.begin(), physical_vector_intervals_.end(),
54                  std::back_inserter(inst_life_intervals_), [](auto li) { return li != nullptr; });
55     COMPILER_LOG(DEBUG, LIVENESS_ANALYZER) << "Liveness analysis is constructed";
56     return true;
57 }
58 
ResetLiveness()59 void LivenessAnalyzer::ResetLiveness()
60 {
61     inst_life_numbers_.clear();
62     inst_life_intervals_.clear();
63     block_live_sets_.clear();
64     block_live_ranges_.clear();
65     physical_general_intervals_.clear();
66     physical_vector_intervals_.clear();
67     if (GetGraph()->GetArch() != Arch::NONE) {
68         physical_general_intervals_.resize(REGISTERS_NUM);
69         physical_vector_intervals_.resize(VREGISTERS_NUM);
70     }
71 }
72 
73 /*
74  * Linear blocks order means:
75  * - all dominators of a block are visiting before this block;
76  * - all blocks belonging to the same loop are contiguous;
77  */
BuildBlocksLinearOrder()78 void LivenessAnalyzer::BuildBlocksLinearOrder()
79 {
80     ASSERT_PRINT(GetGraph()->IsAnalysisValid<DominatorsTree>(), "Liveness Analyzer needs valid Dom Tree");
81     auto size = GetGraph()->GetBlocksRPO().size();
82     linear_blocks_.reserve(size);
83     linear_blocks_.clear();
84     marker_ = GetGraph()->NewMarker();
85     ASSERT_PRINT(marker_ != UNDEF_MARKER, "There are no free markers");
86     if (GetGraph()->IsBytecodeOptimizer() && !GetGraph()->GetTryBeginBlocks().empty()) {
87         LinearizeBlocks<true>();
88     } else {
89         LinearizeBlocks<false>();
90     }
91     ASSERT(linear_blocks_.size() == size);
92     GetGraph()->EraseMarker(marker_);
93     ASSERT_PRINT(CheckLinearOrder(), "Linear block order isn't correct");
94 
95     block_live_sets_.resize(GetGraph()->GetVectorBlocks().size());
96     block_live_ranges_.resize(GetGraph()->GetVectorBlocks().size());
97 }
98 
99 /*
100  * Check if all forward edges of loop header were visited to get the resulting block order in RPO.
101  * Predecessors which are not in the same loop with a header - are forward edges.
102  */
AllForwardEdgesVisited(BasicBlock * block)103 bool LivenessAnalyzer::AllForwardEdgesVisited(BasicBlock *block)
104 {
105     if (!block->IsLoopHeader()) {
106         for (auto pred : block->GetPredsBlocks()) {
107             if (!pred->IsMarked(marker_)) {
108                 return false;
109             }
110         }
111     } else {
112         // Head of irreducible loop can not dominate other blocks in the loop
113         if (block->GetLoop()->IsIrreducible()) {
114             return true;
115         }
116         // Predecessors which are not dominated - are forward edges,
117         for (auto pred : block->GetPredsBlocks()) {
118             if (!block->IsDominate(pred) && !pred->IsMarked(marker_)) {
119                 return false;
120             }
121         }
122     }
123     return true;
124 }
125 
126 template <bool use_pc_order>
LinearizeBlocks()127 void LivenessAnalyzer::LinearizeBlocks()
128 {
129     ArenaList<BasicBlock *> pending {GetGraph()->GetLocalAllocator()->Adapter()};
130     pending.push_back(GetGraph()->GetStartBlock());
131 
132     while (!pending.empty()) {
133         auto current = pending.front();
134         pending.pop_front();
135 
136         linear_blocks_.push_back(current);
137         current->SetMarker(marker_);
138 
139         auto succs = current->GetSuccsBlocks();
140         // Each block is inserted into pending list before all already inserted blocks
141         // from the same loop. To process edges forwarding to a "true" branches successors
142         // should be processed in reversed order.
143         for (auto it = succs.rbegin(); it != succs.rend(); ++it) {
144             auto succ = *it;
145             if (succ->IsMarked(marker_) || !AllForwardEdgesVisited(succ)) {
146                 continue;
147             }
148 
149             if constexpr (use_pc_order) {  // NOLINT(readability-braces-around-statements)
150                 auto pc_compare = [succ](auto block) { return block->GetGuestPc() > succ->GetGuestPc(); };
151                 auto insert_before = std::find_if(pending.begin(), pending.end(), pc_compare);
152                 pending.insert(insert_before, succ);
153             } else {  // NOLINT(readability-misleading-indentation)
154                 // Insert successor right before a block from the same loop, outer loop's block
155                 // or before a block from the root loop.
156                 // Such ordering guarantee that a loop and all it's inner loops will be processed
157                 // before following edges leading to outer loop blocks.
158                 auto is_same_or_inner_loop = [succ](auto block) {
159                     return succ->GetLoop() == block->GetLoop() || block->GetLoop()->IsRoot() ||
160                            succ->GetLoop()->IsInside(block->GetLoop());
161                 };
162                 auto insert_before = std::find_if(pending.begin(), pending.end(), is_same_or_inner_loop);
163                 pending.insert(insert_before, succ);
164             }
165         }
166     }
167 }
168 
169 /*
170  * Check linear order correctness, using dominators tree
171  */
CheckLinearOrder()172 bool LivenessAnalyzer::CheckLinearOrder()
173 {
174     ArenaVector<size_t> block_pos(GetGraph()->GetVectorBlocks().size(), 0, GetAllocator()->Adapter());
175     size_t position = 0;
176     for (auto block : linear_blocks_) {
177         block_pos[block->GetId()] = position++;
178     }
179 
180     for (auto block : linear_blocks_) {
181         if (block->GetDominator() != nullptr) {
182             ASSERT_PRINT(block_pos[block->GetDominator()->GetId()] < block_pos[block->GetId()],
183                          "Each block should be visited after its dominator");
184         }
185         if (!block->IsTryEnd()) {
186             continue;
187         }
188         ASSERT(block->GetTryId() != INVALID_ID);
189         for (auto bb : linear_blocks_) {
190             if (bb->IsTry() && bb->GetTryId() == block->GetTryId()) {
191                 ASSERT_PRINT(block_pos[bb->GetId()] < block_pos[block->GetId()],
192                              "Each try-block should be visited before its try-end block");
193             }
194         }
195     }
196 
197     return true;
198 }
199 
200 /*
201  * Set lifetime number and visiting number for each instruction
202  */
BuildInstLifeNumbers()203 void LivenessAnalyzer::BuildInstLifeNumbers()
204 {
205     LifeNumber block_begin;
206     LifeNumber life_number = 0;
207     LinearNumber linear_number = 0;
208 
209     for (auto block : GetLinearizedBlocks()) {
210         block_begin = life_number;
211         // set the same number for each phi in the block
212         for (auto phi : block->PhiInsts()) {
213             phi->SetLinearNumber(linear_number++);
214             SetInstLifeNumber(phi, life_number);
215             CreateLifeIntervals(phi);
216         }
217         // ignore PHI instructions
218         insts_by_life_number_.push_back(nullptr);
219         // set a unique number for each instruction in the block, differing by 2
220         // for the reason of adding spill/fill instructions
221         for (auto inst : block->Insts()) {
222             inst->SetLinearNumber(linear_number++);
223             CreateLifeIntervals(inst);
224             life_number += LIFE_NUMBER_GAP;
225             SetInstLifeNumber(inst, life_number);
226             insts_by_life_number_.push_back(inst);
227         }
228         life_number += LIFE_NUMBER_GAP;
229         SetBlockLiveRange(block, {block_begin, life_number});
230     }
231 }
232 
233 /*
234  * Get lifetime intervals for each instruction
235  */
BuildInstLifeIntervals()236 void LivenessAnalyzer::BuildInstLifeIntervals()
237 {
238     for (auto it = GetLinearizedBlocks().rbegin(); it != GetLinearizedBlocks().rend(); it++) {
239         auto block = *it;
240         auto live_set = GetInitInstLiveSet(block);
241         ProcessBlockLiveInstructions(block, live_set);
242     }
243 }
244 
245 /*
246  * The initial set of live instructions in the `block` is the the union of all live instructions at the beginning of
247  * the block's successors.
248  * Also for each phi-instruction of the successors: input corresponding to the `block` is added to the live set.
249  */
GetInitInstLiveSet(BasicBlock * block)250 InstLiveSet *LivenessAnalyzer::GetInitInstLiveSet(BasicBlock *block)
251 {
252     unsigned instruction_count = inst_life_intervals_.size();
253     auto live_set = GetAllocator()->New<InstLiveSet>(instruction_count, GetAllocator());
254     CHECK_NOT_NULL(live_set);
255     for (auto succ : block->GetSuccsBlocks()) {
256         // catch-begin is pseudo successor, its live set will be processed for blocks with throwable instructions
257         if (succ->IsCatchBegin()) {
258             continue;
259         }
260         live_set->Union(GetBlockLiveSet(succ));
261         for (auto phi : succ->PhiInsts()) {
262             auto phi_input = phi->CastToPhi()->GetPhiDataflowInput(block);
263             live_set->Add(phi_input->GetLinearNumber());
264         }
265     }
266 
267     // if basic block contains throwable instruction, all instucrions live in the catch-handlers should be live in this
268     // block
269     if (auto inst = block->GetFistThrowableInst(); inst != nullptr) {
270         auto handlers = GetGraph()->GetThrowableInstHandlers(inst);
271         for (auto catch_handler : handlers) {
272             live_set->Union(GetBlockLiveSet(catch_handler));
273         }
274     }
275     return live_set;
276 }
277 
GetLoopEnd(Loop * loop)278 LifeNumber LivenessAnalyzer::GetLoopEnd(Loop *loop)
279 {
280     LifeNumber loop_end = 0;
281     // find max LifeNumber of inner loops
282     for (auto inner : loop->GetInnerLoops()) {
283         loop_end = std::max(loop_end, GetLoopEnd(inner));
284     }
285     // find max LifeNumber of back_edges
286     for (auto back_edge : loop->GetBackEdges()) {
287         loop_end = std::max(loop_end, GetBlockLiveRange(back_edge).GetEnd());
288     }
289     return loop_end;
290 }
291 
292 /*
293  * Append and adjust the lifetime intervals for each instruction live in the block and for their inputs
294  */
ProcessBlockLiveInstructions(BasicBlock * block,InstLiveSet * live_set)295 void LivenessAnalyzer::ProcessBlockLiveInstructions(BasicBlock *block, InstLiveSet *live_set)
296 {
297     // For each live instruction set initial life range equals to the block life range
298     for (auto &interval : inst_life_intervals_) {
299         if (live_set->IsSet(interval->GetInst()->GetLinearNumber())) {
300             interval->AppendRange(GetBlockLiveRange(block));
301         }
302     }
303 
304     for (Inst *inst : block->InstsSafeReverse()) {
305         // Shorten instruction lifetime to the position where its defined
306         // and remove from the block's live set
307         auto inst_life_number = GetInstLifeNumber(inst);
308         auto interval = GetInstLifeIntervals(inst);
309         interval->StartFrom(inst_life_number);
310         live_set->Remove(inst->GetLinearNumber());
311         if (inst->IsCatchPhi()) {
312             // catch-phi's liveness should overlap all linked try blocks' livenesses
313             for (auto pred : inst->GetBasicBlock()->GetPredsBlocks()) {
314                 inst_life_number = std::min(inst_life_number, GetBlockLiveRange(pred).GetBegin());
315             }
316             interval->StartFrom(inst_life_number);
317             AdjustCatchPhiInputsLifetime(inst);
318         } else {
319             auto current_live_range = LiveRange {GetBlockLiveRange(block).GetBegin(), inst_life_number};
320             AdjustInputsLifetime(inst, current_live_range, live_set);
321         }
322     }
323 
324     // The lifetime interval of phis instructions starts at the beginning of the block
325     for (auto phi : block->PhiInsts()) {
326         live_set->Remove(phi->GetLinearNumber());
327     }
328 
329     // All instructions live at the beginning ot the loop header
330     // must be live for the entire loop
331     if (block->IsLoopHeader()) {
332         LifeNumber loop_end_position = GetLoopEnd(block->GetLoop());
333 
334         for (auto &interval : inst_life_intervals_) {
335             if (live_set->IsSet(interval->GetInst()->GetLinearNumber())) {
336                 interval->AppendGroupRange({GetBlockLiveRange(block).GetBegin(), loop_end_position});
337             }
338         }
339     }
340     SetBlockLiveSet(block, live_set);
341 }
342 
343 /* static */
GetPropagatedLiveRange(Inst * inst,LiveRange live_range)344 LiveRange LivenessAnalyzer::GetPropagatedLiveRange(Inst *inst, LiveRange live_range)
345 {
346     /*
347      * We need to propagate liveness for instruction with CallRuntime to save registers before call;
348      * Otherwise, we will not be able to restore the value of the virtual registers
349      */
350     if (inst->IsPropagateLiveness()) {
351         live_range.SetEnd(live_range.GetEnd() + 1);
352     }
353     return live_range;
354 }
355 
356 /*
357  * Adjust instruction inputs lifetime and add them to the block's live set
358  */
AdjustInputsLifetime(Inst * inst,LiveRange live_range,InstLiveSet * live_set)359 void LivenessAnalyzer::AdjustInputsLifetime(Inst *inst, LiveRange live_range, InstLiveSet *live_set)
360 {
361     for (auto input : inst->GetInputs()) {
362         auto input_inst = inst->GetDataFlowInput(input.GetInst());
363         live_set->Add(input_inst->GetLinearNumber());
364         SetInputRange(inst, input_inst, live_range);
365     }
366 
367     // Extend SaveState inputs lifetime to the end of SaveState's lifetime
368     if (inst->RequireState()) {
369         auto save_state = inst->GetSaveState();
370         ASSERT(save_state != nullptr);
371         auto propagated_range = GetPropagatedLiveRange(inst, live_range);
372         for (auto ss_input : save_state->GetInputs()) {
373             auto input_inst = save_state->GetDataFlowInput(ss_input.GetInst());
374             live_set->Add(input_inst->GetLinearNumber());
375             GetInstLifeIntervals(input_inst)->AppendRange(propagated_range);
376         }
377     }
378 
379     // Handle CatchPhi inputs associated with inst
380     auto range = pending_catch_phi_inputs_.equal_range(inst);
381     for (auto it = range.first; it != range.second; ++it) {
382         auto throwable_input = it->second;
383         auto throwable_input_interval = GetInstLifeIntervals(throwable_input);
384         live_set->Add(throwable_input->GetLinearNumber());
385         throwable_input_interval->AppendRange(live_range);
386     }
387     pending_catch_phi_inputs_.erase(inst);
388 }
389 
390 /*
391  * Increase ref-input liveness in the 'no-async-jit' mode, since GC can be triggered and delete ref during callee-method
392  * compilation
393  */
SetInputRange(const Inst * inst,const Inst * input,LiveRange live_range) const394 void LivenessAnalyzer::SetInputRange([[maybe_unused]] const Inst *inst, const Inst *input, LiveRange live_range) const
395 {
396     GetInstLifeIntervals(input)->AppendRange(live_range);
397 }
398 
399 /*
400  * CatchPhi does not handle inputs as regular instructions - instead of performing
401  * some action at CatchPhi's definition copy instruction are added before throwable instructions.
402  * Instead of extending input life interval until CatchPhi it is extended until throwable instruction.
403  */
AdjustCatchPhiInputsLifetime(Inst * inst)404 void LivenessAnalyzer::AdjustCatchPhiInputsLifetime(Inst *inst)
405 {
406     auto catch_phi = inst->CastToCatchPhi();
407 
408     for (ssize_t input_idx = catch_phi->GetInputsCount() - 1; input_idx >= 0; input_idx--) {
409         auto input_inst = catch_phi->GetDataFlowInput(input_idx);
410         auto throwable_inst = const_cast<Inst *>(catch_phi->GetThrowableInst(input_idx));
411 
412         pending_catch_phi_inputs_.insert({throwable_inst, input_inst});
413     }
414 }
415 
SetInstLifeNumber(const Inst * inst,LifeNumber number)416 void LivenessAnalyzer::SetInstLifeNumber([[maybe_unused]] const Inst *inst, LifeNumber number)
417 {
418     ASSERT(inst_life_numbers_.size() == inst->GetLinearNumber());
419     inst_life_numbers_.push_back(number);
420 }
421 
GetInstLifeNumber(Inst * inst) const422 LifeNumber LivenessAnalyzer::GetInstLifeNumber(Inst *inst) const
423 {
424     return inst_life_numbers_[inst->GetLinearNumber()];
425 }
426 
427 /*
428  * Create new lifetime intervals for instruction, check that instruction linear number is equal to intervals
429  * position in vector
430  */
CreateLifeIntervals(Inst * inst)431 void LivenessAnalyzer::CreateLifeIntervals(Inst *inst)
432 {
433     ASSERT(inst->GetLinearNumber() == inst_life_intervals_.size());
434     inst_life_intervals_.push_back(GetAllocator()->New<LifeIntervals>(GetAllocator(), inst));
435 }
436 
GetInstLifeIntervals(const Inst * inst) const437 LifeIntervals *LivenessAnalyzer::GetInstLifeIntervals(const Inst *inst) const
438 {
439     ASSERT(inst->GetLinearNumber() != INVALID_LINEAR_NUM);
440     return inst_life_intervals_[inst->GetLinearNumber()];
441 }
442 
SetBlockLiveRange(BasicBlock * block,LiveRange life_range)443 void LivenessAnalyzer::SetBlockLiveRange(BasicBlock *block, LiveRange life_range)
444 {
445     block_live_ranges_[block->GetId()] = life_range;
446 }
447 
GetBlockLiveRange(const BasicBlock * block) const448 LiveRange LivenessAnalyzer::GetBlockLiveRange(const BasicBlock *block) const
449 {
450     return block_live_ranges_[block->GetId()];
451 }
452 
SetBlockLiveSet(BasicBlock * block,InstLiveSet * live_set)453 void LivenessAnalyzer::SetBlockLiveSet(BasicBlock *block, InstLiveSet *live_set)
454 {
455     block_live_sets_[block->GetId()] = live_set;
456 }
457 
GetBlockLiveSet(BasicBlock * block) const458 InstLiveSet *LivenessAnalyzer::GetBlockLiveSet(BasicBlock *block) const
459 {
460     return block_live_sets_[block->GetId()];
461 }
462 
DumpLifeIntervals(std::ostream & out) const463 void LivenessAnalyzer::DumpLifeIntervals(std::ostream &out) const
464 {
465     for (auto bb : GetGraph()->GetBlocksRPO()) {
466         if (bb->GetId() >= GetBlocksCount()) {
467             continue;
468         }
469         auto block_range = GetBlockLiveRange(bb);
470         out << "BB " << bb->GetId() << "\t" << block_range.ToString() << std::endl;
471 
472         for (auto inst : bb->AllInsts()) {
473             if (inst->GetLinearNumber() == INVALID_LINEAR_NUM) {
474                 continue;
475             }
476             auto interval = GetInstLifeIntervals(inst);
477 
478             out << "v" << inst->GetId() << "\t";
479             for (auto sibling = interval; sibling != nullptr; sibling = sibling->GetSibling()) {
480                 out << sibling->ToString<false>() << "@ " << sibling->GetLocation().ToString(GetGraph()->GetArch())
481                     << "; ";
482             }
483             out << std::endl;
484         }
485     }
486     DumpLocationsUsage(out);
487 }
488 
DumpLocationsUsage(std::ostream & out) const489 void LivenessAnalyzer::DumpLocationsUsage(std::ostream &out) const
490 {
491     std::map<Register, std::vector<LifeIntervals *>> regs_intervals;
492     std::map<Register, std::vector<LifeIntervals *>> vregs_intervals;
493     std::map<Register, std::vector<LifeIntervals *>> slots_intervals;
494     for (auto &interval : inst_life_intervals_) {
495         for (auto sibling = interval; sibling != nullptr; sibling = sibling->GetSibling()) {
496             auto location = sibling->GetLocation();
497             if (location.IsFpRegister()) {
498                 ASSERT(DataType::IsFloatType(interval->GetType()));
499                 vregs_intervals[location.GetValue()].push_back(sibling);
500             } else if (location.IsRegister()) {
501                 regs_intervals[location.GetValue()].push_back(sibling);
502             } else if (location.IsStack()) {
503                 slots_intervals[location.GetValue()].push_back(sibling);
504             }
505         }
506     }
507 
508     for (auto intervals_map : {&regs_intervals, &vregs_intervals, &slots_intervals}) {
509         std::string loc_symbol;
510         if (intervals_map == &regs_intervals) {
511             out << std::endl << "Registers intervals" << std::endl;
512             loc_symbol = "r";
513         } else if (intervals_map == &vregs_intervals) {
514             out << std::endl << "Vector registers intervals" << std::endl;
515             loc_symbol = "vr";
516         } else {
517             ASSERT(intervals_map == &slots_intervals);
518             out << std::endl << "Stack slots intervals" << std::endl;
519             loc_symbol = "s";
520         }
521 
522         if (intervals_map->empty()) {
523             out << "-" << std::endl;
524             continue;
525         }
526         for (auto &[reg, intervals] : *intervals_map) {
527             std::sort(intervals.begin(), intervals.end(),
528                       [](const auto &lhs, const auto &rhs) { return lhs->GetBegin() < rhs->GetBegin(); });
529             out << loc_symbol << std::to_string(reg) << ": ";
530             auto delim = "";
531             for (auto &interval : intervals) {
532                 out << delim << interval->ToString<false>();
533                 delim = "; ";
534             }
535             out << std::endl;
536         }
537     }
538 }
539 
540 template <bool is_fp>
BlockPhysicalRegisters(LifeNumber block_from)541 void LivenessAnalyzer::BlockPhysicalRegisters(LifeNumber block_from)
542 {
543     auto arch = GetGraph()->GetArch();
544     RegMask caller_regs {GetCallerRegsMask(arch, is_fp)};
545     for (auto reg = GetFirstCallerReg(arch, is_fp); reg <= GetLastCallerReg(arch, is_fp); ++reg) {
546         if (caller_regs.test(reg)) {
547             BlockReg<is_fp>(reg, block_from);
548         }
549     }
550 }
551 
BlockFixedLocationRegister(Location location,LifeNumber ln)552 void LivenessAnalyzer::BlockFixedLocationRegister(Location location, LifeNumber ln)
553 {
554     if (location.IsRegister() && location.IsRegisterValid()) {
555         BlockReg<false>(location.GetValue(), ln);
556     } else if (location.IsFpRegister() && location.IsRegisterValid()) {
557         BlockReg<true>(location.GetValue(), ln);
558     }
559 }
560 
561 template <bool is_fp>
BlockReg(Register reg,LifeNumber block_from)562 void LivenessAnalyzer::BlockReg(Register reg, LifeNumber block_from)
563 {
564     auto &intervals = is_fp ? physical_vector_intervals_ : physical_general_intervals_;
565     auto interval = intervals.at(reg);
566     if (interval == nullptr) {
567         interval = GetGraph()->GetAllocator()->New<LifeIntervals>(GetGraph()->GetAllocator());
568         CHECK_NOT_NULL(interval);
569         interval->SetPhysicalReg(reg, is_fp ? DataType::FLOAT64 : DataType::UINT64);
570         intervals.at(reg) = interval;
571     }
572     interval->AppendRange(block_from, block_from + 1U);
573     interval->AddUsePosition(block_from);
574 }
575 
IsCallBlockingRegisters(Inst * inst) const576 bool LivenessAnalyzer::IsCallBlockingRegisters(Inst *inst) const
577 {
578     if (inst->IsCall()) {
579         return true;
580     }
581     if (inst->IsIntrinsic() && inst->CastToIntrinsic()->IsNativeCall()) {
582         return true;
583     }
584     return false;
585 }
586 
SplitAt(LifeNumber ln,ArenaAllocator * alloc)587 LifeIntervals *LifeIntervals::SplitAt(LifeNumber ln, ArenaAllocator *alloc)
588 {
589     ASSERT(!IsPhysical());
590     ASSERT(ln > GetBegin() && ln <= GetEnd());
591     auto split_child = alloc->New<LifeIntervals>(alloc, GetInst());
592     CHECK_NOT_NULL(split_child);
593     if (sibling_ != nullptr) {
594         split_child->sibling_ = sibling_;
595     }
596     split_child->is_split_sibling_ = true;
597 
598     sibling_ = split_child;
599     split_child->SetType(GetType());
600 
601     for (auto &range = live_ranges_.back(); range.GetEnd() > ln; range = live_ranges_.back()) {
602         live_ranges_.pop_back();
603         if (range.GetBegin() > ln) {
604             split_child->AppendRange(range);
605         } else {
606             split_child->AppendRange(ln, range.GetEnd());
607             range.SetEnd(ln);
608             if (range.GetBegin() != range.GetEnd()) {
609                 live_ranges_.push_back(range);
610             }
611 
612             break;
613         }
614     }
615 
616     // Move use positions to the child
617     auto it = use_positions_.lower_bound(ln);
618     split_child->use_positions_.insert(it, use_positions_.end());
619     use_positions_.erase(it, use_positions_.end());
620 
621     return split_child;
622 }
623 
MergeSibling()624 void LifeIntervals::MergeSibling()
625 {
626     ASSERT(sibling_ != nullptr);
627     while (!live_ranges_.empty()) {
628         sibling_->AppendRange(live_ranges_.back());
629         live_ranges_.pop_back();
630     }
631     live_ranges_ = std::move(sibling_->live_ranges_);
632 
633     for (auto &use_pos : sibling_->use_positions_) {
634         AddUsePosition(use_pos);
635     }
636     sibling_ = nullptr;
637 }
638 
FindSiblingAt(LifeNumber ln)639 LifeIntervals *LifeIntervals::FindSiblingAt(LifeNumber ln)
640 {
641     ASSERT(!IsSplitSibling());
642     for (auto head = this; head != nullptr; head = head->GetSibling()) {
643         if (head->GetBegin() <= ln && ln <= head->GetEnd()) {
644             return head;
645         }
646     }
647     return nullptr;
648 }
649 
Intersects(const LiveRange & range) const650 bool LifeIntervals::Intersects(const LiveRange &range) const
651 {
652     return  // the interval starts within the range
653         (range.GetBegin() <= GetBegin() && GetBegin() <= range.GetEnd()) ||
654         // the interval ends within the range
655         (range.GetBegin() <= GetEnd() && GetEnd() <= range.GetEnd()) ||
656         // the range is fully covered by the interval
657         (GetBegin() <= range.GetBegin() && range.GetEnd() <= GetEnd());
658 }
659 
GetFirstIntersectionWith(const LifeIntervals * other,LifeNumber search_from) const660 LifeNumber LifeIntervals::GetFirstIntersectionWith(const LifeIntervals *other, LifeNumber search_from) const
661 {
662     for (auto range : GetRanges()) {
663         if (range.GetEnd() <= search_from) {
664             continue;
665         }
666         for (auto other_range : other->GetRanges()) {
667             if (other_range.GetEnd() <= search_from) {
668                 continue;
669             }
670             auto range_begin = std::max<LifeNumber>(search_from, range.GetBegin());
671             auto other_range_begin = std::max<LifeNumber>(search_from, other_range.GetBegin());
672             if (range_begin <= other_range_begin) {
673                 if (other_range_begin < range.GetEnd()) {
674                     // [range]
675                     //    [other]
676                     return other_range_begin;
677                 }
678                 ASSERT(other_range_begin >= range.GetEnd());
679             } else {
680                 //     [range]
681                 // [other]
682                 if (range_begin < other_range.GetEnd()) {
683                     return range_begin;
684                 }
685                 ASSERT(range_begin >= other_range.GetEnd());
686             }
687         }
688     }
689     return INVALID_LIFE_NUMBER;
690 }
691 
IntersectsWith(const LifeIntervals * other) const692 bool LifeIntervals::IntersectsWith(const LifeIntervals *other) const
693 {
694     return GetFirstIntersectionWith(other) != INVALID_LIFE_NUMBER;
695 }
696 
697 }  // namespace panda::compiler
698