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 BB *curBB = cgFunc->GetFirstBB();
37 bool flag = false;
38 while (curBB != nullptr) {
39 for (OptimizationPattern *p : singlePassPatterns) {
40 if (p->Optimize(*curBB)) {
41 flag = p->IsKeepPosition();
42 p->SetKeepPosition(false);
43 break;
44 }
45 }
46
47 if (flag) {
48 flag = false;
49 } else {
50 curBB = curBB->GetNext();
51 }
52 }
53 }
54
55 if (CGOptions::IsDumpOptimizeCommonLog()) {
56 constexpr int arrSize = 80;
57 char post[arrSize];
58 errno_t cpyRet = strcpy_s(post, arrSize, "post-");
59 CHECK_FATAL(cpyRet == EOK, "call strcpy_s failed");
60 errno_t catRes = strcat_s(post, arrSize, name);
61 CHECK_FATAL(catRes == EOK, "call strcat_s failed ");
62 OptimizeLogger::GetLogger().Print(funcName);
63 }
64 OptimizeLogger::GetLogger().ClearLocal();
65 }
66
Search2Op(bool noOptimize)67 void OptimizationPattern::Search2Op(bool noOptimize)
68 {
69 checkOnly = noOptimize;
70 BB *curBB = cgFunc->GetFirstBB();
71 while (curBB != nullptr) {
72 bool changed = false;
73 do {
74 changed = Optimize(*curBB);
75 } while (changed);
76 if (keepPosition) {
77 keepPosition = false;
78 } else {
79 curBB = curBB->GetNext();
80 }
81 }
82 }
83
Log(uint32 bbID)84 void OptimizationPattern::Log(uint32 bbID)
85 {
86 OptimizeLogger::GetLogger().Log(patternName.c_str());
87 DotGenerator::SetColor(bbID, dotColor.c_str());
88 }
89
90 std::map<uint32, std::string> DotGenerator::coloringMap;
91
SetColor(uint32 bbID,const std::string & color)92 void DotGenerator::SetColor(uint32 bbID, const std::string &color)
93 {
94 coloringMap[bbID] = color;
95 }
96
GetFileName(const MIRModule & mirModule,const std::string & filePreFix)97 std::string DotGenerator::GetFileName(const MIRModule &mirModule, const std::string &filePreFix)
98 {
99 std::string fileName;
100 if (!filePreFix.empty()) {
101 fileName.append(filePreFix);
102 fileName.append("-");
103 }
104 fileName.append(mirModule.GetFileName());
105 for (uint32 i = 0; i < fileName.length(); i++) {
106 if (fileName[i] == ';' || fileName[i] == '/' || fileName[i] == '|') {
107 fileName[i] = '_';
108 }
109 }
110
111 fileName.append(".dot");
112 return fileName;
113 }
114
IsBackEdgeForLoop(const CGFuncLoops & loop,const BB & from,const BB & to)115 static bool IsBackEdgeForLoop(const CGFuncLoops &loop, const BB &from, const BB &to)
116 {
117 const BB *header = loop.GetHeader();
118 if (header->GetId() == to.GetId()) {
119 for (auto *be : loop.GetBackedge()) {
120 if (be->GetId() == from.GetId()) {
121 return true;
122 }
123 }
124 }
125 for (auto *inner : loop.GetInnerLoops()) {
126 if (IsBackEdgeForLoop(*inner, from, to)) {
127 return true;
128 }
129 }
130 return false;
131 }
IsBackEdge(const CGFunc & cgFunction,const BB & from,const BB & to)132 bool DotGenerator::IsBackEdge(const CGFunc &cgFunction, const BB &from, const BB &to)
133 {
134 for (const auto *loop : cgFunction.GetLoops()) {
135 if (IsBackEdgeForLoop(*loop, from, to)) {
136 return true;
137 }
138 }
139 return false;
140 }
141
DumpEdge(const CGFunc & cgFunction,std::ofstream & cfgFileOfStream,bool isIncludeEH)142 void DotGenerator::DumpEdge(const CGFunc &cgFunction, std::ofstream &cfgFileOfStream, bool isIncludeEH)
143 {
144 FOR_ALL_BB_CONST(bb, &cgFunction) {
145 for (auto *succBB : bb->GetSuccs()) {
146 cfgFileOfStream << "BB" << bb->GetId();
147 cfgFileOfStream << " -> "
148 << "BB" << succBB->GetId();
149 if (IsBackEdge(cgFunction, *bb, *succBB)) {
150 cfgFileOfStream << " [color=red]";
151 } else {
152 cfgFileOfStream << " [color=green]";
153 }
154 cfgFileOfStream << ";\n";
155 }
156 if (isIncludeEH) {
157 for (auto *ehSuccBB : bb->GetEhSuccs()) {
158 cfgFileOfStream << "BB" << bb->GetId();
159 cfgFileOfStream << " -> "
160 << "BB" << ehSuccBB->GetId();
161 cfgFileOfStream << "[color=red]";
162 cfgFileOfStream << ";\n";
163 }
164 }
165 }
166 }
167
FoundListOpndRegNum(ListOperand & listOpnd,const Insn & insnObj,regno_t vReg)168 bool DotGenerator::FoundListOpndRegNum(ListOperand &listOpnd, const Insn &insnObj, regno_t vReg)
169 {
170 bool exist = false;
171 for (auto op : listOpnd.GetOperands()) {
172 RegOperand *regOpnd = static_cast<RegOperand *>(op);
173 if (op->IsRegister() && regOpnd->GetRegisterNumber() == vReg) {
174 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
175 exist = true;
176 break;
177 }
178 }
179 return exist;
180 }
181
FoundMemAccessOpndRegNum(const MemOperand & memOperand,const Insn & insnObj,regno_t vReg)182 bool DotGenerator::FoundMemAccessOpndRegNum(const MemOperand &memOperand, const Insn &insnObj, regno_t vReg)
183 {
184 Operand *base = memOperand.GetBaseRegister();
185 Operand *offset = memOperand.GetIndexRegister();
186 bool exist = false;
187 if (base != nullptr && base->IsRegister()) {
188 RegOperand *regOpnd = static_cast<RegOperand *>(base);
189 if (regOpnd->GetRegisterNumber() == vReg) {
190 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
191 exist = true;
192 }
193 } else if (offset != nullptr && offset->IsRegister()) {
194 RegOperand *regOpnd = static_cast<RegOperand *>(offset);
195 if (regOpnd->GetRegisterNumber() == vReg) {
196 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
197 exist = true;
198 }
199 }
200 return exist;
201 }
202
FoundNormalOpndRegNum(const RegOperand & regOpnd,const Insn & insnObj,regno_t vReg)203 bool DotGenerator::FoundNormalOpndRegNum(const RegOperand ®Opnd, const Insn &insnObj, regno_t vReg)
204 {
205 bool exist = false;
206 if (regOpnd.GetRegisterNumber() == vReg) {
207 LogInfo::MapleLogger() << "BB" << insnObj.GetBB()->GetId() << " [style=filled, fillcolor=red];\n";
208 exist = true;
209 }
210 return exist;
211 }
212
DumpBBInstructions(const CGFunc & cgFunction,regno_t vReg,std::ofstream & cfgFile)213 void DotGenerator::DumpBBInstructions(const CGFunc &cgFunction, regno_t vReg, std::ofstream &cfgFile)
214 {
215 FOR_ALL_BB_CONST(bb, &cgFunction) {
216 if (vReg != 0) {
217 FOR_BB_INSNS_CONST(insn, bb) {
218 bool found = false;
219 uint32 opndNum = insn->GetOperandSize();
220 for (uint32 i = 0; i < opndNum; ++i) {
221 Operand &opnd = insn->GetOperand(i);
222 if (opnd.IsList()) {
223 auto &listOpnd = static_cast<ListOperand &>(opnd);
224 found = FoundListOpndRegNum(listOpnd, *insn, vReg);
225 } else if (opnd.IsMemoryAccessOperand()) {
226 auto &memOpnd = static_cast<MemOperand &>(opnd);
227 found = FoundMemAccessOpndRegNum(memOpnd, *insn, vReg);
228 } else {
229 if (opnd.IsRegister()) {
230 auto ®Opnd = static_cast<RegOperand &>(opnd);
231 found = FoundNormalOpndRegNum(regOpnd, *insn, vReg);
232 }
233 }
234 if (found) {
235 break;
236 }
237 }
238 if (found) {
239 break;
240 }
241 }
242 }
243 cfgFile << "BB" << bb->GetId() << "[";
244 auto it = coloringMap.find(bb->GetId());
245 if (it != coloringMap.end()) {
246 cfgFile << "style=filled,fillcolor=" << it->second << ",";
247 }
248 if (bb->GetKind() == BB::kBBIf) {
249 cfgFile << "shape=diamond,label= \" BB" << bb->GetId() << ":\n";
250 } else {
251 cfgFile << "shape=box,label= \" BB" << bb->GetId() << ":\n";
252 }
253 cfgFile << "{ ";
254 cfgFile << bb->GetKindName() << "\n";
255 cfgFile << bb->GetFrequency() << "\n";
256 if (bb->GetLabIdx() != 0) {
257 cfgFile << "LabIdx=" << bb->GetLabIdx() << "\n";
258 }
259 cfgFile << "}\"];\n";
260 }
261 }
262
263 /* Generate dot file for cfg */
GenerateDot(const std::string & preFix,const CGFunc & cgFunc,const MIRModule & mod,bool includeEH,const std::string fname,regno_t vReg)264 void DotGenerator::GenerateDot(const std::string &preFix, const CGFunc &cgFunc, const MIRModule &mod, bool includeEH,
265 const std::string fname, regno_t vReg)
266 {
267 std::ofstream cfgFile;
268 std::streambuf *coutBuf = std::cout.rdbuf(); /* keep original cout buffer */
269 std::streambuf *buf = cfgFile.rdbuf();
270 std::cout.rdbuf(buf);
271 std::string fileName = GetFileName(mod, (preFix + "-" + fname));
272
273 cfgFile.open(fileName, std::ios::trunc);
274 CHECK_FATAL(cfgFile.is_open(), "Failed to open output file: %s", fileName.c_str());
275 cfgFile << "digraph {\n";
276 /* dump edge */
277 DumpEdge(cgFunc, cfgFile, includeEH);
278
279 /* dump instruction in each BB */
280 DumpBBInstructions(cgFunc, vReg, cfgFile);
281
282 cfgFile << "}\n";
283 coloringMap.clear();
284 cfgFile.flush();
285 cfgFile.close();
286 std::cout.rdbuf(coutBuf);
287 }
288
Print(const std::string & funcName)289 void OptimizeLogger::Print(const std::string &funcName)
290 {
291 if (!localStat.empty()) {
292 LogInfo::MapleLogger() << funcName << '\n';
293 for (const auto &localStatPair : localStat) {
294 LogInfo::MapleLogger() << "Optimized " << localStatPair.first << ":" << localStatPair.second << "\n";
295 }
296
297 ClearLocal();
298 LogInfo::MapleLogger() << "Total:" << '\n';
299 for (const auto &globalStatPair : globalStat) {
300 LogInfo::MapleLogger() << "Optimized " << globalStatPair.first << ":" << globalStatPair.second << "\n";
301 }
302 }
303 }
304
Log(const std::string & patternName)305 void OptimizeLogger::Log(const std::string &patternName)
306 {
307 auto itemInGlobal = globalStat.find(patternName);
308 if (itemInGlobal != globalStat.end()) {
309 itemInGlobal->second++;
310 } else {
311 (void)globalStat.emplace(std::pair<const std::string, int>(patternName, 1));
312 }
313 auto itemInLocal = localStat.find(patternName);
314 if (itemInLocal != localStat.end()) {
315 itemInLocal->second++;
316 } else {
317 (void)localStat.emplace(std::pair<const std::string, int>(patternName, 1));
318 }
319 }
320
ClearLocal()321 void OptimizeLogger::ClearLocal()
322 {
323 localStat.clear();
324 }
325 } /* namespace maplebe */
326