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