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