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 "live.h"
17 #include <set>
18 #include "cg.h"
19 #include "cg_option.h"
20 #include "cgfunc.h"
21
22 /*
23 * This phase build two sets: liveOutRegno and liveInRegno of each BB.
24 * This algorithm mainly include 3 parts:
25 * 1. initialize and get def[]/use[] of each BB;
26 * 2. build live_in and live_out based on this algorithm
27 * Out[B] = U In[S] //S means B's successor;
28 * In[B] = use[B] U (Out[B]-def[B]);
29 * 3. deal with cleanup BB.
30 */
31 namespace maplebe {
32 #define LIVE_ANALYZE_DUMP_NEWPM CG_DEBUG_FUNC(f)
33
InitAndGetDefUse()34 void LiveAnalysis::InitAndGetDefUse()
35 {
36 FOR_ALL_BB(bb, cgFunc)
37 {
38 InitBB(*bb);
39 GetBBDefUse(*bb);
40 }
41 }
42
RemovePhiLiveInFromSuccNotFromThisBB(BB & curBB,BB & succBB) const43 bool LiveAnalysis::RemovePhiLiveInFromSuccNotFromThisBB(BB &curBB, BB &succBB) const
44 {
45 if (succBB.GetPhiInsns().empty()) {
46 return false;
47 }
48 LocalMapleAllocator allocator(cgFunc->GetStackMemPool());
49 SparseDataInfo tempPhiIn(succBB.GetLiveIn()->GetMaxRegNum(), allocator);
50 tempPhiIn.ResetAllBit();
51 for (auto phiInsnIt : succBB.GetPhiInsns()) {
52 auto &phiList = static_cast<PhiOperand &>(phiInsnIt.second->GetOperand(kInsnSecondOpnd));
53 for (auto phiOpndIt : phiList.GetOperands()) {
54 uint32 fBBId = phiOpndIt.first;
55 DEBUG_ASSERT(fBBId != 0, "GetFromBBID = 0");
56 if (fBBId != curBB.GetId()) {
57 regno_t regNo = phiOpndIt.second->GetRegisterNumber();
58 tempPhiIn.SetBit(regNo);
59 }
60 }
61 }
62 return curBB.GetLiveOut()->Difference(tempPhiIn);
63 }
64
65 /* Out[BB] = Union all of In[Succs(BB)]
66 *
67 * in ssa form
68 * Out[BB] = Union all of In[Succs(BB)] Except Phi use reg dont from this BB
69 */
GenerateLiveOut(BB & bb) const70 bool LiveAnalysis::GenerateLiveOut(BB &bb) const
71 {
72 bool isChanged = false;
73 for (auto succBB : bb.GetSuccs()) {
74 if (succBB->GetLiveInChange() && !succBB->GetLiveIn()->NoneBit()) {
75 isChanged = bb.LiveOutOrBits(*succBB->GetLiveIn()) || isChanged;
76 isChanged = RemovePhiLiveInFromSuccNotFromThisBB(bb, *succBB) || isChanged;
77 }
78 }
79 return isChanged;
80 }
81
82 /* In[BB] = use[BB] Union (Out[BB]-def[BB]) */
GenerateLiveIn(BB & bb)83 bool LiveAnalysis::GenerateLiveIn(BB &bb)
84 {
85 bool isChanged = false;
86 LocalMapleAllocator allocator(cgFunc->GetStackMemPool());
87 if (!bb.GetInsertUse()) {
88 if (!bb.GetLiveIn()->IsEqual(*bb.GetUse())) {
89 bb.SetLiveInInfo(*bb.GetUse());
90 isChanged = true;
91 }
92 bb.SetInsertUse(true);
93 }
94 SparseDataInfo &bbLiveOut = bb.GetLiveOut()->Clone(allocator);
95 if (!bbLiveOut.NoneBit()) {
96 bbLiveOut.Difference(*bb.GetDef());
97 isChanged = bb.LiveInOrBits(bbLiveOut) || isChanged;
98 }
99 return isChanged;
100 }
101
GenerateLiveInByDefUse(SparseDataInfo & liveOut,SparseDataInfo & use,SparseDataInfo & def)102 SparseDataInfo *LiveAnalysis::GenerateLiveInByDefUse(SparseDataInfo &liveOut, SparseDataInfo &use, SparseDataInfo &def)
103 {
104 SparseDataInfo *liveIn = &use;
105 LocalMapleAllocator allocator(cgFunc->GetStackMemPool());
106 SparseDataInfo *tmpLiveOut = memPool->New<SparseDataInfo>(liveOut, allocator);
107 if (!liveOut.NoneBit()) {
108 tmpLiveOut->Difference(def);
109 liveIn->OrBits(*tmpLiveOut);
110 }
111 return liveIn;
112 }
113
GenerateStackMapLiveIn()114 void LiveAnalysis::GenerateStackMapLiveIn()
115 {
116 const auto &stackMapInsns = cgFunc->GetStackMapInsns();
117 for (auto *insn : stackMapInsns) {
118 BB *curBB = insn->GetBB();
119 SparseDataInfo *liveIn =
120 GenerateLiveInByDefUse(*curBB->GetLiveOut(), *insn->GetStackMapUse(), *insn->GetStackMapDef());
121 insn->SetStackMapLiveIn(*liveIn);
122 }
123 }
124 /* building liveIn and liveOut of each BB. */
BuildInOutforFunc()125 void LiveAnalysis::BuildInOutforFunc()
126 {
127 iteration = 0;
128 bool hasChange;
129 do {
130 ++iteration;
131 hasChange = false;
132 FOR_ALL_BB_REV(bb, cgFunc)
133 {
134 if (!bb || bb->IsUnreachable() || !bb->GetLiveOut() || !bb->GetLiveIn()) {
135 continue;
136 }
137 if (!GenerateLiveOut(*bb) && bb->GetInsertUse()) {
138 continue;
139 }
140 if (GenerateLiveIn(*bb)) {
141 bb->SetLiveInChange(true);
142 hasChange = true;
143 } else {
144 bb->SetLiveInChange(false);
145 }
146 }
147 } while (hasChange);
148 }
149
150 /* reset to liveout/in_regno */
ResetLiveSet()151 void LiveAnalysis::ResetLiveSet()
152 {
153 FOR_ALL_BB(bb, cgFunc)
154 {
155 bb->GetLiveIn()->GetBitsOfInfo<MapleSet<uint32>>(bb->GetLiveInRegNO());
156 bb->GetLiveOut()->GetBitsOfInfo<MapleSet<uint32>>(bb->GetLiveOutRegNO());
157 }
158 }
159
160 /* entry function for LiveAnalysis */
AnalysisLive()161 void LiveAnalysis::AnalysisLive()
162 {
163 InitAndGetDefUse();
164 BuildInOutforFunc();
165 InsertInOutOfCleanupBB();
166 if (!cgFunc->IsStackMapComputed()) {
167 GenerateStackMapLiveIn();
168 }
169 }
170
DealWithInOutOfCleanupBB()171 void LiveAnalysis::DealWithInOutOfCleanupBB()
172 {
173 const BB *cleanupBB = cgFunc->GetCleanupBB();
174 if (cleanupBB == nullptr) {
175 return;
176 }
177 for (size_t i = 0; i != cleanupBB->GetLiveIn()->Size(); ++i) {
178 if (!cleanupBB->GetLiveIn()->TestBit(i)) {
179 continue;
180 }
181 if (CleanupBBIgnoreReg(regno_t(i))) {
182 continue;
183 }
184 /*
185 * a param vreg may used in cleanup bb. So this param vreg will live on the whole function
186 * since everywhere in function body may occur exceptions.
187 */
188 FOR_ALL_BB(bb, cgFunc)
189 {
190 if (bb->IsCleanup()) {
191 continue;
192 }
193 /* If bb is not a cleanup bb, then insert reg to both livein and liveout. */
194 if ((bb != cgFunc->GetFirstBB()) && !bb->GetDef()->TestBit(i)) {
195 bb->SetLiveInBit(i);
196 }
197 bb->SetLiveOutBit(i);
198 }
199 }
200 }
201
InsertInOutOfCleanupBB()202 void LiveAnalysis::InsertInOutOfCleanupBB()
203 {
204 LocalMapleAllocator allocator(cgFunc->GetStackMemPool());
205 const BB *cleanupBB = cgFunc->GetCleanupBB();
206 if (cleanupBB == nullptr) {
207 return;
208 }
209 if (cleanupBB->GetLiveIn() == nullptr || cleanupBB->GetLiveIn()->NoneBit()) {
210 return;
211 }
212 SparseDataInfo &cleanupBBLi = cleanupBB->GetLiveIn()->Clone(allocator);
213 /* registers need to be ignored: (reg < 8) || (29 <= reg && reg <= 32) */
214 for (uint32 i = 1; i < 8; ++i) { // reset 8 reg for R0-R7
215 cleanupBBLi.ResetBit(i);
216 }
217 for (uint32 j = 29; j <= 32; ++j) { // registers 29 ~ 32 need to be ignored
218 cleanupBBLi.ResetBit(j);
219 }
220
221 FOR_ALL_BB(bb, cgFunc)
222 {
223 if (bb->IsCleanup()) {
224 continue;
225 }
226 if (bb != cgFunc->GetFirstBB()) {
227 cleanupBBLi.Difference(*bb->GetDef());
228 bb->LiveInOrBits(cleanupBBLi);
229 }
230 bb->LiveOutOrBits(cleanupBBLi);
231 }
232 }
233
MarkStackMapInsn(Insn & insn,BB & bb) const234 void LiveAnalysis::MarkStackMapInsn(Insn &insn, BB &bb) const
235 {
236 if (insn.GetStackMap() != nullptr) {
237 for (auto [deoptVreg, opnd] : insn.GetStackMap()->GetDeoptInfo().GetDeoptBundleInfo()) {
238 CollectLiveInfo(bb, *opnd, false, true);
239 }
240 }
241 insn.SetStackMapDef(*NewDef(*bb.GetDef()));
242 insn.SetStackMapUse(*NewUse(*bb.GetUse()));
243 }
244
245 /*
246 * entry of get def/use of bb.
247 * getting the def or use info of each regopnd as parameters of CollectLiveInfo().
248 */
GetBBDefUse(BB & bb) const249 void LiveAnalysis::GetBBDefUse(BB &bb) const
250 {
251 if (bb.GetKind() == BB::kBBReturn) {
252 GenerateReturnBBDefUse(bb);
253 }
254 if (!bb.HasMachineInsn()) {
255 return;
256 }
257 bb.DefResetAllBit();
258 bb.UseResetAllBit();
259
260 FOR_BB_INSNS_REV(insn, &bb)
261 {
262 if (!insn->IsMachineInstruction()) {
263 continue;
264 }
265
266 if (insn->IsCall() && !cgFunc->IsStackMapComputed()) {
267 MarkStackMapInsn(*insn, bb);
268 }
269
270 bool isAsm = insn->IsAsmInsn();
271 const InsnDesc *md = insn->GetDesc();
272 if (insn->IsCall() || insn->IsTailCall()) {
273 ProcessCallInsnParam(bb, *insn);
274 }
275 uint32 opndNum = insn->GetOperandSize();
276 for (uint32 i = 0; i < opndNum; ++i) {
277 const OpndDesc *opndDesc = md->GetOpndDes(i);
278 DEBUG_ASSERT(opndDesc != nullptr, "null ptr check");
279 Operand &opnd = insn->GetOperand(i);
280 if (opnd.IsList()) {
281 if (isAsm) {
282 ProcessAsmListOpnd(bb, opnd, i);
283 } else {
284 ProcessListOpnd(bb, opnd, opndDesc->IsDef());
285 }
286 } else if (opnd.IsMemoryAccessOperand()) {
287 ProcessMemOpnd(bb, opnd);
288 } else if (opnd.IsConditionCode()) {
289 ProcessCondOpnd(bb);
290 } else if (opnd.IsPhi()) {
291 auto &phiOpnd = static_cast<PhiOperand &>(opnd);
292 for (auto opIt : phiOpnd.GetOperands()) {
293 CollectLiveInfo(bb, *opIt.second, false, true);
294 }
295 } else {
296 bool isDef = opndDesc->IsRegDef();
297 bool isUse = opndDesc->IsRegUse();
298 CollectLiveInfo(bb, opnd, isDef, isUse);
299 }
300 }
301 }
302 }
303
304 /* build use and def sets of each BB according to the type of regOpnd. */
CollectLiveInfo(BB & bb,const Operand & opnd,bool isDef,bool isUse) const305 void LiveAnalysis::CollectLiveInfo(BB &bb, const Operand &opnd, bool isDef, bool isUse) const
306 {
307 if (!opnd.IsRegister()) {
308 return;
309 }
310 auto ®Opnd = static_cast<const RegOperand &>(opnd);
311 regno_t regNO = regOpnd.GetRegisterNumber();
312 RegType regType = regOpnd.GetRegisterType();
313 if (regType == kRegTyVary) {
314 return;
315 }
316 if (isDef) {
317 bb.SetDefBit(regNO);
318 if (!isUse) {
319 bb.UseResetBit(regNO);
320 }
321 }
322 if (isUse) {
323 bb.SetUseBit(regNO);
324 bb.DefResetBit(regNO);
325 }
326 if (!cgFunc->IsStackMapComputed() && regOpnd.GetBaseRefOpnd() != nullptr) {
327 const RegOperand &baseOpnd = *regOpnd.GetBaseRefOpnd();
328 regno_t baseRegNO = baseOpnd.GetRegisterNumber();
329 bb.SetUseBit(baseRegNO);
330 bb.DefResetBit(baseRegNO);
331 }
332 }
333
ProcessAsmListOpnd(BB & bb,Operand & opnd,uint32 idx) const334 void LiveAnalysis::ProcessAsmListOpnd(BB &bb, Operand &opnd, uint32 idx) const
335 {
336 bool isDef = false;
337 bool isUse = false;
338 switch (idx) {
339 case kAsmOutputListOpnd:
340 case kAsmClobberListOpnd: {
341 isDef = true;
342 break;
343 }
344 case kAsmInputListOpnd: {
345 isUse = true;
346 break;
347 }
348 default:
349 return;
350 }
351 ListOperand &listOpnd = static_cast<ListOperand &>(opnd);
352 for (auto op : listOpnd.GetOperands()) {
353 CollectLiveInfo(bb, *op, isDef, isUse);
354 }
355 }
356
ProcessListOpnd(BB & bb,Operand & opnd,bool isDef) const357 void LiveAnalysis::ProcessListOpnd(BB &bb, Operand &opnd, bool isDef) const
358 {
359 ListOperand &listOpnd = static_cast<ListOperand &>(opnd);
360 for (auto op : listOpnd.GetOperands()) {
361 CollectLiveInfo(bb, *op, isDef, !isDef);
362 }
363 }
364
ProcessMemOpnd(BB & bb,Operand & opnd) const365 void LiveAnalysis::ProcessMemOpnd(BB &bb, Operand &opnd) const
366 {
367 auto &memOpnd = static_cast<MemOperand &>(opnd);
368 Operand *base = memOpnd.GetBaseRegister();
369 Operand *offset = memOpnd.GetIndexRegister();
370 if (base != nullptr) {
371 CollectLiveInfo(bb, *base, !memOpnd.IsIntactIndexed(), true);
372 }
373 if (offset != nullptr) {
374 CollectLiveInfo(bb, *offset, false, true);
375 }
376 }
377
ProcessCondOpnd(BB & bb) const378 void LiveAnalysis::ProcessCondOpnd(BB &bb) const
379 {
380 Operand &rflag = cgFunc->GetOrCreateRflag();
381 CollectLiveInfo(bb, rflag, false, true);
382 }
383
384 /* dump the current info of def/use/livein/liveout */
Dump() const385 void LiveAnalysis::Dump() const
386 {
387 MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(cgFunc->GetFunction().GetStIdx().Idx());
388 DEBUG_ASSERT(funcSt != nullptr, "null ptr check");
389 LogInfo::MapleLogger() << "\n--------- liveness for " << funcSt->GetName() << " iteration ";
390 LogInfo::MapleLogger() << iteration << " ---------\n";
391 FOR_ALL_BB(bb, cgFunc)
392 {
393 LogInfo::MapleLogger() << " === BB_" << bb->GetId() << " (" << std::hex << bb << ") " << std::dec << " <"
394 << bb->GetKindName();
395 if (bb->GetLabIdx() != MIRLabelTable::GetDummyLabel()) {
396 LogInfo::MapleLogger() << "[labeled with " << bb->GetLabIdx() << "]";
397 }
398 LogInfo::MapleLogger() << "> idx " << bb->GetId() << " ===\n";
399
400 if (!bb->GetPreds().empty()) {
401 LogInfo::MapleLogger() << " pred [ ";
402 for (auto *pred : bb->GetPreds()) {
403 LogInfo::MapleLogger() << pred->GetId() << " (" << std::hex << pred << ") " << std::dec << " ";
404 }
405 LogInfo::MapleLogger() << "]\n";
406 }
407 if (!bb->GetSuccs().empty()) {
408 LogInfo::MapleLogger() << " succ [ ";
409 for (auto *succ : bb->GetSuccs()) {
410 LogInfo::MapleLogger() << succ->GetId() << " (" << std::hex << succ << ") " << std::dec << " ";
411 }
412 LogInfo::MapleLogger() << "]\n";
413 }
414
415 const SparseDataInfo *infoDef = nullptr;
416 LogInfo::MapleLogger() << " DEF: ";
417 infoDef = bb->GetDef();
418 DumpInfo(*infoDef);
419
420 const SparseDataInfo *infoUse = nullptr;
421 LogInfo::MapleLogger() << "\n USE: ";
422 infoUse = bb->GetUse();
423 DumpInfo(*infoUse);
424
425 const SparseDataInfo *infoLiveIn = nullptr;
426 LogInfo::MapleLogger() << "\n Live IN: ";
427 infoLiveIn = bb->GetLiveIn();
428 DumpInfo(*infoLiveIn);
429
430 const SparseDataInfo *infoLiveOut = nullptr;
431 LogInfo::MapleLogger() << "\n Live OUT: ";
432 infoLiveOut = bb->GetLiveOut();
433 DumpInfo(*infoLiveOut);
434 LogInfo::MapleLogger() << "\n";
435 }
436 LogInfo::MapleLogger() << "---------------------------\n";
437 }
438
DumpInfo(const SparseDataInfo & info) const439 void LiveAnalysis::DumpInfo(const SparseDataInfo &info) const
440 {
441 uint32 count = 1;
442 std::set<uint32> res;
443 info.GetInfo().ConvertToSet(res);
444 for (uint32 x : res) {
445 LogInfo::MapleLogger() << x << " ";
446 ++count;
447 /* 20 output one line */
448 if ((count % 20) == 0) {
449 LogInfo::MapleLogger() << "\n";
450 }
451 }
452 LogInfo::MapleLogger() << '\n';
453 }
454
455 /* initialize dependent info and container of BB. */
InitBB(BB & bb)456 void LiveAnalysis::InitBB(BB &bb)
457 {
458 bb.SetLiveInChange(true);
459 bb.SetInsertUse(false);
460 bb.ClearLiveInRegNO();
461 bb.ClearLiveOutRegNO();
462 const uint32 maxRegCount =
463 cgFunc->GetSSAvRegCount() > cgFunc->GetMaxVReg() ? cgFunc->GetSSAvRegCount() : cgFunc->GetMaxVReg();
464 bb.SetLiveIn(*NewLiveIn(maxRegCount));
465 bb.SetLiveOut(*NewLiveOut(maxRegCount));
466 bb.SetDef(*NewDef(maxRegCount));
467 bb.SetUse(*NewUse(maxRegCount));
468 }
469
ClearInOutDataInfo()470 void LiveAnalysis::ClearInOutDataInfo()
471 {
472 FOR_ALL_BB(bb, cgFunc)
473 {
474 bb->SetLiveInChange(false);
475 bb->DefClearDataInfo();
476 bb->UseClearDataInfo();
477 bb->LiveInClearDataInfo();
478 bb->LiveOutClearDataInfo();
479 }
480 }
481
GetAnalysisDependence(AnalysisDep & aDep) const482 void CgLiveAnalysis::GetAnalysisDependence(AnalysisDep &aDep) const
483 {
484 #if TARGX86_64
485 if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
486 aDep.AddRequired<CgHandleCFG>();
487 }
488 #endif
489 aDep.SetPreservedAll();
490 }
491
PhaseRun(maplebe::CGFunc & f)492 bool CgLiveAnalysis::PhaseRun(maplebe::CGFunc &f)
493 {
494 MemPool *liveMemPool = GetPhaseMemPool();
495 live = f.GetCG()->CreateLiveAnalysis(*liveMemPool, f);
496 CHECK_FATAL(live != nullptr, "NIY");
497 live->AnalysisLive();
498 if (LIVE_ANALYZE_DUMP_NEWPM) {
499 live->Dump();
500 }
501 live->ResetLiveSet();
502 return false;
503 }
504 MAPLE_ANALYSIS_PHASE_REGISTER(CgLiveAnalysis, liveanalysis)
505 } /* namespace maplebe */
506