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 #include "cse.h"
17 #include "utils/logger.h"
18 #include "optimizer/analysis/rpo.h"
19 #include "optimizer/analysis/dominators_tree.h"
20 #include "algorithm"
21 #include "compiler_logger.h"
22
23 namespace ark::compiler {
LocalCse()24 void Cse::LocalCse()
25 {
26 deletedInsts_.clear();
27 candidates_.clear();
28 for (auto bb : GetGraph()->GetBlocksRPO()) {
29 candidates_.clear();
30 for (auto inst : bb->Insts()) {
31 if (!IsLegalExp(inst)) {
32 continue;
33 }
34 // match the insts in candidates
35 Exp exp = GetExp(inst);
36 if (AllNotIn(candidates_, inst)) {
37 InstVector emptyTmp(GetGraph()->GetLocalAllocator()->Adapter());
38 emptyTmp.emplace_back(inst);
39 candidates_.emplace(exp, std::move(emptyTmp));
40 continue;
41 }
42 if (NotIn(candidates_, exp)) {
43 exp = GetExpCommutative(inst);
44 }
45
46 auto &cntainer = candidates_.at(exp);
47 auto iter = std::find_if(cntainer.begin(), cntainer.end(), Finder(inst));
48 if (iter != cntainer.end()) {
49 inst->ReplaceUsers(*iter);
50 deletedInsts_.emplace_back(inst);
51 } else {
52 cntainer.emplace_back(inst);
53 }
54 }
55 }
56 RemoveInstsIn(&deletedInsts_);
57 }
58
TryAddReplacePair(Inst * inst)59 void Cse::TryAddReplacePair(Inst *inst)
60 {
61 if (!IsLegalExp(inst) || AllNotIn(candidates_, inst)) {
62 return;
63 }
64 Exp exp = NotIn(candidates_, GetExp(inst)) ? GetExpCommutative(inst) : GetExp(inst);
65 auto &cntainer = candidates_.at(exp);
66 auto iter = std::find_if(cntainer.begin(), cntainer.end(), Finder(inst));
67 if (iter != cntainer.end()) {
68 replacePair_.emplace_back(inst, *iter);
69 }
70 }
71
CollectTreeForest()72 void Cse::CollectTreeForest()
73 {
74 replacePair_.clear();
75 for (auto bb : GetGraph()->GetBlocksRPO()) {
76 if (bb->IsEndBlock()) {
77 continue;
78 }
79 candidates_.clear();
80 for (auto inst : bb->Insts()) {
81 if (!IsLegalExp(inst)) {
82 continue;
83 }
84 auto exp = GetExp(inst);
85 if (AllNotIn(candidates_, inst)) {
86 InstVector vectmp(GetGraph()->GetLocalAllocator()->Adapter());
87 vectmp.emplace_back(inst);
88 candidates_.emplace(exp, std::move(vectmp));
89 } else if (!NotIn(candidates_, exp)) {
90 candidates_.at(exp).emplace_back(inst);
91 } else {
92 candidates_.at(GetExpCommutative(inst)).emplace_back(inst);
93 }
94 }
95 if (candidates_.empty()) {
96 continue;
97 }
98 for (auto domed : bb->GetDominatedBlocks()) {
99 for (auto inst : domed->Insts()) {
100 TryAddReplacePair(inst);
101 }
102 }
103 }
104 }
105
106 /// Convert the tree-forest structure of replace_pair into star-forest structure
ConvertTreeForestToStarForest()107 void Cse::ConvertTreeForestToStarForest()
108 {
109 minReplaceStar_.clear();
110 for (auto rpair : replacePair_) {
111 Inst *temp = rpair.second;
112 auto it = replacePair_.begin();
113 do {
114 it = replacePair_.begin();
115 while (it != replacePair_.end() && it->first != temp) {
116 it++;
117 }
118 if (it != replacePair_.end()) {
119 temp = it->second;
120 }
121 } while (it != replacePair_.end());
122
123 minReplaceStar_.emplace_back(temp, rpair.first);
124 }
125 }
126
EliminateAlongDomTree()127 void Cse::EliminateAlongDomTree()
128 {
129 // Eliminate along Dominator tree (based on star structure)
130 deletedInsts_.clear();
131 for (auto pair : minReplaceStar_) {
132 pair.second->ReplaceUsers(pair.first);
133 deletedInsts_.emplace_back(pair.second);
134 }
135 RemoveInstsIn(&deletedInsts_);
136 }
137
BuildSetOfPairs(BasicBlock * block)138 void Cse::BuildSetOfPairs(BasicBlock *block)
139 {
140 sameExpPair_.clear();
141 auto bbl = block->GetPredsBlocks()[0];
142 auto bbr = block->GetPredsBlocks()[1];
143 for (auto instl : bbl->Insts()) {
144 if (!IsLegalExp(instl) || InVector(deletedInsts_, instl)) {
145 continue;
146 }
147 Exp expl = GetExp(instl);
148 if (!NotIn(sameExpPair_, expl)) {
149 auto &pair = sameExpPair_.at(expl);
150 pair.first.emplace_back(instl);
151 continue;
152 }
153 if (!AllNotIn(sameExpPair_, instl)) {
154 auto &pair = sameExpPair_.at(GetExpCommutative(instl));
155 pair.first.emplace_back(instl);
156 continue;
157 }
158 for (auto instr : bbr->Insts()) {
159 if (!IsLegalExp(instr) || (NotSameExp(GetExp(instr), expl) && NotSameExp(GetExpCommutative(instr), expl)) ||
160 InVector(deletedInsts_, instr)) {
161 continue;
162 }
163 if (!NotIn(sameExpPair_, expl)) {
164 auto &pair = sameExpPair_.at(expl);
165 pair.second.emplace_back(instr);
166 continue;
167 }
168 InstVector emptyl(GetGraph()->GetLocalAllocator()->Adapter());
169 emptyl.emplace_back(instl);
170 InstVector emptyr(GetGraph()->GetLocalAllocator()->Adapter());
171 emptyr.emplace_back(instr);
172 sameExpPair_.emplace(expl, std::make_pair(std::move(emptyl), std::move(emptyr)));
173 }
174 }
175 }
176
DomTreeCse()177 void Cse::DomTreeCse()
178 {
179 CollectTreeForest();
180 ConvertTreeForestToStarForest();
181 EliminateAlongDomTree();
182 }
183
GlobalCse()184 void Cse::GlobalCse()
185 {
186 // Cse should not be used in OSR mode.
187 if (GetGraph()->IsOsrMode()) {
188 return;
189 }
190
191 deletedInsts_.clear();
192 matchedTuple_.clear();
193 static constexpr size_t TWO_PREDS = 2;
194 // Find out redundant insts
195 for (auto bb : GetGraph()->GetBlocksRPO()) {
196 if (bb->GetPredsBlocks().size() != TWO_PREDS) {
197 continue;
198 }
199 BuildSetOfPairs(bb);
200 if (sameExpPair_.empty()) {
201 continue;
202 }
203 // Build the set of matched insts
204 for (auto inst : bb->Insts()) {
205 if (!IsLegalExp(inst) || AllNotIn(sameExpPair_, inst)) {
206 continue;
207 }
208 Exp exp = NotIn(sameExpPair_, GetExp(inst)) ? GetExpCommutative(inst) : GetExp(inst);
209 auto &pair = sameExpPair_.find(exp)->second;
210 ASSERT(!pair.first.empty());
211 auto instl = *pair.first.begin();
212 // If one decides to enable Cse in OSR mode then
213 // ensure that inst's basic block is not OsrEntry.
214 deletedInsts_.emplace_back(inst);
215 auto lrpair = std::make_pair(instl, *(pair.second.begin()));
216 matchedTuple_.emplace_back(inst, std::move(lrpair));
217 }
218 }
219 // Add phi instruction
220 matchedTuple_.shrink_to_fit();
221 for (auto tuple : matchedTuple_) {
222 auto inst = tuple.first;
223 auto phi = GetGraph()->CreateInstPhi(inst->GetType(), inst->GetPc());
224 inst->ReplaceUsers(phi);
225 inst->GetBasicBlock()->AppendPhi(phi);
226 auto &pair = tuple.second;
227 phi->AppendInput(pair.first);
228 phi->AppendInput(pair.second);
229 }
230 RemoveInstsIn(&deletedInsts_);
231 }
232
RunImpl()233 bool Cse::RunImpl()
234 {
235 LocalCse();
236 DomTreeCse();
237 GlobalCse();
238 if (!isApplied_) {
239 COMPILER_LOG(DEBUG, CSE_OPT) << "Cse does not find duplicate insts";
240 }
241 return isApplied_;
242 }
243 } // namespace ark::compiler
244