1 /*
2 * Copyright (c) 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 "optimize_common.h"
17 #include <fstream>
18
19 /* This file provides common class and function for cfgo and ico. */
20 namespace maplebe {
Run(const std::string & funcName,bool checkOnly)21 void Optimizer::Run(const std::string &funcName, bool checkOnly)
22 {
23 /* Initialize cfg optimization patterns */
24 InitOptimizePatterns();
25
26 /* For each pattern, search cgFunc for optimization */
27 for (OptimizationPattern *p : diffPassPatterns) {
28 p->Search2Op(checkOnly);
29 }
30 /* Search the cgFunc for multiple possible optimizations in one pass */
31 if (!singlePassPatterns.empty()) {
32 bool changed = false;
33 do {
34 changed = false;
35 for (OptimizationPattern *p : singlePassPatterns) {
36 BB *curBB = cgFunc->GetFirstBB();
37 while (curBB != nullptr) {
38 if (p->Optimize(*curBB)) {
39 changed = true;
40 }
41 if (p->IsKeepPosition()) {
42 p->SetKeepPosition(false);
43 } else {
44 curBB = curBB->GetNext();
45 }
46 }
47 }
48 } while (changed);
49 }
50
51 // Update commonExitBB info, especially in infinite loop case.
52 // But we can not get the commonExitBB by traversal CFG, so
53 // it needs to be handled separately.
54 cgFunc->GetTheCFG()->UpdateCommonExitBBInfo();
55
56 OptimizeLogger::GetLogger().ClearLocal();
57 }
58
Search2Op(bool noOptimize)59 bool OptimizationPattern::Search2Op(bool noOptimize)
60 {
61 bool hasChange = false;
62 checkOnly = noOptimize;
63 InitPattern();
64 BB *curBB = cgFunc->GetFirstBB();
65 while (curBB != nullptr) {
66 bool changed = false;
67 do {
68 changed = Optimize(*curBB);
69 hasChange = hasChange || changed;
70 } while (changed);
71 if (keepPosition) {
72 keepPosition = false;
73 } else {
74 curBB = curBB->GetNext();
75 }
76 }
77 return hasChange;
78 }
79
Log(uint32 bbID)80 void OptimizationPattern::Log(uint32 bbID)
81 {
82 OptimizeLogger::GetLogger().Log(patternName.c_str());
83 DotGenerator::SetColor(bbID, dotColor.c_str());
84 }
85
86 std::map<uint32, std::string> DotGenerator::coloringMap;
87
SetColor(uint32 bbID,const std::string & color)88 void DotGenerator::SetColor(uint32 bbID, const std::string &color)
89 {
90 coloringMap[bbID] = color;
91 }
92
GetFileName(const MIRModule & mirModule,const std::string & filePreFix)93 std::string DotGenerator::GetFileName(const MIRModule &mirModule, const std::string &filePreFix)
94 {
95 std::string fileName;
96 if (!filePreFix.empty()) {
97 fileName.append(filePreFix);
98 fileName.append("-");
99 }
100 fileName.append(mirModule.GetFileName());
101 for (uint32 i = 0; i < fileName.length(); i++) {
102 if (fileName[i] == ';' || fileName[i] == '/' || fileName[i] == '|') {
103 fileName[i] = '_';
104 }
105 }
106
107 fileName.append(".dot");
108 return fileName;
109 }
110
DumpEdge(const CGFunc & cgFunction,std::ofstream & cfgFileOfStream)111 void DotGenerator::DumpEdge(const CGFunc &cgFunction, std::ofstream &cfgFileOfStream)
112 {
113 FOR_ALL_BB_CONST(bb, &cgFunction)
114 {
115 for (auto *succBB : bb->GetSuccs()) {
116 cfgFileOfStream << "BB" << bb->GetId() << " -> " << "BB" << succBB->GetId() << " [color=green];\n";
117 }
118 }
119 }
120
FoundListOpndRegNum(ListOperand & listOpnd,const Insn & insnObj,regno_t vReg)121 bool DotGenerator::FoundListOpndRegNum(ListOperand &listOpnd, const Insn &insnObj, regno_t vReg)
122 {
123 bool exist = false;
124 for (auto op : listOpnd.GetOperands()) {
125 RegOperand *regOpnd = static_cast<RegOperand *>(op);
126 if (op->IsRegister() && regOpnd->GetRegisterNumber() == vReg) {
127 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
128 exist = true;
129 break;
130 }
131 }
132 return exist;
133 }
134
FoundMemAccessOpndRegNum(const MemOperand & memOperand,const Insn & insnObj,regno_t vReg)135 bool DotGenerator::FoundMemAccessOpndRegNum(const MemOperand &memOperand, const Insn &insnObj, regno_t vReg)
136 {
137 Operand *base = memOperand.GetBaseRegister();
138 Operand *offset = memOperand.GetIndexRegister();
139 bool exist = false;
140 if (base != nullptr && base->IsRegister()) {
141 RegOperand *regOpnd = static_cast<RegOperand *>(base);
142 if (regOpnd->GetRegisterNumber() == vReg) {
143 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
144 exist = true;
145 }
146 } else if (offset != nullptr && offset->IsRegister()) {
147 RegOperand *regOpnd = static_cast<RegOperand *>(offset);
148 if (regOpnd->GetRegisterNumber() == vReg) {
149 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
150 exist = true;
151 }
152 }
153 return exist;
154 }
155
FoundNormalOpndRegNum(const RegOperand & regOpnd,const Insn & insnObj,regno_t vReg)156 bool DotGenerator::FoundNormalOpndRegNum(const RegOperand ®Opnd, const Insn &insnObj, regno_t vReg)
157 {
158 bool exist = false;
159 if (regOpnd.GetRegisterNumber() == vReg) {
160 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
161 exist = true;
162 }
163 return exist;
164 }
165
DumpBBInstructions(const CGFunc & cgFunction,regno_t vReg,std::ofstream & cfgFile)166 void DotGenerator::DumpBBInstructions(const CGFunc &cgFunction, regno_t vReg, std::ofstream &cfgFile)
167 {
168 FOR_ALL_BB_CONST(bb, &cgFunction)
169 {
170 if (vReg != 0) {
171 FOR_BB_INSNS_CONST(insn, bb)
172 {
173 bool found = false;
174 uint32 opndNum = insn->GetOperandSize();
175 for (uint32 i = 0; i < opndNum; ++i) {
176 Operand &opnd = insn->GetOperand(i);
177 if (opnd.IsList()) {
178 auto &listOpnd = static_cast<ListOperand &>(opnd);
179 found = FoundListOpndRegNum(listOpnd, *insn, vReg);
180 } else if (opnd.IsMemoryAccessOperand()) {
181 auto &memOpnd = static_cast<MemOperand &>(opnd);
182 found = FoundMemAccessOpndRegNum(memOpnd, *insn, vReg);
183 } else {
184 if (opnd.IsRegister()) {
185 auto ®Opnd = static_cast<RegOperand &>(opnd);
186 found = FoundNormalOpndRegNum(regOpnd, *insn, vReg);
187 }
188 }
189 if (found) {
190 break;
191 }
192 }
193 if (found) {
194 break;
195 }
196 }
197 }
198 cfgFile << "BB" << bb->GetId() << "[";
199 auto it = coloringMap.find(bb->GetId());
200 if (it != coloringMap.end()) {
201 cfgFile << "style=filled,fillcolor=" << it->second << ",";
202 }
203 if (bb->GetKind() == BB::kBBIf) {
204 cfgFile << "shape=diamond,label= \" BB" << bb->GetId() << ":\n";
205 } else {
206 cfgFile << "shape=box,label= \" BB" << bb->GetId() << ":\n";
207 }
208 cfgFile << "{ ";
209 cfgFile << bb->GetKindName() << "\n";
210 cfgFile << bb->GetFrequency() << "\n";
211 if (bb->GetLabIdx() != 0) {
212 cfgFile << "LabIdx=" << bb->GetLabIdx() << "\n";
213 }
214 cfgFile << "}\"];\n";
215 }
216 }
217
218 /* Generate dot file for cfg */
GenerateDot(const std::string & preFix,const CGFunc & cgFunc,const MIRModule & mod,const std::string fname,regno_t vReg)219 void DotGenerator::GenerateDot(const std::string &preFix, const CGFunc &cgFunc, const MIRModule &mod,
220 const std::string fname, regno_t vReg)
221 {
222 std::ofstream cfgFile;
223 std::streambuf *coutBuf = std::cout.rdbuf(); /* keep original cout buffer */
224 std::streambuf *buf = cfgFile.rdbuf();
225 std::cout.rdbuf(buf);
226 std::string fileName = GetFileName(mod, (preFix + "-" + fname));
227
228 cfgFile.open(fileName, std::ios::trunc);
229 CHECK_FATAL(cfgFile.is_open(), "Failed to open output file: %s", fileName.c_str());
230 cfgFile << "digraph {\n";
231 /* dump edge */
232 DumpEdge(cgFunc, cfgFile);
233
234 /* dump instruction in each BB */
235 DumpBBInstructions(cgFunc, vReg, cfgFile);
236
237 cfgFile << "}\n";
238 coloringMap.clear();
239 cfgFile.flush();
240 cfgFile.close();
241 std::cout.rdbuf(coutBuf);
242 }
243
Print(const std::string & funcName)244 void OptimizeLogger::Print(const std::string &funcName)
245 {
246 if (!localStat.empty()) {
247 LogInfo::MapleLogger() << funcName << '\n';
248 for (const auto &localStatPair : localStat) {
249 LogInfo::MapleLogger() << "Optimized " << localStatPair.first << ":" << localStatPair.second << "\n";
250 }
251
252 ClearLocal();
253 LogInfo::MapleLogger() << "Total:" << '\n';
254 for (const auto &globalStatPair : globalStat) {
255 LogInfo::MapleLogger() << "Optimized " << globalStatPair.first << ":" << globalStatPair.second << "\n";
256 }
257 }
258 }
259
Log(const std::string & patternName)260 void OptimizeLogger::Log(const std::string &patternName)
261 {
262 auto itemInGlobal = globalStat.find(patternName);
263 if (itemInGlobal != globalStat.end()) {
264 itemInGlobal->second++;
265 } else {
266 (void)globalStat.emplace(std::pair<const std::string, int>(patternName, 1));
267 }
268 auto itemInLocal = localStat.find(patternName);
269 if (itemInLocal != localStat.end()) {
270 itemInLocal->second++;
271 } else {
272 (void)localStat.emplace(std::pair<const std::string, int>(patternName, 1));
273 }
274 }
275
ClearLocal()276 void OptimizeLogger::ClearLocal()
277 {
278 localStat.clear();
279 }
280 } /* namespace maplebe */
281