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