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 ®Opnd = 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