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 "cg_ssa.h"
17 #include "cg.h"
18
19 #include "optimize_common.h"
20
21 namespace maplebe {
22 uint32 CGSSAInfo::SSARegNObase = 100;
ConstructSSA()23 void CGSSAInfo::ConstructSSA()
24 {
25 InsertPhiInsn();
26 /* Rename variables */
27 RenameVariablesForBB(domInfo->GetCommonEntryBB().GetId());
28 #if DEBUG
29 /* Check phiListOpnd, must be ssaForm */
30 FOR_ALL_BB(bb, cgFunc)
31 {
32 FOR_BB_INSNS(insn, bb)
33 {
34 if (!insn->IsPhi()) {
35 continue;
36 }
37 Operand &phiListOpnd = insn->GetOperand(kInsnSecondOpnd);
38 CHECK_FATAL(phiListOpnd.IsPhi(), "unexpect phi operand");
39 MapleMap<uint32, RegOperand *> &phiList = static_cast<PhiOperand &>(phiListOpnd).GetOperands();
40 for (auto &phiOpndIt : phiList) {
41 if (!phiOpndIt.second->IsSSAForm()) {
42 CHECK_FATAL(false, "phiOperand is not ssaForm!");
43 }
44 }
45 }
46 }
47 #endif
48 cgFunc->SetSSAvRegCount(static_cast<uint32>(GetAllSSAOperands().size()) + SSARegNObase + 1);
49 /* save reversePostOrder of bbs for rectify validbit */
50 SetReversePostOrder();
51 }
52
MarkInsnsInSSA(Insn & insn)53 void CGSSAInfo::MarkInsnsInSSA(Insn &insn)
54 {
55 CHECK_FATAL(insn.GetId() == 0, "insn is not clean !!"); /* change to assert*/
56 insnCount += kInsnNum2;
57 insn.SetId(static_cast<uint32>(insnCount));
58 }
59
InsertPhiInsn()60 void CGSSAInfo::InsertPhiInsn()
61 {
62 FOR_ALL_BB(bb, cgFunc)
63 {
64 FOR_BB_INSNS(insn, bb)
65 {
66 if (!insn->IsMachineInstruction()) {
67 continue;
68 }
69 std::set<uint32> defRegNOs = insn->GetDefRegs();
70 for (auto vRegNO : defRegNOs) {
71 RegOperand *virtualOpnd = cgFunc->GetVirtualRegisterOperand(vRegNO);
72 if (virtualOpnd != nullptr) {
73 PrunedPhiInsertion(*bb, *virtualOpnd);
74 }
75 }
76 }
77 }
78 }
79
PrunedPhiInsertion(const BB & bb,RegOperand & virtualOpnd)80 void CGSSAInfo::PrunedPhiInsertion(const BB &bb, RegOperand &virtualOpnd)
81 {
82 regno_t vRegNO = virtualOpnd.GetRegisterNumber();
83 MapleVector<uint32> frontiers = domInfo->GetDomFrontier(bb.GetId());
84 for (auto i : frontiers) {
85 BB *phiBB = cgFunc->GetBBFromID(i);
86 CHECK_FATAL(phiBB != nullptr, "get phiBB failed change to DEBUG_ASSERT");
87 if (phiBB->HasPhiInsn(vRegNO)) {
88 continue;
89 }
90 if (phiBB->GetLiveIn()->TestBit(vRegNO)) {
91 CG *codeGen = cgFunc->GetCG();
92 PhiOperand &phiList = codeGen->CreatePhiOperand(*memPool, ssaAlloc);
93 /* do not insert phi opnd when insert phi insn? */
94 for (auto prevBB : phiBB->GetPreds()) {
95 if (prevBB->GetLiveOut()->TestBit(vRegNO)) {
96 auto *paraOpnd = static_cast<RegOperand *>(virtualOpnd.Clone(*tempMp));
97 phiList.InsertOpnd(prevBB->GetId(), *paraOpnd);
98 } else {
99 CHECK_FATAL(false, "multipule BB in");
100 }
101 }
102 Insn &phiInsn = codeGen->BuildPhiInsn(virtualOpnd, phiList);
103 MarkInsnsInSSA(phiInsn);
104 bool insertSuccess = false;
105 FOR_BB_INSNS(insn, phiBB)
106 {
107 if (insn->IsMachineInstruction()) {
108 (void)phiBB->InsertInsnBefore(*insn, phiInsn);
109 insertSuccess = true;
110 break;
111 }
112 }
113 if (!insertSuccess) {
114 phiBB->InsertInsnBegin(phiInsn);
115 }
116 phiBB->AddPhiInsn(vRegNO, phiInsn);
117 PrunedPhiInsertion(*phiBB, virtualOpnd);
118 }
119 }
120 }
121
RenameVariablesForBB(uint32 bbID)122 void CGSSAInfo::RenameVariablesForBB(uint32 bbID)
123 {
124 RenameBB(*cgFunc->GetBBFromID(bbID)); /* rename first BB */
125 const auto &domChildren = domInfo->GetDomChildren(bbID);
126 for (const auto &child : domChildren) {
127 RenameBB(*cgFunc->GetBBFromID(child));
128 }
129 }
130
RenameBB(BB & bb)131 void CGSSAInfo::RenameBB(BB &bb)
132 {
133 if (IsBBRenamed(bb.GetId())) {
134 return;
135 }
136 AddRenamedBB(bb.GetId());
137 /* record version stack size */
138 size_t tempSize =
139 vRegStk.empty() ? allSSAOperands.size() + cgFunc->GetFirstMapleIrVRegNO() + 1 : vRegStk.rbegin()->first + 1;
140 std::vector<int32> oriStackSize(tempSize, -1);
141 for (auto it : vRegStk) {
142 DEBUG_ASSERT(it.first < oriStackSize.size(), "out of range");
143 oriStackSize[it.first] = static_cast<int32>(it.second.size());
144 }
145 RenamePhi(bb);
146 FOR_BB_INSNS(insn, &bb)
147 {
148 if (!insn->IsMachineInstruction()) {
149 continue;
150 }
151 MarkInsnsInSSA(*insn);
152 RenameInsn(*insn);
153 }
154 RenameSuccPhiUse(bb);
155 RenameVariablesForBB(bb.GetId());
156 /* stack pop up */
157 for (auto &it : vRegStk) {
158 if (it.first < oriStackSize.size() && oriStackSize[it.first] >= 0) {
159 while (static_cast<int32>(it.second.size()) > oriStackSize[static_cast<uint64>(it.first)]) {
160 DEBUG_ASSERT(!it.second.empty(), "empty stack");
161 it.second.pop();
162 }
163 }
164 }
165 }
166
RenamePhi(BB & bb)167 void CGSSAInfo::RenamePhi(BB &bb)
168 {
169 for (auto phiInsnIt : bb.GetPhiInsns()) {
170 Insn *phiInsn = phiInsnIt.second;
171 CHECK_FATAL(phiInsn != nullptr, "get phi insn failed");
172 auto *phiDefOpnd = static_cast<RegOperand *>(&phiInsn->GetOperand(kInsnFirstOpnd));
173 VRegVersion *newVst = CreateNewVersion(*phiDefOpnd, *phiInsn, kInsnFirstOpnd, true);
174 phiInsn->SetOperand(kInsnFirstOpnd, *newVst->GetSSAvRegOpnd());
175 }
176 }
177
RenameSuccPhiUse(const BB & bb)178 void CGSSAInfo::RenameSuccPhiUse(const BB &bb)
179 {
180 for (auto *sucBB : bb.GetSuccs()) {
181 for (auto phiInsnIt : sucBB->GetPhiInsns()) {
182 Insn *phiInsn = phiInsnIt.second;
183 CHECK_FATAL(phiInsn != nullptr, "get phi insn failed");
184 Operand *phiListOpnd = &phiInsn->GetOperand(kInsnSecondOpnd);
185 CHECK_FATAL(phiListOpnd->IsPhi(), "unexpect phi operand");
186 MapleMap<uint32, RegOperand *> &phiList = static_cast<PhiOperand *>(phiListOpnd)->GetOperands();
187 DEBUG_ASSERT(phiList.size() <= sucBB->GetPreds().size(), "unexpect phiList size need check");
188 for (auto phiOpndIt = phiList.begin(); phiOpndIt != phiList.end(); ++phiOpndIt) {
189 if (phiOpndIt->first == bb.GetId()) {
190 RegOperand *renamedOpnd = GetRenamedOperand(*(phiOpndIt->second), false, *phiInsn, kInsnSecondOpnd);
191 phiList[phiOpndIt->first] = renamedOpnd;
192 }
193 }
194 }
195 }
196 }
197
IncreaseVregCount(regno_t vRegNO)198 uint32 CGSSAInfo::IncreaseVregCount(regno_t vRegNO)
199 {
200 if (!vRegDefCount.count(vRegNO)) {
201 vRegDefCount.emplace(vRegNO, 0);
202 } else {
203 vRegDefCount[vRegNO]++;
204 }
205 return vRegDefCount[vRegNO];
206 }
207
IncreaseSSAOperand(regno_t vRegNO,VRegVersion * vst)208 bool CGSSAInfo::IncreaseSSAOperand(regno_t vRegNO, VRegVersion *vst)
209 {
210 if (allSSAOperands.count(vRegNO)) {
211 return false;
212 }
213 allSSAOperands.emplace(vRegNO, vst);
214 return true;
215 }
216
CreateNewVersion(RegOperand & virtualOpnd,Insn & defInsn,uint32 idx,bool isDefByPhi)217 VRegVersion *CGSSAInfo::CreateNewVersion(RegOperand &virtualOpnd, Insn &defInsn, uint32 idx, bool isDefByPhi)
218 {
219 regno_t vRegNO = virtualOpnd.GetRegisterNumber();
220 uint32 verionIdx = IncreaseVregCount(vRegNO);
221 RegOperand *ssaOpnd = CreateSSAOperand(virtualOpnd);
222 auto *newVst = memPool->New<VRegVersion>(ssaAlloc, *ssaOpnd, verionIdx, vRegNO);
223 auto *defInfo = CreateDUInsnInfo(&defInsn, idx);
224 newVst->SetDefInsn(defInfo, isDefByPhi ? kDefByPhi : kDefByInsn);
225 if (!IncreaseSSAOperand(ssaOpnd->GetRegisterNumber(), newVst)) {
226 CHECK_FATAL(false, "insert ssa operand failed");
227 }
228 auto it = vRegStk.find(vRegNO);
229 if (it == vRegStk.end()) {
230 MapleStack<VRegVersion *> vRegVersionStack(ssaAlloc.Adapter());
231 auto ret = vRegStk.emplace(std::pair<regno_t, MapleStack<VRegVersion *>>(vRegNO, vRegVersionStack));
232 CHECK_FATAL(ret.second, "insert failed");
233 it = ret.first;
234 }
235 it->second.push(newVst);
236 return newVst;
237 }
238
GetVersion(const RegOperand & virtualOpnd)239 VRegVersion *CGSSAInfo::GetVersion(const RegOperand &virtualOpnd)
240 {
241 regno_t vRegNO = virtualOpnd.GetRegisterNumber();
242 auto vRegIt = vRegStk.find(vRegNO);
243 return vRegIt != vRegStk.end() ? vRegIt->second.top() : nullptr;
244 }
245
FindSSAVersion(regno_t ssaRegNO)246 VRegVersion *CGSSAInfo::FindSSAVersion(regno_t ssaRegNO)
247 {
248 auto it = allSSAOperands.find(ssaRegNO);
249 return it != allSSAOperands.end() ? it->second : nullptr;
250 }
251
CreatePhiOperand()252 PhiOperand &CGSSAInfo::CreatePhiOperand()
253 {
254 return cgFunc->GetCG()->CreatePhiOperand(*memPool, ssaAlloc);
255 }
256
SetReversePostOrder()257 void CGSSAInfo::SetReversePostOrder()
258 {
259 MapleVector<BB *> &reverse = domInfo->GetReversePostOrder();
260 for (auto *bb : reverse) {
261 if (bb != nullptr) {
262 reversePostOrder.emplace_back(bb->GetId());
263 }
264 }
265 }
266
GetDefInsn(const RegOperand & useReg)267 Insn *CGSSAInfo::GetDefInsn(const RegOperand &useReg)
268 {
269 if (!useReg.IsSSAForm()) {
270 return nullptr;
271 }
272 regno_t useRegNO = useReg.GetRegisterNumber();
273 VRegVersion *useVersion = FindSSAVersion(useRegNO);
274 CHECK_FATAL(useVersion != nullptr, "useVRegVersion must not be null based on ssa");
275 CHECK_FATAL(!useVersion->IsDeleted(), "deleted version");
276 DUInsnInfo *defInfo = useVersion->GetDefInsnInfo();
277 return defInfo == nullptr ? nullptr : defInfo->GetInsn();
278 }
279
DumpFuncCGIRinSSAForm() const280 void CGSSAInfo::DumpFuncCGIRinSSAForm() const
281 {
282 LogInfo::MapleLogger() << "\n****** SSA CGIR for " << cgFunc->GetName() << " *******\n";
283 FOR_ALL_BB_CONST(bb, cgFunc)
284 {
285 LogInfo::MapleLogger() << "=== BB "
286 << " <" << bb->GetKindName();
287 if (bb->GetLabIdx() != MIRLabelTable::GetDummyLabel()) {
288 LogInfo::MapleLogger() << "[labeled with " << bb->GetLabIdx();
289 LogInfo::MapleLogger() << " ==> @" << cgFunc->GetFunction().GetLabelName(bb->GetLabIdx()) << "]";
290 }
291
292 LogInfo::MapleLogger() << "> <" << bb->GetId() << "> ";
293 if (bb->IsCleanup()) {
294 LogInfo::MapleLogger() << "[is_cleanup] ";
295 }
296 if (bb->IsUnreachable()) {
297 LogInfo::MapleLogger() << "[unreachable] ";
298 }
299 if (bb->GetFirstStmt() == cgFunc->GetCleanupLabel()) {
300 LogInfo::MapleLogger() << "cleanup ";
301 }
302 if (!bb->GetSuccs().empty()) {
303 LogInfo::MapleLogger() << "succs: ";
304 for (auto *succBB : bb->GetSuccs()) {
305 LogInfo::MapleLogger() << succBB->GetId() << " ";
306 }
307 }
308 LogInfo::MapleLogger() << "===\n";
309 LogInfo::MapleLogger() << "frequency:" << bb->GetFrequency() << "\n";
310
311 FOR_BB_INSNS_CONST(insn, bb)
312 {
313 if (insn->IsCfiInsn() && insn->IsDbgInsn()) {
314 insn->Dump();
315 } else {
316 DumpInsnInSSAForm(*insn);
317 }
318 }
319 }
320 }
321
AddUseInsn(CGSSAInfo & ssaInfo,Insn & useInsn,uint32 idx)322 void VRegVersion::AddUseInsn(CGSSAInfo &ssaInfo, Insn &useInsn, uint32 idx)
323 {
324 DEBUG_ASSERT(useInsn.GetId() > 0, "insn should be marked during ssa");
325 auto useInsnIt = useInsnInfos.find(useInsn.GetId());
326 if (useInsnIt != useInsnInfos.end()) {
327 useInsnIt->second->IncreaseDU(idx);
328 } else {
329 useInsnInfos.insert(std::make_pair(useInsn.GetId(), ssaInfo.CreateDUInsnInfo(&useInsn, idx)));
330 }
331 }
332
RemoveUseInsn(const Insn & useInsn,uint32 idx)333 void VRegVersion::RemoveUseInsn(const Insn &useInsn, uint32 idx)
334 {
335 auto useInsnIt = useInsnInfos.find(useInsn.GetId());
336 DEBUG_ASSERT(useInsnIt != useInsnInfos.end(), "use Insn not found");
337 useInsnIt->second->DecreaseDU(idx);
338 if (useInsnIt->second->HasNoDU()) {
339 useInsnInfos.erase(useInsnIt);
340 }
341 }
342
CheckDeadUse(const Insn & useInsn)343 void VRegVersion::CheckDeadUse(const Insn &useInsn)
344 {
345 auto useInsnIt = useInsnInfos.find(useInsn.GetId());
346 DEBUG_ASSERT(useInsnIt != useInsnInfos.end(), "use Insn not found");
347 if (useInsnIt->second->HasNoDU()) {
348 useInsnInfos.erase(useInsnIt);
349 }
350 }
351
GetAnalysisDependence(maple::AnalysisDep & aDep) const352 void CgSSAConstruct::GetAnalysisDependence(maple::AnalysisDep &aDep) const
353 {
354 aDep.AddRequired<CgDomAnalysis>();
355 aDep.AddRequired<CgLiveAnalysis>();
356 aDep.PreservedAllExcept<CgLiveAnalysis>();
357 }
358
PhaseRun(maplebe::CGFunc & f)359 bool CgSSAConstruct::PhaseRun(maplebe::CGFunc &f)
360 {
361 if (CG_DEBUG_FUNC(f)) {
362 DotGenerator::GenerateDot("beforessa", f, f.GetMirModule());
363 }
364 MemPool *ssaMemPool = GetPhaseMemPool();
365 MemPool *ssaTempMp = ApplyTempMemPool();
366 DomAnalysis *domInfo = nullptr;
367 domInfo = GET_ANALYSIS(CgDomAnalysis, f);
368 LiveAnalysis *liveInfo = nullptr;
369 liveInfo = GET_ANALYSIS(CgLiveAnalysis, f);
370 ssaInfo = f.GetCG()->CreateCGSSAInfo(*ssaMemPool, f, *domInfo, *ssaTempMp);
371 ssaInfo->ConstructSSA();
372
373 if (CG_DEBUG_FUNC(f)) {
374 LogInfo::MapleLogger() << "******** CG IR After ssaconstruct in ssaForm: *********"
375 << "\n";
376 ssaInfo->DumpFuncCGIRinSSAForm();
377 }
378 if (liveInfo != nullptr) {
379 liveInfo->ClearInOutDataInfo();
380 }
381 /* due to change of register number */
382 GetAnalysisInfoHook()->ForceEraseAnalysisPhase(f.GetUniqueID(), &CgLiveAnalysis::id);
383 return true;
384 }
385 MAPLE_ANALYSIS_PHASE_REGISTER(CgSSAConstruct, cgssaconstruct) /* both transform & analysis */
386 } // namespace maplebe
387