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