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