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