• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &regOpnd = 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