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