• 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 #ifndef COMPILER_OPTIMIZER_ANALYSIS_LIVE_REGISTERS_H
17 #define COMPILER_OPTIMIZER_ANALYSIS_LIVE_REGISTERS_H
18 
19 #include <optimizer/ir/inst.h>
20 #include <optimizer/ir/graph.h>
21 #include "utils/arena_containers.h"
22 #include "optimizer/pass.h"
23 #include "optimizer/analysis/liveness_analyzer.h"
24 
25 namespace panda::compiler {
26 
27 using LifeIntervalsIt = ArenaVector<LifeIntervals *>::iterator;
28 class LifeIntervalsTreeNode {
29 public:
LifeIntervalsTreeNode(LifeNumber min_value,LifeNumber max_value,LifeIntervalsIt begin,LifeIntervalsIt end)30     explicit LifeIntervalsTreeNode(LifeNumber min_value, LifeNumber max_value, LifeIntervalsIt begin,
31                                    LifeIntervalsIt end)
32         : min_value_(min_value), max_value_(max_value), begin_(begin), end_(end)
33     {
34     }
35 
36     DEFAULT_MOVE_SEMANTIC(LifeIntervalsTreeNode);
37     DEFAULT_COPY_SEMANTIC(LifeIntervalsTreeNode);
38     ~LifeIntervalsTreeNode() = default;
39 
GetMidpoint()40     LifeNumber GetMidpoint() const
41     {
42         return (min_value_ + max_value_) / 2;
43     }
44 
GetMinValue()45     LifeNumber GetMinValue() const
46     {
47         return min_value_;
48     }
49 
GetMaxValue()50     LifeNumber GetMaxValue() const
51     {
52         return max_value_;
53     }
54 
GetBegin()55     LifeIntervalsIt GetBegin() const
56     {
57         return begin_;
58     }
59 
GetEnd()60     LifeIntervalsIt GetEnd() const
61     {
62         return end_;
63     }
64 
GetLeft()65     LifeIntervalsTreeNode *GetLeft() const
66     {
67         return left_;
68     }
69 
SetLeft(LifeIntervalsTreeNode * left)70     void SetLeft(LifeIntervalsTreeNode *left)
71     {
72         ASSERT(left_ == nullptr);
73         left_ = left;
74     }
75 
GetRight()76     LifeIntervalsTreeNode *GetRight() const
77     {
78         return right_;
79     }
80 
SetRight(LifeIntervalsTreeNode * right)81     void SetRight(LifeIntervalsTreeNode *right)
82     {
83         ASSERT(right_ == nullptr);
84         right_ = right;
85     }
86 
87 private:
88     LifeNumber min_value_;
89     LifeNumber max_value_;
90     LifeIntervalsIt begin_;
91     LifeIntervalsIt end_;
92     LifeIntervalsTreeNode *left_ {nullptr};
93     LifeIntervalsTreeNode *right_ {nullptr};
94 };
95 
96 // Simplified intervals tree implementation.
97 // Each LifeIntervalsTreeNode stores intervals covering the mid point associated with a node, these intervals
98 // sorted by the life range end in descending order. Every left child stores intervals ended before current node's
99 // mid point and every right child stores intervals started after current node's mid point.
100 class LifeIntervalsTree {
101 public:
BuildIntervalsTree(Graph * graph)102     static LifeIntervalsTree *BuildIntervalsTree(Graph *graph)
103     {
104         ASSERT(graph->IsAnalysisValid<LivenessAnalyzer>());
105         return LifeIntervalsTree::BuildIntervalsTree(graph->GetAnalysis<LivenessAnalyzer>().GetLifeIntervals(), graph);
106     }
107 
108     static LifeIntervalsTree *BuildIntervalsTree(const ArenaVector<LifeIntervals *> &life_intervals,
109                                                  const Graph *graph);
110 
LifeIntervalsTree(LifeIntervalsTreeNode * root)111     explicit LifeIntervalsTree(LifeIntervalsTreeNode *root) : root_(root) {};
112 
113     DEFAULT_MOVE_SEMANTIC(LifeIntervalsTree);
114     DEFAULT_COPY_SEMANTIC(LifeIntervalsTree);
115     ~LifeIntervalsTree() = default;
116 
117     template <bool live_inputs = true, typename Func>
118     void VisitIntervals(LifeNumber ln, Func func, const Inst *skip_inst = nullptr) const
119     {
120         for (auto node = root_; node != nullptr; node = ln < node->GetMidpoint() ? node->GetLeft() : node->GetRight()) {
121             if (ln < node->GetMinValue() || ln > node->GetMaxValue()) {
122                 // current node does not contain intervals covering target life number
123                 continue;
124             }
125             for (auto i = node->GetBegin(); i < node->GetEnd(); i++) {
126                 auto interval = *i;
127                 if (interval->GetInst() == skip_inst) {
128                     continue;
129                 }
130                 if (ln > interval->GetEnd()) {
131                     // intervals are ordered by its end in descending order, so we can stop on first interval
132                     // that ends before target life number
133                     break;
134                 }
135                 if (interval->SplitCover<live_inputs>(ln)) {
136                     func(interval);
137                 }
138             }
139         }
140     }
141 
142 private:
143     LifeIntervalsTreeNode *root_;
144 };
145 
146 // Analysis collecting live intervals with assigned registers and
147 // allowing to visit those of them which are intersecting with specific instruction.
148 class LiveRegisters : public Analysis {
149 public:
LiveRegisters(Graph * graph)150     explicit LiveRegisters(Graph *graph) : Analysis(graph) {};
151 
152     NO_MOVE_SEMANTIC(LiveRegisters);
153     NO_COPY_SEMANTIC(LiveRegisters);
154     ~LiveRegisters() override = default;
155 
RunImpl()156     bool RunImpl() override
157     {
158         inst_life_intervals_tree_ = LifeIntervalsTree::BuildIntervalsTree(GetGraph());
159         return true;
160     }
161 
162     // Visit all live intervals with assigned registers intersecting with specified instruction
163     // (excluding the interval for that instruction).
164     template <bool live_inputs = true, typename Func>
VisitIntervalsWithLiveRegisters(Inst * inst,Func func)165     void VisitIntervalsWithLiveRegisters(Inst *inst, Func func)
166     {
167         ASSERT(GetGraph()->IsAnalysisValid<LivenessAnalyzer>());
168 
169         if (inst_life_intervals_tree_ == nullptr) {
170             return;
171         }
172 
173         auto &la = GetGraph()->GetAnalysis<LivenessAnalyzer>();
174         auto li = la.GetInstLifeIntervals(inst);
175         inst_life_intervals_tree_->VisitIntervals<live_inputs, Func>(li->GetBegin(), func, inst);
176     }
177 
GetPassName()178     const char *GetPassName() const override
179     {
180         return "Live Registers";
181     }
182 
183 private:
184     LifeIntervalsTree *inst_life_intervals_tree_ {nullptr};
185 };
186 
187 }  // namespace panda::compiler
188 #endif  // COMPILER_OPTIMIZER_ANALYSIS_LIVE_REGISTERS_H
189