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 "aarch64_color_ra.h"
17 #include <iostream>
18 #include <fstream>
19 #include "aarch64_cg.h"
20 #include "mir_lower.h"
21 #include "securec.h"
22 /*
23 * Based on concepts from Chow and Hennessey.
24 * Phases are as follows:
25 * Prepass to collect local BB information.
26 * Compute local register allocation demands for global RA.
27 * Compute live ranges.
28 * Live ranges LR represented by a vector of size #BBs.
29 * for each cross bb vreg, a bit is set in the vector.
30 * Build interference graph with basic block as granularity.
31 * When intersection of two LRs is not null, they interfere.
32 * Separate unconstrained and constrained LRs.
33 * unconstrained - LR with connect edges less than available colors.
34 * These LR can always be colored.
35 * constrained - not uncontrained.
36 * Split LR based on priority cost
37 * Repetitive adding BB from original LR to new LR until constrained.
38 * Update all LR the new LR interferes with.
39 * Color the new LR
40 * Each LR has a forbidden list, the registers cannot be assigned
41 * Coalesce move using preferred color first.
42 * Mark the remaining uncolorable LR after split as spill.
43 * Local register allocate.
44 * Emit and insert spills.
45 */
46 namespace maplebe {
47 #define CLANG (cgFunc->GetMirModule().IsCModule())
48
PrintLiveUnit() const49 void LiveUnit::PrintLiveUnit() const
50 {
51 LogInfo::MapleLogger() << "[" << begin << "," << end << "]"
52 << "<D" << defNum << "U" << useNum << ">";
53 if (!hasCall) {
54 /* Too many calls, so only print when there is no call. */
55 LogInfo::MapleLogger() << " nc";
56 }
57 if (needReload) {
58 LogInfo::MapleLogger() << " rlod";
59 }
60 if (needRestore) {
61 LogInfo::MapleLogger() << " rstr";
62 }
63 }
64
65 template <typename Func>
ForEachBBArrElem(const uint64 * vec,Func functor) const66 void GraphColorRegAllocator::ForEachBBArrElem(const uint64 *vec, Func functor) const
67 {
68 for (uint32 iBBArrElem = 0; iBBArrElem < bbBuckets; ++iBBArrElem) {
69 for (uint32 bBBArrElem = 0; bBBArrElem < kU64; ++bBBArrElem) {
70 if ((vec[iBBArrElem] & (1ULL << bBBArrElem)) != 0) {
71 functor(iBBArrElem * kU64 + bBBArrElem);
72 }
73 }
74 }
75 }
76
77 template <typename Func>
ForEachBBArrElemWithInterrupt(const uint64 * vec,Func functor) const78 void GraphColorRegAllocator::ForEachBBArrElemWithInterrupt(const uint64 *vec, Func functor) const
79 {
80 for (uint32 iBBArrElem = 0; iBBArrElem < bbBuckets; ++iBBArrElem) {
81 for (uint32 bBBArrElem = 0; bBBArrElem < kU64; ++bBBArrElem) {
82 if ((vec[iBBArrElem] & (1ULL << bBBArrElem)) != 0) {
83 if (functor(iBBArrElem * kU64 + bBBArrElem)) {
84 return;
85 }
86 }
87 }
88 }
89 }
90
91 template <typename Func>
ForEachRegArrElem(const uint64 * vec,Func functor) const92 void GraphColorRegAllocator::ForEachRegArrElem(const uint64 *vec, Func functor) const
93 {
94 for (uint32 iBBArrElem = 0; iBBArrElem < regBuckets; ++iBBArrElem) {
95 for (uint32 bBBArrElem = 0; bBBArrElem < kU64; ++bBBArrElem) {
96 if ((vec[iBBArrElem] & (1ULL << bBBArrElem)) != 0) {
97 functor(iBBArrElem * kU64 + bBBArrElem);
98 }
99 }
100 }
101 }
102
PrintLiveUnitMap(const LiveRange & lr) const103 void GraphColorRegAllocator::PrintLiveUnitMap(const LiveRange &lr) const
104 {
105 LogInfo::MapleLogger() << "\n\tlu:";
106 for (uint32 i = 0; i < cgFunc->NumBBs(); ++i) {
107 if (!IsBitArrElemSet(lr.GetBBMember(), i)) {
108 continue;
109 }
110 auto lu = lr.GetLuMap().find(i);
111 if (lu != lr.GetLuMap().end() && (lu->second->GetDefNum() || lu->second->GetUseNum())) {
112 LogInfo::MapleLogger() << "(" << i << " ";
113 lu->second->PrintLiveUnit();
114 LogInfo::MapleLogger() << ")";
115 }
116 }
117 LogInfo::MapleLogger() << "\n";
118 }
119
PrintLiveRangeConflicts(const LiveRange & lr) const120 void GraphColorRegAllocator::PrintLiveRangeConflicts(const LiveRange &lr) const
121 {
122 LogInfo::MapleLogger() << "\n\tinterfere(" << lr.GetNumBBConflicts() << "): ";
123 for (uint32 i = 0; i < regBuckets; ++i) {
124 uint64 chunk = lr.GetBBConflictElem(i);
125 for (uint64 bit = 0; bit < kU64; ++bit) {
126 if (chunk & (1ULL << bit)) {
127 regno_t newNO = i * kU64 + bit;
128 LogInfo::MapleLogger() << newNO << ",";
129 }
130 }
131 }
132 LogInfo::MapleLogger() << "\n";
133 }
134
PrintLiveBBBit(const LiveRange & lr) const135 void GraphColorRegAllocator::PrintLiveBBBit(const LiveRange &lr) const
136 {
137 LogInfo::MapleLogger() << "live_bb(" << lr.GetNumBBMembers() << "): ";
138 for (uint32 i = 0; i < cgFunc->NumBBs(); ++i) {
139 if (IsBitArrElemSet(lr.GetBBMember(), i)) {
140 LogInfo::MapleLogger() << i << " ";
141 }
142 }
143 LogInfo::MapleLogger() << "\n";
144 }
145
PrintLiveRange(const LiveRange & lr,const std::string & str) const146 void GraphColorRegAllocator::PrintLiveRange(const LiveRange &lr, const std::string &str) const
147 {
148 LogInfo::MapleLogger() << str << "\n";
149
150 LogInfo::MapleLogger() << "R" << lr.GetRegNO();
151 if (lr.GetRegType() == kRegTyInt) {
152 LogInfo::MapleLogger() << "(I)";
153 } else if (lr.GetRegType() == kRegTyFloat) {
154 LogInfo::MapleLogger() << "(F)";
155 } else {
156 LogInfo::MapleLogger() << "(U)";
157 }
158 if (lr.GetSpillSize() == k32) {
159 LogInfo::MapleLogger() << "S32";
160 } else if (lr.GetSpillSize() == k64) {
161 LogInfo::MapleLogger() << "S64";
162 } else {
163 LogInfo::MapleLogger() << "S0(nodef)";
164 }
165 LogInfo::MapleLogger() << "\tnumCall " << lr.GetNumCall();
166 LogInfo::MapleLogger() << "\tpriority " << lr.GetPriority();
167 LogInfo::MapleLogger() << "\tforbidden: ";
168 for (regno_t preg = kInvalidRegNO; preg < kMaxRegNum; preg++) {
169 if (lr.GetForbidden(preg)) {
170 LogInfo::MapleLogger() << preg << ",";
171 }
172 }
173 LogInfo::MapleLogger() << "\tpregveto: ";
174 for (regno_t preg = kInvalidRegNO; preg < kMaxRegNum; preg++) {
175 if (lr.GetPregveto(preg)) {
176 LogInfo::MapleLogger() << preg << ",";
177 }
178 }
179 if (lr.IsSpilled()) {
180 LogInfo::MapleLogger() << " spilled";
181 }
182 if (lr.GetSplitLr()) {
183 LogInfo::MapleLogger() << " split";
184 }
185 LogInfo::MapleLogger() << "\top: " << kOpcodeInfo.GetName(lr.GetOp());
186 LogInfo::MapleLogger() << "\n";
187 PrintLiveBBBit(lr);
188 PrintLiveRangeConflicts(lr);
189 PrintLiveUnitMap(lr);
190 if (lr.GetSplitLr()) {
191 PrintLiveRange(*lr.GetSplitLr(), "===>Split LR");
192 }
193 }
194
PrintLiveRanges() const195 void GraphColorRegAllocator::PrintLiveRanges() const
196 {
197 LogInfo::MapleLogger() << "PrintLiveRanges: size = " << lrMap.size() << "\n";
198 for (auto it : lrMap) {
199 PrintLiveRange(*it.second, "");
200 }
201 LogInfo::MapleLogger() << "\n";
202 }
203
PrintLocalRAInfo(const std::string & str) const204 void GraphColorRegAllocator::PrintLocalRAInfo(const std::string &str) const
205 {
206 LogInfo::MapleLogger() << str << "\n";
207 for (uint32 id = 0; id < cgFunc->NumBBs(); ++id) {
208 LocalRaInfo *lraInfo = localRegVec[id];
209 if (lraInfo == nullptr) {
210 continue;
211 }
212 LogInfo::MapleLogger() << "bb " << id << " def ";
213 for (const auto &defCntPair : lraInfo->GetDefCnt()) {
214 LogInfo::MapleLogger() << "[" << defCntPair.first << ":" << defCntPair.second << "],";
215 }
216 LogInfo::MapleLogger() << "\n";
217 LogInfo::MapleLogger() << "use ";
218 for (const auto &useCntPair : lraInfo->GetUseCnt()) {
219 LogInfo::MapleLogger() << "[" << useCntPair.first << ":" << useCntPair.second << "],";
220 }
221 LogInfo::MapleLogger() << "\n";
222 }
223 }
224
PrintBBAssignInfo() const225 void GraphColorRegAllocator::PrintBBAssignInfo() const
226 {
227 for (size_t id = 0; id < bfs->sortedBBs.size(); ++id) {
228 uint32 bbID = bfs->sortedBBs[id]->GetId();
229 BBAssignInfo *bbInfo = bbRegInfo[bbID];
230 if (bbInfo == nullptr) {
231 continue;
232 }
233 LogInfo::MapleLogger() << "BBinfo(" << id << ")";
234 LogInfo::MapleLogger() << " lra-needed int " << bbInfo->GetIntLocalRegsNeeded();
235 LogInfo::MapleLogger() << " fp " << bbInfo->GetFpLocalRegsNeeded();
236 LogInfo::MapleLogger() << " greg-used ";
237 for (regno_t regNO = kInvalidRegNO; regNO < kMaxRegNum; ++regNO) {
238 if (bbInfo->GetGlobalsAssigned(regNO)) {
239 LogInfo::MapleLogger() << regNO << ",";
240 }
241 }
242 LogInfo::MapleLogger() << "\n";
243 }
244 }
245
PrintBBs() const246 void GraphColorRegAllocator::PrintBBs() const
247 {
248 for (auto *bb : bfs->sortedBBs) {
249 LogInfo::MapleLogger() << "\n< === > ";
250 LogInfo::MapleLogger() << bb->GetId();
251 LogInfo::MapleLogger() << " succs:";
252 for (auto *succBB : bb->GetSuccs()) {
253 LogInfo::MapleLogger() << " " << succBB->GetId();
254 }
255 LogInfo::MapleLogger() << " eh_succs:";
256 }
257 LogInfo::MapleLogger() << "\n";
258 }
259
MaxIntPhysRegNum() const260 uint32 GraphColorRegAllocator::MaxIntPhysRegNum() const
261 {
262 return (R28 - R0);
263 }
264
MaxFloatPhysRegNum() const265 uint32 GraphColorRegAllocator::MaxFloatPhysRegNum() const
266 {
267 return (V31 - V0);
268 }
269
IsReservedReg(AArch64reg regNO) const270 bool GraphColorRegAllocator::IsReservedReg(AArch64reg regNO) const
271 {
272 if (!doMultiPass || cgFunc->GetMirModule().GetSrcLang() != kSrcLangC) {
273 return (regNO == R16) || (regNO == R17);
274 } else {
275 return (regNO == R16);
276 }
277 }
278
InitFreeRegPool()279 void GraphColorRegAllocator::InitFreeRegPool()
280 {
281 /*
282 * ==== int regs ====
283 * FP 29, LR 30, SP 31, 0 to 7 parameters
284
285 * MapleCG defines 32 as ZR (zero register)
286 * use 8 if callee does not return large struct ? No
287 * 16 and 17 are intra-procedure call temp, can be caller saved
288 * 18 is platform reg, still use it
289 */
290 uint32 intNum = 0;
291 uint32 fpNum = 0;
292 for (regno_t regNO = kRinvalid; regNO < kMaxRegNum; ++regNO) {
293 if (!AArch64Abi::IsAvailableReg(static_cast<AArch64reg>(regNO))) {
294 continue;
295 }
296
297 #ifdef RESERVED_REGS
298 /* r16,r17 are used besides ra. */
299 if (IsReservedReg(static_cast<AArch64reg>(regNO))) {
300 continue;
301 }
302 #endif /* RESERVED_REGS */
303
304 if (AArch64isa::IsGPRegister(static_cast<AArch64reg>(regNO))) {
305 /* when yieldpoint is enabled, x19 is reserved. */
306 if (IsYieldPointReg(static_cast<AArch64reg>(regNO))) {
307 continue;
308 }
309 if (regNO == R29) {
310 if (!cgFunc->UseFP()) {
311 (void)intCalleeRegSet.insert(regNO - R0);
312 ++intNum;
313 }
314 continue;
315 }
316 if (AArch64Abi::IsCalleeSavedReg(static_cast<AArch64reg>(regNO))) {
317 (void)intCalleeRegSet.insert(regNO - R0);
318 } else {
319 (void)intCallerRegSet.insert(regNO - R0);
320 }
321 ++intNum;
322 } else {
323 DEBUG_ASSERT(regNO >= V0, "regNO - V0 is unsigned");
324 if (AArch64Abi::IsCalleeSavedReg(static_cast<AArch64reg>(regNO))) {
325 (void)fpCalleeRegSet.insert(regNO - V0);
326 } else {
327 (void)fpCallerRegSet.insert(regNO - V0);
328 }
329 ++fpNum;
330 }
331 }
332 intRegNum = intNum;
333 fpRegNum = fpNum;
334 }
335
InitCCReg()336 void GraphColorRegAllocator::InitCCReg()
337 {
338 Operand &opnd = cgFunc->GetOrCreateRflag();
339 auto &tmpRegOp = static_cast<RegOperand &>(opnd);
340 ccReg = tmpRegOp.GetRegisterNumber();
341 }
342
IsYieldPointReg(regno_t regNO) const343 bool GraphColorRegAllocator::IsYieldPointReg(regno_t regNO) const
344 {
345 if (cgFunc->GetCG()->GenYieldPoint()) {
346 return (regNO == RYP);
347 }
348 return false;
349 }
350
IsUnconcernedReg(regno_t regNO) const351 bool GraphColorRegAllocator::IsUnconcernedReg(regno_t regNO) const
352 {
353 /* RFP = 32, RLR = 31, RSP = 33, RZR = 34 */
354 if ((regNO >= RLR && regNO <= RZR) || regNO == RFP || regNO == ccReg) {
355 return true;
356 }
357
358 /* when yieldpoint is enabled, the RYP(x19) can not be used. */
359 if (IsYieldPointReg(static_cast<AArch64reg>(regNO))) {
360 return true;
361 }
362
363 return false;
364 }
365
IsUnconcernedReg(const RegOperand & regOpnd) const366 bool GraphColorRegAllocator::IsUnconcernedReg(const RegOperand ®Opnd) const
367 {
368 RegType regType = regOpnd.GetRegisterType();
369 if (regType == kRegTyCc || regType == kRegTyVary) {
370 return true;
371 }
372 uint32 regNO = regOpnd.GetRegisterNumber();
373 if (regNO == RZR) {
374 return true;
375 }
376 return IsUnconcernedReg(regNO);
377 }
378
379 /*
380 * Based on live analysis, the live-in and live-out set determines
381 * the bit to be set in the LR vector, which is of size #BBs.
382 * If a vreg is in the live-in and live-out set, it is live in the BB.
383 *
384 * Also keep track if a LR crosses a call. If a LR crosses a call, it
385 * interferes with all caller saved registers. Add all caller registers
386 * to the LR's forbidden list.
387 *
388 * Return created LiveRange object
389 *
390 * maybe need extra info:
391 * Add info for setjmp.
392 * Add info for defBB, useBB, index in BB for def and use
393 * Add info for startingBB and endingBB
394 */
NewLiveRange()395 LiveRange *GraphColorRegAllocator::NewLiveRange()
396 {
397 LiveRange *lr = memPool->New<LiveRange>(alloc);
398
399 if (bbBuckets == 0) {
400 bbBuckets = (cgFunc->NumBBs() / kU64) + 1;
401 }
402 lr->SetBBBuckets(bbBuckets);
403 lr->InitBBMember(*memPool, bbBuckets);
404 if (regBuckets == 0) {
405 regBuckets = (cgFunc->GetMaxRegNum() / kU64) + 1;
406 }
407 lr->SetRegBuckets(regBuckets);
408 lr->InitBBConflict(*memPool, regBuckets);
409 lr->InitPregveto();
410 lr->InitForbidden();
411 return lr;
412 }
413
414 /* Create local info for LR. return true if reg is not local. */
CreateLiveRangeHandleLocal(regno_t regNO,const BB & bb,bool isDef)415 bool GraphColorRegAllocator::CreateLiveRangeHandleLocal(regno_t regNO, const BB &bb, bool isDef)
416 {
417 if (FindIn(bb.GetLiveInRegNO(), regNO) || FindIn(bb.GetLiveOutRegNO(), regNO)) {
418 return true;
419 }
420 /*
421 * register not in globals for the bb, so it is local.
422 * Compute local RA info.
423 */
424 LocalRaInfo *lraInfo = localRegVec[bb.GetId()];
425 if (lraInfo == nullptr) {
426 lraInfo = memPool->New<LocalRaInfo>(alloc);
427 localRegVec[bb.GetId()] = lraInfo;
428 }
429 if (isDef) {
430 /* movk is handled by different id for use/def in the same insn. */
431 lraInfo->SetDefCntElem(regNO, lraInfo->GetDefCntElem(regNO) + 1);
432 } else {
433 lraInfo->SetUseCntElem(regNO, lraInfo->GetUseCntElem(regNO) + 1);
434 }
435 /* lr info is useful for lra, so continue lr info */
436 return false;
437 }
438
CreateLiveRangeAllocateAndUpdate(regno_t regNO,const BB & bb,bool isDef,uint32 currId)439 LiveRange *GraphColorRegAllocator::CreateLiveRangeAllocateAndUpdate(regno_t regNO, const BB &bb, bool isDef,
440 uint32 currId)
441 {
442 LiveRange *lr = GetLiveRange(regNO);
443 if (lr == nullptr) {
444 lr = NewLiveRange();
445 lr->SetID(currId);
446
447 LiveUnit *lu = memPool->New<LiveUnit>();
448 lr->SetElemToLuMap(bb.GetId(), *lu);
449 lu->SetBegin(currId);
450 lu->SetEnd(currId);
451 if (isDef) {
452 /* means no use after def for reg, chances for ebo opt */
453 for (const auto &pregNO : pregLive) {
454 lr->InsertElemToPregveto(pregNO);
455 }
456 }
457 } else {
458 LiveUnit *lu = lr->GetLiveUnitFromLuMap(bb.GetId());
459 if (lu == nullptr) {
460 lu = memPool->New<LiveUnit>();
461 lr->SetElemToLuMap(bb.GetId(), *lu);
462 lu->SetBegin(currId);
463 lu->SetEnd(currId);
464 }
465 if (lu->GetBegin() > currId) {
466 lu->SetBegin(currId);
467 }
468 }
469
470 if (CLANG) {
471 auto *a64CGFunc = static_cast<AArch64CGFunc *>(cgFunc);
472 MIRPreg *preg = a64CGFunc->GetPseudoRegFromVirtualRegNO(regNO, CGOptions::DoCGSSA());
473 if (preg) {
474 switch (preg->GetOp()) {
475 case OP_constval:
476 lr->SetRematerializable(preg->rematInfo.mirConst);
477 break;
478 case OP_addrof:
479 case OP_dread:
480 lr->SetRematerializable(preg->GetOp(), preg->rematInfo.sym, preg->fieldID, preg->addrUpper);
481 break;
482 case OP_undef:
483 break;
484 default:
485 DEBUG_ASSERT(false, "Unexpected op in Preg");
486 }
487 }
488 }
489
490 return lr;
491 }
492
CreateLiveRange(regno_t regNO,const BB & bb,bool isDef,uint32 currId,bool updateCount)493 void GraphColorRegAllocator::CreateLiveRange(regno_t regNO, const BB &bb, bool isDef, uint32 currId, bool updateCount)
494 {
495 bool isNonLocal = CreateLiveRangeHandleLocal(regNO, bb, isDef);
496
497 if (!isDef) {
498 --currId;
499 }
500
501 LiveRange *lr = CreateLiveRangeAllocateAndUpdate(regNO, bb, isDef, currId);
502 lr->SetRegNO(regNO);
503 lr->SetIsNonLocal(isNonLocal);
504 if (isDef) {
505 (void)vregLive.erase(regNO);
506 #ifdef OPTIMIZE_FOR_PROLOG
507 if (doOptProlog && updateCount) {
508 if (lr->GetNumDefs() == 0) {
509 lr->SetFrequency(lr->GetFrequency() + bb.GetFrequency());
510 }
511 lr->IncNumDefs();
512 }
513 #endif /* OPTIMIZE_FOR_PROLOG */
514 } else {
515 (void)vregLive.insert(regNO);
516 #ifdef OPTIMIZE_FOR_PROLOG
517 if (doOptProlog && updateCount) {
518 if (lr->GetNumUses() == 0) {
519 lr->SetFrequency(lr->GetFrequency() + bb.GetFrequency());
520 }
521 lr->IncNumUses();
522 }
523 #endif /* OPTIMIZE_FOR_PROLOG */
524 }
525 for (const auto &pregNO : pregLive) {
526 lr->InsertElemToPregveto(pregNO);
527 }
528
529 /* only handle it in live_in and def point? */
530 uint32 bbID = bb.GetId();
531 lr->SetMemberBitArrElem(bbID);
532
533 lrMap[regNO] = lr;
534 }
535
SetupLiveRangeByOpHandlePhysicalReg(const RegOperand & regOpnd,Insn & insn,regno_t regNO,bool isDef)536 bool GraphColorRegAllocator::SetupLiveRangeByOpHandlePhysicalReg(const RegOperand ®Opnd, Insn &insn, regno_t regNO,
537 bool isDef)
538 {
539 if (!regOpnd.IsPhysicalRegister()) {
540 return false;
541 }
542 LocalRaInfo *lraInfo = localRegVec[insn.GetBB()->GetId()];
543 if (lraInfo == nullptr) {
544 lraInfo = memPool->New<LocalRaInfo>(alloc);
545 localRegVec[insn.GetBB()->GetId()] = lraInfo;
546 }
547
548 if (isDef) {
549 if (FindNotIn(pregLive, regNO)) {
550 for (const auto &vRegNO : vregLive) {
551 if (IsUnconcernedReg(vRegNO)) {
552 continue;
553 }
554 lrMap[vRegNO]->InsertElemToPregveto(regNO);
555 }
556 }
557 pregLive.erase(regNO);
558 if (lraInfo != nullptr) {
559 lraInfo->SetDefCntElem(regNO, lraInfo->GetDefCntElem(regNO) + 1);
560 }
561 } else {
562 (void)pregLive.insert(regNO);
563 for (const auto &vregNO : vregLive) {
564 if (IsUnconcernedReg(vregNO)) {
565 continue;
566 }
567 LiveRange *lr = lrMap[vregNO];
568 lr->InsertElemToPregveto(regNO);
569 }
570
571 if (lraInfo != nullptr) {
572 lraInfo->SetUseCntElem(regNO, lraInfo->GetUseCntElem(regNO) + 1);
573 }
574 }
575 return true;
576 }
577
578 /*
579 * add pregs to forbidden list of lr. If preg is in
580 * the live list, then it is forbidden for other vreg on the list.
581 */
SetupLiveRangeByOp(Operand & op,Insn & insn,bool isDef,uint32 & numUses)582 void GraphColorRegAllocator::SetupLiveRangeByOp(Operand &op, Insn &insn, bool isDef, uint32 &numUses)
583 {
584 if (!op.IsRegister()) {
585 return;
586 }
587 auto ®Opnd = static_cast<RegOperand &>(op);
588 uint32 regNO = regOpnd.GetRegisterNumber();
589 if (IsUnconcernedReg(regOpnd)) {
590 if (GetLiveRange(regNO) != nullptr) {
591 DEBUG_ASSERT(false, "Unconcerned reg");
592 lrMap.erase(regNO);
593 }
594 return;
595 }
596 if (SetupLiveRangeByOpHandlePhysicalReg(regOpnd, insn, regNO, isDef)) {
597 return;
598 }
599
600 CreateLiveRange(regNO, *insn.GetBB(), isDef, insn.GetId(), true);
601
602 LiveRange *lr = GetLiveRange(regNO);
603 DEBUG_ASSERT(lr != nullptr, "lr should not be nullptr");
604 if (isDef) {
605 lr->SetSpillSize((regOpnd.GetSize() <= k32) ? k32 : k64);
606 }
607 if (lr->GetRegType() == kRegTyUndef) {
608 lr->SetRegType(regOpnd.GetRegisterType());
609 }
610 if (isDef) {
611 lr->GetLiveUnitFromLuMap(insn.GetBB()->GetId())->IncDefNum();
612 lr->AddRef(insn.GetBB()->GetId(), insn.GetId(), kIsDef);
613 } else {
614 lr->GetLiveUnitFromLuMap(insn.GetBB()->GetId())->IncUseNum();
615 lr->AddRef(insn.GetBB()->GetId(), insn.GetId(), kIsUse);
616 ++numUses;
617 }
618 #ifdef MOVE_COALESCE
619 if (insn.GetMachineOpcode() == MOP_xmovrr || insn.GetMachineOpcode() == MOP_wmovrr) {
620 RegOperand &opnd1 = static_cast<RegOperand &>(insn.GetOperand(1));
621 if (opnd1.GetRegisterNumber() < kAllRegNum && !IsUnconcernedReg(opnd1)) {
622 lr->InsertElemToPrefs(opnd1.GetRegisterNumber() - R0);
623 }
624 RegOperand &opnd0 = static_cast<RegOperand &>(insn.GetOperand(0));
625 if (opnd0.GetRegisterNumber() < kAllRegNum) {
626 DEBUG_ASSERT(opnd0.GetRegisterNumber() >= R0, "opnd0.GetRegisterNumber() - R0 should be unsigned");
627 lr->InsertElemToPrefs(opnd0.GetRegisterNumber() - R0);
628 }
629 }
630 #endif /* MOVE_COALESCE */
631 if (!insn.IsSpecialIntrinsic() && insn.GetBothDefUseOpnd() != kInsnMaxOpnd) {
632 lr->SetDefUse();
633 }
634 }
635
636 /* handle live range for bb->live_out */
SetupLiveRangeByRegNO(regno_t liveOut,BB & bb,uint32 currPoint)637 void GraphColorRegAllocator::SetupLiveRangeByRegNO(regno_t liveOut, BB &bb, uint32 currPoint)
638 {
639 if (IsUnconcernedReg(liveOut)) {
640 return;
641 }
642 if (liveOut >= kAllRegNum) {
643 (void)vregLive.insert(liveOut);
644 CreateLiveRange(liveOut, bb, false, currPoint, false);
645 return;
646 }
647
648 (void)pregLive.insert(liveOut);
649 for (const auto &vregNO : vregLive) {
650 LiveRange *lr = lrMap[vregNO];
651 lr->InsertElemToPregveto(liveOut);
652 }
653
654 /* See if phys reg is livein also. Then assume it span the entire bb. */
655 if (!FindIn(bb.GetLiveInRegNO(), liveOut)) {
656 return;
657 }
658 LocalRaInfo *lraInfo = localRegVec[bb.GetId()];
659 if (lraInfo == nullptr) {
660 lraInfo = memPool->New<LocalRaInfo>(alloc);
661 localRegVec[bb.GetId()] = lraInfo;
662 }
663 /* Make it a large enough so no locals can be allocated. */
664 lraInfo->SetUseCntElem(liveOut, kMaxUint16);
665 }
666
ClassifyOperand(std::unordered_set<regno_t> & pregs,std::unordered_set<regno_t> & vregs,const Operand & opnd) const667 void GraphColorRegAllocator::ClassifyOperand(std::unordered_set<regno_t> &pregs, std::unordered_set<regno_t> &vregs,
668 const Operand &opnd) const
669 {
670 if (!opnd.IsRegister()) {
671 return;
672 }
673 auto ®Opnd = static_cast<const RegOperand &>(opnd);
674 regno_t regNO = regOpnd.GetRegisterNumber();
675 if (IsUnconcernedReg(regNO)) {
676 return;
677 }
678 if (regOpnd.IsPhysicalRegister()) {
679 (void)pregs.insert(regNO);
680 } else {
681 (void)vregs.insert(regNO);
682 }
683 }
684
ComputeLiveRangesForEachDefOperand(Insn & insn,bool & multiDef)685 void GraphColorRegAllocator::ComputeLiveRangesForEachDefOperand(Insn &insn, bool &multiDef)
686 {
687 uint32 numDefs = 0;
688 uint32 numUses = 0;
689 const InsnDesc *md = insn.GetDesc();
690 uint32 opndNum = insn.GetOperandSize();
691 for (uint32 i = 0; i < opndNum; ++i) {
692 if (insn.GetMachineOpcode() == MOP_asm && (i == kAsmOutputListOpnd || i == kAsmClobberListOpnd)) {
693 for (auto opnd : static_cast<ListOperand &>(insn.GetOperand(i)).GetOperands()) {
694 SetupLiveRangeByOp(*static_cast<RegOperand *>(opnd), insn, true, numUses);
695 ++numDefs;
696 }
697 continue;
698 }
699 Operand &opnd = insn.GetOperand(i);
700 if (opnd.IsMemoryAccessOperand()) {
701 auto &memOpnd = static_cast<MemOperand &>(opnd);
702 if (!memOpnd.IsIntactIndexed()) {
703 SetupLiveRangeByOp(opnd, insn, true, numUses);
704 ++numDefs;
705 }
706 }
707 if (!md->GetOpndDes(i)->IsRegDef()) {
708 continue;
709 }
710 SetupLiveRangeByOp(opnd, insn, true, numUses);
711 ++numDefs;
712 }
713 DEBUG_ASSERT(numUses == 0, "should only be def opnd");
714 if (numDefs > 1) {
715 multiDef = true;
716 needExtraSpillReg = true;
717 }
718 }
719
ComputeLiveRangesForEachUseOperand(Insn & insn)720 void GraphColorRegAllocator::ComputeLiveRangesForEachUseOperand(Insn &insn)
721 {
722 uint32 numUses = 0;
723 const InsnDesc *md = insn.GetDesc();
724 uint32 opndNum = insn.GetOperandSize();
725 for (uint32 i = 0; i < opndNum; ++i) {
726 if (insn.GetMachineOpcode() == MOP_asm && i == kAsmInputListOpnd) {
727 for (auto opnd : static_cast<ListOperand &>(insn.GetOperand(i)).GetOperands()) {
728 SetupLiveRangeByOp(*static_cast<RegOperand *>(opnd), insn, false, numUses);
729 }
730 continue;
731 }
732 if (md->GetOpndDes(i)->IsRegDef() && !md->GetOpndDes(i)->IsRegUse()) {
733 continue;
734 }
735 Operand &opnd = insn.GetOperand(i);
736 if (opnd.IsList()) {
737 auto &listOpnd = static_cast<ListOperand &>(opnd);
738 for (auto op : listOpnd.GetOperands()) {
739 SetupLiveRangeByOp(*op, insn, false, numUses);
740 }
741 } else if (opnd.IsMemoryAccessOperand()) {
742 auto &memOpnd = static_cast<MemOperand &>(opnd);
743 Operand *base = memOpnd.GetBaseRegister();
744 Operand *offset = memOpnd.GetIndexRegister();
745 if (base != nullptr) {
746 SetupLiveRangeByOp(*base, insn, false, numUses);
747 }
748 if (offset != nullptr) {
749 SetupLiveRangeByOp(*offset, insn, false, numUses);
750 }
751 } else {
752 SetupLiveRangeByOp(opnd, insn, false, numUses);
753 }
754 }
755 if (numUses >= AArch64Abi::kNormalUseOperandNum || insn.GetMachineOpcode() == MOP_lazy_ldr) {
756 needExtraSpillReg = true;
757 }
758 }
759
ComputeLiveRangesUpdateIfInsnIsCall(const Insn & insn)760 void GraphColorRegAllocator::ComputeLiveRangesUpdateIfInsnIsCall(const Insn &insn)
761 {
762 if (!insn.IsCall()) {
763 return;
764 }
765 /* def the return value */
766 pregLive.erase(R0);
767 pregLive.erase(V0);
768
769 /* active the parametes */
770 Operand &opnd1 = insn.GetOperand(1);
771 if (opnd1.IsList()) {
772 auto &srcOpnds = static_cast<ListOperand &>(opnd1);
773 for (auto regOpnd : srcOpnds.GetOperands()) {
774 DEBUG_ASSERT(!regOpnd->IsVirtualRegister(), "not be a virtual register");
775 auto physicalReg = static_cast<AArch64reg>(regOpnd->GetRegisterNumber());
776 (void)pregLive.insert(physicalReg);
777 }
778 }
779 }
780
ComputeLiveRangesUpdateLiveUnitInsnRange(BB & bb,uint32 currPoint)781 void GraphColorRegAllocator::ComputeLiveRangesUpdateLiveUnitInsnRange(BB &bb, uint32 currPoint)
782 {
783 for (auto lin : bb.GetLiveInRegNO()) {
784 if (lin < kAllRegNum) {
785 continue;
786 }
787 LiveRange *lr = GetLiveRange(lin);
788 if (lr == nullptr) {
789 continue;
790 }
791 auto lu = lr->FindInLuMap(bb.GetId());
792 DEBUG_ASSERT(lu != lr->EndOfLuMap(), "container empty check");
793 if (bb.GetFirstInsn()) {
794 lu->second->SetBegin(bb.GetFirstInsn()->GetId());
795 } else {
796 /* since bb is empty, then use pointer as is */
797 lu->second->SetBegin(currPoint);
798 }
799 CHECK_FATAL(lu->second->GetBegin() >= 1, "value overflow");
800 lu->second->SetBegin(lu->second->GetBegin() - 1);
801 }
802 }
803
UpdateInsnCntAndSkipUseless(Insn & insn,uint32 & currPoint) const804 bool GraphColorRegAllocator::UpdateInsnCntAndSkipUseless(Insn &insn, uint32 &currPoint) const
805 {
806 insn.SetId(currPoint);
807 if (insn.IsImmaterialInsn() || !insn.IsMachineInstruction()) {
808 --currPoint;
809 return true;
810 }
811 return false;
812 }
813
UpdateCallInfo(uint32 bbId,uint32 currPoint,const Insn & insn)814 void GraphColorRegAllocator::UpdateCallInfo(uint32 bbId, uint32 currPoint, const Insn &insn)
815 {
816 auto *targetOpnd = insn.GetCallTargetOperand();
817 CHECK_FATAL(targetOpnd != nullptr, "target is null in Insn::IsCallToFunctionThatNeverReturns");
818 if (CGOptions::DoIPARA() && targetOpnd->IsFuncNameOpnd()) {
819 FuncNameOperand *target = static_cast<FuncNameOperand *>(targetOpnd);
820 const MIRSymbol *funcSt = target->GetFunctionSymbol();
821 DEBUG_ASSERT(funcSt->GetSKind() == kStFunc, "funcst must be a function name symbol");
822 MIRFunction *func = funcSt->GetFunction();
823 if (func != nullptr && func->IsReferedRegsValid()) {
824 for (auto preg : func->GetReferedRegs()) {
825 if (AArch64Abi::IsCallerSaveReg(static_cast<AArch64reg>(preg))) {
826 for (auto vregNO : vregLive) {
827 LiveRange *lr = lrMap[vregNO];
828 lr->InsertElemToCallDef(preg);
829 }
830 }
831 }
832 } else {
833 for (auto vregNO : vregLive) {
834 LiveRange *lr = lrMap[vregNO];
835 lr->SetCrossCall();
836 }
837 }
838 } else {
839 for (auto vregNO : vregLive) {
840 LiveRange *lr = lrMap[vregNO];
841 lr->SetCrossCall();
842 }
843 }
844 for (auto vregNO : vregLive) {
845 LiveRange *lr = lrMap[vregNO];
846 lr->IncNumCall();
847 lr->AddRef(bbId, currPoint, kIsCall);
848
849 auto lu = lr->FindInLuMap(bbId);
850 if (lu != lr->EndOfLuMap()) {
851 lu->second->SetHasCall(true);
852 }
853 }
854 }
855
SetLrMustAssign(const RegOperand * regOpnd)856 void GraphColorRegAllocator::SetLrMustAssign(const RegOperand *regOpnd)
857 {
858 regno_t regNO = regOpnd->GetRegisterNumber();
859 LiveRange *lr = GetLiveRange(regNO);
860 if (lr != nullptr) {
861 lr->SetMustAssigned();
862 lr->SetIsNonLocal(true);
863 }
864 }
865
SetupMustAssignedLiveRanges(const Insn & insn)866 void GraphColorRegAllocator::SetupMustAssignedLiveRanges(const Insn &insn)
867 {
868 if (!insn.IsSpecialIntrinsic()) {
869 return;
870 }
871 if (insn.GetMachineOpcode() == MOP_asm) {
872 for (auto regOpnd : static_cast<ListOperand &>(insn.GetOperand(kAsmOutputListOpnd)).GetOperands()) {
873 SetLrMustAssign(regOpnd);
874 }
875 for (auto regOpnd : static_cast<ListOperand &>(insn.GetOperand(kAsmInputListOpnd)).GetOperands()) {
876 SetLrMustAssign(regOpnd);
877 }
878 return;
879 }
880 uint32 opndNum = insn.GetOperandSize();
881 for (uint32 i = 0; i < opndNum; ++i) {
882 Operand *opnd = &insn.GetOperand(i);
883 if (!opnd->IsRegister()) {
884 continue;
885 }
886 auto regOpnd = static_cast<RegOperand *>(opnd);
887 SetLrMustAssign(regOpnd);
888 }
889 }
890
891 /* Create a common stack space for spilling with need_spill */
CreateSpillMem(uint32 spillIdx,SpillMemCheck check)892 MemOperand *GraphColorRegAllocator::CreateSpillMem(uint32 spillIdx, SpillMemCheck check)
893 {
894 if (spillIdx >= spillMemOpnds.size()) {
895 return nullptr;
896 }
897
898 if (operandSpilled[spillIdx]) {
899 /* For this insn, spill slot already used, need to find next available slot. */
900 uint32 i;
901 for (i = spillIdx + 1; i < kSpillMemOpndNum; ++i) {
902 if (!operandSpilled[i]) {
903 break;
904 }
905 }
906 CHECK_FATAL(i < kSpillMemOpndNum, "no more available spill mem slot");
907 spillIdx = i;
908 }
909 if (check == kSpillMemPost) {
910 operandSpilled[spillIdx] = true;
911 }
912
913 if (spillMemOpnds[spillIdx] == nullptr) {
914 regno_t reg = cgFunc->NewVReg(kRegTyInt, sizeof(int64));
915 auto *a64CGFunc = static_cast<AArch64CGFunc *>(cgFunc);
916 spillMemOpnds[spillIdx] = a64CGFunc->GetOrCreatSpillMem(reg);
917 }
918 return spillMemOpnds[spillIdx];
919 }
920
IsLocalReg(regno_t regNO) const921 bool GraphColorRegAllocator::IsLocalReg(regno_t regNO) const
922 {
923 LiveRange *lr = GetLiveRange(regNO);
924 if (lr == nullptr) {
925 LogInfo::MapleLogger() << "unexpected regNO" << regNO;
926 return true;
927 }
928 return IsLocalReg(*lr);
929 }
930
IsLocalReg(const LiveRange & lr) const931 bool GraphColorRegAllocator::IsLocalReg(const LiveRange &lr) const
932 {
933 return !lr.GetSplitLr() && (lr.GetNumBBMembers() == 1) && !lr.IsNonLocal();
934 }
935
CheckOverlap(uint64 val,uint32 i,LiveRange & lr1,LiveRange & lr2) const936 bool GraphColorRegAllocator::CheckOverlap(uint64 val, uint32 i, LiveRange &lr1, LiveRange &lr2) const
937 {
938 regno_t lr1RegNO = lr1.GetRegNO();
939 regno_t lr2RegNO = lr2.GetRegNO();
940 for (uint32 x = 0; x < kU64; ++x) {
941 if ((val & (1ULL << x)) != 0) {
942 uint32 lastBitSet = i * kU64 + x;
943 /*
944 * begin and end should be in the bb info (LU)
945 * Need to rethink this if.
946 * Under some circumstance, lr->begin can occur after lr->end.
947 */
948 auto lu1 = lr1.FindInLuMap(lastBitSet);
949 auto lu2 = lr2.FindInLuMap(lastBitSet);
950 if (lu1 != lr1.EndOfLuMap() && lu2 != lr2.EndOfLuMap() &&
951 !((lu1->second->GetBegin() < lu2->second->GetBegin() &&
952 lu1->second->GetEnd() < lu2->second->GetBegin()) ||
953 (lu2->second->GetBegin() < lu1->second->GetEnd() &&
954 lu2->second->GetEnd() < lu1->second->GetBegin()))) {
955 lr1.SetConflictBitArrElem(lr2RegNO);
956 lr2.SetConflictBitArrElem(lr1RegNO);
957 return true;
958 }
959 }
960 }
961 return false;
962 }
963
CheckInterference(LiveRange & lr1,LiveRange & lr2) const964 void GraphColorRegAllocator::CheckInterference(LiveRange &lr1, LiveRange &lr2) const
965 {
966 uint64 bitArr[bbBuckets];
967 for (uint32 i = 0; i < bbBuckets; ++i) {
968 bitArr[i] = lr1.GetBBMember()[i] & lr2.GetBBMember()[i];
969 }
970
971 for (uint32 i = 0; i < bbBuckets; ++i) {
972 DEBUG_ASSERT(bitArr[i] >= 0, "bitArr[i] must not be garbage or undefined");
973 uint64 val = bitArr[i];
974 if (val == 0) {
975 continue;
976 }
977 if (CheckOverlap(val, i, lr1, lr2)) {
978 break;
979 }
980 }
981 }
982
SetBBInfoGlobalAssigned(uint32 bbID,regno_t regNO)983 void GraphColorRegAllocator::SetBBInfoGlobalAssigned(uint32 bbID, regno_t regNO)
984 {
985 DEBUG_ASSERT(bbID < bbRegInfo.size(), "index out of range in GraphColorRegAllocator::SetBBInfoGlobalAssigned");
986 BBAssignInfo *bbInfo = bbRegInfo[bbID];
987 if (bbInfo == nullptr) {
988 bbInfo = memPool->New<BBAssignInfo>(alloc);
989 bbRegInfo[bbID] = bbInfo;
990 bbInfo->InitGlobalAssigned();
991 }
992 bbInfo->InsertElemToGlobalsAssigned(regNO);
993 }
994
HaveAvailableColor(const LiveRange & lr,uint32 num) const995 bool GraphColorRegAllocator::HaveAvailableColor(const LiveRange &lr, uint32 num) const
996 {
997 return ((lr.GetRegType() == kRegTyInt && num < intRegNum) || (lr.GetRegType() == kRegTyFloat && num < fpRegNum));
998 }
999
GetHighPriorityLr(MapleVector<LiveRange * > & lrSet) const1000 MapleVector<LiveRange *>::iterator GraphColorRegAllocator::GetHighPriorityLr(MapleVector<LiveRange *> &lrSet) const
1001 {
1002 auto it = lrSet.begin();
1003 auto highestIt = it;
1004 LiveRange *startLr = *it;
1005 float maxPrio = startLr->GetPriority();
1006 ++it;
1007 for (; it != lrSet.end(); ++it) {
1008 LiveRange *lr = *it;
1009 if (lr->GetPriority() > maxPrio) {
1010 maxPrio = lr->GetPriority();
1011 highestIt = it;
1012 }
1013 }
1014 return highestIt;
1015 }
1016
UpdateForbiddenForNeighbors(const LiveRange & lr) const1017 void GraphColorRegAllocator::UpdateForbiddenForNeighbors(const LiveRange &lr) const
1018 {
1019 auto updateForbidden = [&lr, this](regno_t regNO) {
1020 LiveRange *newLr = GetLiveRange(regNO);
1021 DEBUG_ASSERT(newLr != nullptr, "newLr should not be nullptr");
1022 if (!newLr->GetPregveto(lr.GetAssignedRegNO())) {
1023 newLr->InsertElemToForbidden(lr.GetAssignedRegNO());
1024 }
1025 };
1026 ForEachRegArrElem(lr.GetBBConflict(), updateForbidden);
1027 }
1028
UpdatePregvetoForNeighbors(const LiveRange & lr) const1029 void GraphColorRegAllocator::UpdatePregvetoForNeighbors(const LiveRange &lr) const
1030 {
1031 auto updatePregveto = [&lr, this](regno_t regNO) {
1032 LiveRange *newLr = GetLiveRange(regNO);
1033 DEBUG_ASSERT(newLr != nullptr, "newLr should not be nullptr");
1034 newLr->InsertElemToPregveto(lr.GetAssignedRegNO());
1035 newLr->EraseElemFromForbidden(lr.GetAssignedRegNO());
1036 };
1037 ForEachRegArrElem(lr.GetBBConflict(), updatePregveto);
1038 }
1039
1040 /*
1041 * For cases with only one def/use and crosses a call.
1042 * It might be more beneficial to spill vs save/restore in prolog/epilog.
1043 * But if the callee register is already used, then it is ok to reuse it again.
1044 * Or in certain cases, just use the callee.
1045 */
ShouldUseCallee(LiveRange & lr,const MapleSet<regno_t> & calleeUsed,const MapleVector<LiveRange * > & delayed) const1046 bool GraphColorRegAllocator::ShouldUseCallee(LiveRange &lr, const MapleSet<regno_t> &calleeUsed,
1047 const MapleVector<LiveRange *> &delayed) const
1048 {
1049 if (FindIn(calleeUsed, lr.GetAssignedRegNO())) {
1050 return true;
1051 }
1052 if (AArch64Abi::IsCalleeSavedReg(static_cast<AArch64reg>(lr.GetAssignedRegNO())) &&
1053 (calleeUsed.size() % kDivide2) != 0) {
1054 return true;
1055 }
1056 if (delayed.size() > 1 && calleeUsed.empty()) {
1057 /* If there are more than 1 vreg that can benefit from callee, use callee */
1058 return true;
1059 }
1060 lr.SetAssignedRegNO(0);
1061 return false;
1062 }
1063
AddCalleeUsed(regno_t regNO,RegType regType)1064 void GraphColorRegAllocator::AddCalleeUsed(regno_t regNO, RegType regType)
1065 {
1066 DEBUG_ASSERT(AArch64isa::IsPhysicalRegister(regNO), "regNO should be physical register");
1067 bool isCalleeReg = AArch64Abi::IsCalleeSavedReg(static_cast<AArch64reg>(regNO));
1068 if (isCalleeReg) {
1069 if (regType == kRegTyInt) {
1070 (void)intCalleeUsed.insert(regNO);
1071 } else {
1072 (void)fpCalleeUsed.insert(regNO);
1073 }
1074 }
1075 }
1076
TryToAssignCallerSave(const LiveRange & lr) const1077 regno_t GraphColorRegAllocator::TryToAssignCallerSave(const LiveRange &lr) const
1078 {
1079 regno_t base;
1080 RegType regType = lr.GetRegType();
1081 const MapleSet<uint32> *currRegSet = nullptr;
1082 if (regType == kRegTyInt) {
1083 currRegSet = &intCallerRegSet;
1084 base = R0;
1085 } else {
1086 currRegSet = &fpCallerRegSet;
1087 base = V0;
1088 }
1089
1090 regno_t reg = 0;
1091 #ifdef MOVE_COALESCE
1092 if (lr.GetNumCall() == 0 || (lr.GetNumDefs() + lr.GetNumUses() <= kRegNum2)) {
1093 for (const auto &it : lr.GetPrefs()) {
1094 reg = it + base;
1095 if ((FindIn(*currRegSet, reg)) && !lr.GetForbidden(reg) && !lr.GetPregveto(reg) && !lr.GetCallDef(reg)) {
1096 return reg;
1097 }
1098 }
1099 }
1100 #endif /* MOVE_COALESCE */
1101 for (const auto &it : *currRegSet) {
1102 reg = it + base;
1103 if (!lr.GetForbidden(reg) && !lr.GetPregveto(reg) && !lr.GetCallDef(reg)) {
1104 return reg;
1105 }
1106 }
1107 return 0;
1108 }
1109
1110 /*
1111 * If forbidden list has more registers than max of all BB's local reg
1112 * requirement, then LR can be colored.
1113 * Update LR's color if success, return true, else return false.
1114 */
AssignColorToLr(LiveRange & lr,bool isDelayed)1115 bool GraphColorRegAllocator::AssignColorToLr(LiveRange &lr, bool isDelayed)
1116 {
1117 if (lr.GetAssignedRegNO() > 0) {
1118 /* Already assigned. */
1119 return true;
1120 }
1121 if (!HaveAvailableColor(lr, lr.GetForbiddenSize() + lr.GetPregvetoSize())) {
1122 if (needDump) {
1123 LogInfo::MapleLogger() << "assigned fail to R" << lr.GetRegNO() << "\n";
1124 }
1125 return false;
1126 }
1127 if (needDump) {
1128 LogInfo::MapleLogger() << "assigned " << lr.GetAssignedRegNO() << " to R" << lr.GetRegNO() << "\n";
1129 }
1130 if (lr.GetAssignedRegNO() == 0) {
1131 return false;
1132 }
1133 #ifdef OPTIMIZE_FOR_PROLOG
1134 if (doOptProlog && isDelayed) {
1135 if ((lr.GetRegType() == kRegTyInt && !ShouldUseCallee(lr, intCalleeUsed, intDelayed)) ||
1136 (lr.GetRegType() == kRegTyFloat && !ShouldUseCallee(lr, fpCalleeUsed, fpDelayed))) {
1137 return false;
1138 }
1139 }
1140 #endif /* OPTIMIZE_FOR_PROLOG */
1141
1142 AddCalleeUsed(lr.GetAssignedRegNO(), lr.GetRegType());
1143
1144 UpdateForbiddenForNeighbors(lr);
1145 ForEachBBArrElem(lr.GetBBMember(),
1146 [&lr, this](uint32 bbID) { SetBBInfoGlobalAssigned(bbID, lr.GetAssignedRegNO()); });
1147 return true;
1148 }
1149
PruneLrForSplit(LiveRange & lr,BB & bb,bool remove,std::set<LoopDesc *,LoopDesc::LoopDescCmp> & candidateInLoop,std::set<LoopDesc *,LoopDesc::LoopDescCmp> & defInLoop)1150 void GraphColorRegAllocator::PruneLrForSplit(LiveRange &lr, BB &bb, bool remove,
1151 std::set<LoopDesc*, LoopDesc::LoopDescCmp> &candidateInLoop,
1152 std::set<LoopDesc*, LoopDesc::LoopDescCmp> &defInLoop)
1153 {
1154 if (bb.GetInternalFlag1()) {
1155 /* already visited */
1156 return;
1157 }
1158
1159 bb.SetInternalFlag1(true);
1160 auto lu = lr.FindInLuMap(bb.GetId());
1161 uint32 defNum = 0;
1162 uint32 useNum = 0;
1163 if (lu != lr.EndOfLuMap()) {
1164 defNum = lu->second->GetDefNum();
1165 useNum = lu->second->GetUseNum();
1166 }
1167
1168 auto *loop = loopInfo.GetBBLoopParent(bb.GetId());
1169 if (remove) {
1170 /* In removal mode, has not encountered a ref yet. */
1171 if (defNum == 0 && useNum == 0) {
1172 if (loop != nullptr && FindIn(candidateInLoop, loop)) {
1173 /*
1174 * Upward search has found a loop. Regardless of def/use
1175 * The loop members must be included in the new LR.
1176 */
1177 remove = false;
1178 } else {
1179 /* No ref in this bb. mark as potential remove. */
1180 bb.SetInternalFlag2(true);
1181 return;
1182 }
1183 } else {
1184 /* found a ref, no more removal of bb and preds. */
1185 remove = false;
1186 }
1187 }
1188
1189 if (loop != nullptr) {
1190 /* With a def in loop, cannot prune that loop */
1191 if (defNum > 0) {
1192 (void)defInLoop.insert(loop);
1193 }
1194 /* bb in loop, need to make sure of loop carried dependency */
1195 (void)candidateInLoop.insert(loop);
1196 }
1197 for (auto pred : bb.GetPreds()) {
1198 if (loop == nullptr || !loop->Has(*pred)) {
1199 PruneLrForSplit(lr, *pred, remove, candidateInLoop, defInLoop);
1200 }
1201 }
1202 }
1203
FindBBSharedInSplit(LiveRange & lr,const std::set<LoopDesc *,LoopDesc::LoopDescCmp> & candidateInLoop,std::set<LoopDesc *,LoopDesc::LoopDescCmp> & defInLoop)1204 void GraphColorRegAllocator::FindBBSharedInSplit(LiveRange &lr,
1205 const std::set<LoopDesc*, LoopDesc::LoopDescCmp> &candidateInLoop,
1206 std::set<LoopDesc*, LoopDesc::LoopDescCmp> &defInLoop)
1207 {
1208 /* A loop might be split into two. Need to see over the entire LR if there is a def in the loop. */
1209 auto FindBBSharedFunc = [&lr, &candidateInLoop, &defInLoop, this](uint32 bbID) {
1210 BB *bb = bbVec[bbID];
1211 auto *loop = loopInfo.GetBBLoopParent(bb->GetId());
1212 if (loop != nullptr && FindIn(candidateInLoop, loop)) {
1213 auto lu = lr.FindInLuMap(bb->GetId());
1214 if (lu != lr.EndOfLuMap() && lu->second->GetDefNum() > 0) {
1215 (void)defInLoop.insert(loop);
1216 }
1217 }
1218 };
1219 ForEachBBArrElem(lr.GetBBMember(), FindBBSharedFunc);
1220 }
1221
1222 /*
1223 * Backward traversal of the top part of the split LR.
1224 * Prune the part of the LR that has no downward exposing references.
1225 * Take into account of loops and loop carried dependencies.
1226 * The candidate bb to be removed, if in a loop, store that info.
1227 * If a LR crosses a loop, even if the loop has no def/use, it must
1228 * be included in the new LR.
1229 */
ComputeBBForNewSplit(LiveRange & newLr,LiveRange & origLr)1230 void GraphColorRegAllocator::ComputeBBForNewSplit(LiveRange &newLr, LiveRange &origLr)
1231 {
1232 /*
1233 * The candidate bb to be removed, if in a loop, store that info.
1234 * If a LR crosses a loop, even if the loop has no def/use, it must
1235 * be included in the new LR.
1236 */
1237 std::set<LoopDesc*, LoopDesc::LoopDescCmp> candidateInLoop;
1238 /* If a bb has a def and is in a loop, store that info. */
1239 std::set<LoopDesc*, LoopDesc::LoopDescCmp> defInLoop;
1240 std::set<BB *, SortedBBCmpFunc> smember;
1241 ForEachBBArrElem(newLr.GetBBMember(), [this, &smember](uint32 bbID) { (void)smember.insert(bbVec[bbID]); });
1242 for (auto bbIt = smember.rbegin(); bbIt != smember.rend(); ++bbIt) {
1243 BB *bb = *bbIt;
1244 if (bb->GetInternalFlag1() != 0) {
1245 continue;
1246 }
1247 PruneLrForSplit(newLr, *bb, true, candidateInLoop, defInLoop);
1248 }
1249 FindBBSharedInSplit(origLr, candidateInLoop, defInLoop);
1250 auto pruneTopLr = [this, &newLr, &candidateInLoop, &defInLoop](uint32 bbID) {
1251 BB *bb = bbVec[bbID];
1252 if (bb->GetInternalFlag2() != 0) {
1253 auto *loop = loopInfo.GetBBLoopParent(bb->GetId());
1254 if (loop != nullptr && FindIn(candidateInLoop, loop)) {
1255 return;
1256 }
1257 if (loop != nullptr || FindNotIn(defInLoop, loop)) {
1258 /* defInLoop should be a subset of candidateInLoop. remove. */
1259 newLr.UnsetMemberBitArrElem(bbID);
1260 }
1261 }
1262 };
1263 ForEachBBArrElem(newLr.GetBBMember(), pruneTopLr); /* prune the top LR. */
1264 }
1265
UseIsUncovered(const BB & bb,const BB & startBB,std::vector<bool> & visitedBB)1266 bool GraphColorRegAllocator::UseIsUncovered(const BB &bb, const BB &startBB, std::vector<bool> &visitedBB)
1267 {
1268 CHECK_FATAL(bb.GetId() < visitedBB.size(), "index out of range");
1269 visitedBB[bb.GetId()] = true;
1270 for (auto pred : bb.GetPreds()) {
1271 if (visitedBB[pred->GetId()]) {
1272 continue;
1273 }
1274 if (pred->GetLevel() <= startBB.GetLevel()) {
1275 return true;
1276 }
1277 if (UseIsUncovered(*pred, startBB, visitedBB)) {
1278 return true;
1279 }
1280 }
1281 return false;
1282 }
1283
FindUseForSplit(LiveRange & lr,SplitBBInfo & bbInfo,bool & remove,std::set<LoopDesc *,LoopDesc::LoopDescCmp> & candidateInLoop,std::set<LoopDesc *,LoopDesc::LoopDescCmp> & defInLoop)1284 void GraphColorRegAllocator::FindUseForSplit(LiveRange &lr, SplitBBInfo &bbInfo, bool &remove,
1285 std::set<LoopDesc*, LoopDesc::LoopDescCmp> &candidateInLoop,
1286 std::set<LoopDesc*, LoopDesc::LoopDescCmp> &defInLoop)
1287 {
1288 BB *bb = bbInfo.GetCandidateBB();
1289 const BB *startBB = bbInfo.GetStartBB();
1290 if (bb->GetInternalFlag1() != 0) {
1291 /* already visited */
1292 return;
1293 }
1294 for (auto pred : bb->GetPreds()) {
1295 if (pred->GetInternalFlag1() == 0) {
1296 return;
1297 }
1298 }
1299
1300 bb->SetInternalFlag1(true);
1301 auto lu = lr.FindInLuMap(bb->GetId());
1302 uint32 defNum = 0;
1303 uint32 useNum = 0;
1304 if (lu != lr.EndOfLuMap()) {
1305 defNum = lu->second->GetDefNum();
1306 useNum = lu->second->GetUseNum();
1307 }
1308
1309 std::vector<bool> visitedBB(cgFunc->GetAllBBs().size(), false);
1310 auto *loop = loopInfo.GetBBLoopParent(bb->GetId());
1311 if (remove) {
1312 /* In removal mode, has not encountered a ref yet. */
1313 if (defNum == 0 && useNum == 0) {
1314 /* No ref in this bb. mark as potential remove. */
1315 bb->SetInternalFlag2(true);
1316 if (loop != nullptr) {
1317 /* bb in loop, need to make sure of loop carried dependency */
1318 (void)candidateInLoop.insert(loop);
1319 }
1320 } else {
1321 /* found a ref, no more removal of bb and preds. */
1322 remove = false;
1323 /* A potential point for a upward exposing use. (might be a def). */
1324 lu->second->SetNeedReload(true);
1325 }
1326 } else if ((defNum > 0 || useNum > 0) && UseIsUncovered(*bb, *startBB, visitedBB)) {
1327 lu->second->SetNeedReload(true);
1328 }
1329
1330 /* With a def in loop, cannot prune that loop */
1331 if (loop != nullptr && defNum > 0) {
1332 (void)defInLoop.insert(loop);
1333 }
1334
1335 for (auto succ : bb->GetSuccs()) {
1336 if (loop && loop->Has(*succ)) {
1337 bbInfo.SetCandidateBB(*succ);
1338 FindUseForSplit(lr, bbInfo, remove, candidateInLoop, defInLoop);
1339 }
1340 }
1341 }
1342
ClearLrBBFlags(const std::set<BB *,SortedBBCmpFunc> & member) const1343 void GraphColorRegAllocator::ClearLrBBFlags(const std::set<BB *, SortedBBCmpFunc> &member) const
1344 {
1345 for (auto bb : member) {
1346 bb->SetInternalFlag1(0);
1347 bb->SetInternalFlag2(0);
1348 for (auto pred : bb->GetPreds()) {
1349 pred->SetInternalFlag1(0);
1350 pred->SetInternalFlag2(0);
1351 }
1352 }
1353 }
1354
1355 /*
1356 * Downward traversal of the bottom part of the split LR.
1357 * Prune the part of the LR that has no upward exposing references.
1358 * Take into account of loops and loop carried dependencies.
1359 */
ComputeBBForOldSplit(LiveRange & newLr,LiveRange & origLr)1360 void GraphColorRegAllocator::ComputeBBForOldSplit(LiveRange &newLr, LiveRange &origLr)
1361 {
1362 /* The candidate bb to be removed, if in a loop, store that info. */
1363 std::set<LoopDesc*, LoopDesc::LoopDescCmp> candidateInLoop;
1364 /* If a bb has a def and is in a loop, store that info. */
1365 std::set<LoopDesc*, LoopDesc::LoopDescCmp> defInLoop;
1366 SplitBBInfo bbInfo;
1367 bool remove = true;
1368
1369 std::set<BB *, SortedBBCmpFunc> smember;
1370 ForEachBBArrElem(origLr.GetBBMember(), [this, &smember](uint32 bbID) { (void)smember.insert(bbVec[bbID]); });
1371 ClearLrBBFlags(smember);
1372 for (auto bb : smember) {
1373 if (bb->GetInternalFlag1() != 0) {
1374 continue;
1375 }
1376 for (auto pred : bb->GetPreds()) {
1377 pred->SetInternalFlag1(true);
1378 }
1379 bbInfo.SetCandidateBB(*bb);
1380 bbInfo.SetStartBB(*bb);
1381 FindUseForSplit(origLr, bbInfo, remove, candidateInLoop, defInLoop);
1382 }
1383 FindBBSharedInSplit(newLr, candidateInLoop, defInLoop);
1384 auto pruneLrFunc = [&origLr, &defInLoop, this](uint32 bbID) {
1385 BB *bb = bbVec[bbID];
1386 if (bb->GetInternalFlag2() != 0) {
1387 auto *loop = loopInfo.GetBBLoopParent(bb->GetId());
1388 if (loop != nullptr && FindNotIn(defInLoop, loop)) {
1389 origLr.UnsetMemberBitArrElem(bbID);
1390 }
1391 }
1392 };
1393 ForEachBBArrElem(origLr.GetBBMember(), pruneLrFunc);
1394 }
1395
1396 /*
1397 * There is at least one available color for this BB from the neighbors
1398 * minus the ones reserved for local allocation.
1399 * bbAdded : The new BB to be added into the split LR if color is available.
1400 * conflictRegs : Reprent the LR before adding the bbAdded. These are the
1401 * forbidden regs before adding the new BBs.
1402 * Side effect : Adding the new forbidden regs from bbAdded into
1403 * conflictRegs if the LR can still be colored.
1404 */
LrCanBeColored(const LiveRange & lr,const BB & bbAdded,std::unordered_set<regno_t> & conflictRegs)1405 bool GraphColorRegAllocator::LrCanBeColored(const LiveRange &lr, const BB &bbAdded,
1406 std::unordered_set<regno_t> &conflictRegs)
1407 {
1408 RegType type = lr.GetRegType();
1409
1410 std::unordered_set<regno_t> newConflict;
1411 auto updateConflictFunc = [&bbAdded, &conflictRegs, &newConflict, &lr, this](regno_t regNO) {
1412 /* check the real conflict in current bb */
1413 LiveRange *conflictLr = lrMap[regNO];
1414 /*
1415 * If the bb to be added to the new LR has an actual
1416 * conflict with another LR, and if that LR has already
1417 * assigned a color that is not in the conflictRegs,
1418 * then add it as a newConflict.
1419 */
1420 if (IsBitArrElemSet(conflictLr->GetBBMember(), bbAdded.GetId())) {
1421 regno_t confReg = conflictLr->GetAssignedRegNO();
1422 if ((confReg > 0) && FindNotIn(conflictRegs, confReg) && !lr.GetPregveto(confReg)) {
1423 (void)newConflict.insert(confReg);
1424 }
1425 } else if (conflictLr->GetSplitLr() != nullptr &&
1426 IsBitArrElemSet(conflictLr->GetSplitLr()->GetBBMember(), bbAdded.GetId())) {
1427 /*
1428 * The after split LR is split into pieces, and this ensures
1429 * the after split color is taken into consideration.
1430 */
1431 regno_t confReg = conflictLr->GetSplitLr()->GetAssignedRegNO();
1432 if ((confReg > 0) && FindNotIn(conflictRegs, confReg) && !lr.GetPregveto(confReg)) {
1433 (void)newConflict.insert(confReg);
1434 }
1435 }
1436 };
1437 ForEachRegArrElem(lr.GetBBConflict(), updateConflictFunc);
1438
1439 size_t numRegs = newConflict.size() + lr.GetPregvetoSize() + conflictRegs.size();
1440
1441 bool canColor = false;
1442 if (type == kRegTyInt) {
1443 if (numRegs < intRegNum) {
1444 canColor = true;
1445 }
1446 } else if (numRegs < fpRegNum) {
1447 canColor = true;
1448 }
1449
1450 if (canColor) {
1451 for (auto regNO : newConflict) {
1452 (void)conflictRegs.insert(regNO);
1453 }
1454 }
1455
1456 /* Update all the registers conflicting when adding thew new bb. */
1457 return canColor;
1458 }
1459
1460 /* Support function for LR split. Move one BB from LR1 to LR2. */
MoveLrBBInfo(LiveRange & oldLr,LiveRange & newLr,BB & bb) const1461 void GraphColorRegAllocator::MoveLrBBInfo(LiveRange &oldLr, LiveRange &newLr, BB &bb) const
1462 {
1463 /* initialize backward traversal flag for the bb pruning phase */
1464 bb.SetInternalFlag1(false);
1465 /* initialize bb removal marker */
1466 bb.SetInternalFlag2(false);
1467 /* Insert BB into new LR */
1468 uint32 bbID = bb.GetId();
1469 newLr.SetMemberBitArrElem(bbID);
1470
1471 /* Move LU from old LR to new LR */
1472 auto luIt = oldLr.FindInLuMap(bb.GetId());
1473 if (luIt != oldLr.EndOfLuMap()) {
1474 newLr.SetElemToLuMap(luIt->first, *(luIt->second));
1475 oldLr.EraseLuMap(luIt);
1476 }
1477
1478 /* Remove BB from old LR */
1479 oldLr.UnsetMemberBitArrElem(bbID);
1480 }
1481
1482 /* Is the set of loops inside the loop? */
ContainsLoop(const LoopDesc & loop,const std::set<LoopDesc *,LoopDesc::LoopDescCmp> & loops) const1483 bool GraphColorRegAllocator::ContainsLoop(const LoopDesc &loop,
1484 const std::set<LoopDesc*, LoopDesc::LoopDescCmp> &loops) const
1485 {
1486 for (const auto *lp : loops) {
1487 while (lp != nullptr) {
1488 if (lp == &loop) {
1489 return true;
1490 }
1491 lp = lp->GetParentLoop();
1492 }
1493 }
1494 return false;
1495 }
1496
GetAllLrMemberLoops(LiveRange & lr,std::set<LoopDesc *,LoopDesc::LoopDescCmp> & loops)1497 void GraphColorRegAllocator::GetAllLrMemberLoops(LiveRange &lr, std::set<LoopDesc*, LoopDesc::LoopDescCmp> &loops)
1498 {
1499 auto GetLrMemberFunc = [&loops, this](uint32 bbID) {
1500 auto *loop = loopInfo.GetBBLoopParent(bbID);
1501 if (loop != nullptr) {
1502 (void)loops.insert(loop);
1503 }
1504 };
1505 ForEachBBArrElem(lr.GetBBMember(), GetLrMemberFunc);
1506 }
1507
SplitLrShouldSplit(LiveRange & lr)1508 bool GraphColorRegAllocator::SplitLrShouldSplit(LiveRange &lr)
1509 {
1510 if (lr.GetSplitLr() != nullptr || lr.GetNumBBMembers() == 1) {
1511 return false;
1512 }
1513 /* Need to split within the same hierarchy */
1514 uint32 loopID = 0xFFFFFFFF; /* loopID is initialized the maximum value,and then be assigned in function */
1515 bool needSplit = true;
1516 auto setNeedSplit = [&needSplit, &loopID, this](uint32 bbID) -> bool {
1517 auto *loop = loopInfo.GetBBLoopParent(bbID);
1518 if (loopID == 0xFFFFFFFF) {
1519 if (loop != nullptr) {
1520 loopID = loop->GetHeader().GetId();
1521 } else {
1522 loopID = 0;
1523 }
1524 } else if ((loop != nullptr && loop->GetHeader().GetId() != loopID) || (loop == nullptr && loopID != 0)) {
1525 needSplit = false;
1526 return true;
1527 }
1528 return false;
1529 };
1530 ForEachBBArrElemWithInterrupt(lr.GetBBMember(), setNeedSplit);
1531 return needSplit;
1532 }
1533
1534 /*
1535 * When a BB in the LR has no def or use in it, then potentially
1536 * there is no conflict within these BB for the new LR, since
1537 * the new LR will need to spill the defs which terminates the
1538 * new LR unless there is a use later which extends the new LR.
1539 * There is no need to compute conflicting register set unless
1540 * there is a def or use.
1541 * It is assumed that the new LR is extended to the def or use.
1542 * Initially newLr is empty, then add bb if can be colored.
1543 * Return true if there is a split.
1544 */
SplitLrFindCandidateLr(LiveRange & lr,LiveRange & newLr,std::unordered_set<regno_t> & conflictRegs)1545 bool GraphColorRegAllocator::SplitLrFindCandidateLr(LiveRange &lr, LiveRange &newLr,
1546 std::unordered_set<regno_t> &conflictRegs)
1547 {
1548 if (needDump) {
1549 LogInfo::MapleLogger() << "start split lr for vreg " << lr.GetRegNO() << "\n";
1550 }
1551 std::set<BB *, SortedBBCmpFunc> smember;
1552 ForEachBBArrElem(lr.GetBBMember(), [&smember, this](uint32 bbID) { (void)smember.insert(bbVec[bbID]); });
1553 for (auto bb : smember) {
1554 if (!LrCanBeColored(lr, *bb, conflictRegs)) {
1555 break;
1556 }
1557 MoveLrBBInfo(lr, newLr, *bb);
1558 }
1559
1560 /* return ture if split is successful */
1561 return newLr.GetNumBBMembers() != 0;
1562 }
1563
SplitLrHandleLoops(LiveRange & lr,LiveRange & newLr,const std::set<LoopDesc *,LoopDesc::LoopDescCmp> & origLoops,const std::set<LoopDesc *,LoopDesc::LoopDescCmp> & newLoops)1564 void GraphColorRegAllocator::SplitLrHandleLoops(LiveRange &lr, LiveRange &newLr,
1565 const std::set<LoopDesc*, LoopDesc::LoopDescCmp> &origLoops,
1566 const std::set<LoopDesc*, LoopDesc::LoopDescCmp> &newLoops)
1567 {
1568 /*
1569 * bb in loops might need a reload due to loop carried dependency.
1570 * Compute this before pruning the LRs.
1571 * if there is no re-definition, then reload is not necessary.
1572 * Part of the new LR region after the last reference is
1573 * no longer in the LR. Remove those bb.
1574 */
1575 ComputeBBForNewSplit(newLr, lr);
1576
1577 /* With new LR, recompute conflict. */
1578 auto recomputeConflict = [&lr, &newLr, this](uint32 bbID) {
1579 auto lrFunc = [&newLr, &bbID, this](regno_t regNO) {
1580 LiveRange *confLrVec = lrMap[regNO];
1581 if (IsBitArrElemSet(confLrVec->GetBBMember(), bbID) ||
1582 (confLrVec->GetSplitLr() != nullptr && IsBitArrElemSet(confLrVec->GetSplitLr()->GetBBMember(), bbID))) {
1583 /*
1584 * New LR getting the interference does not mean the
1585 * old LR can remove the interference.
1586 * Old LR's interference will be handled at the end of split.
1587 */
1588 newLr.SetConflictBitArrElem(regNO);
1589 }
1590 };
1591 ForEachRegArrElem(lr.GetBBConflict(), lrFunc);
1592 };
1593 ForEachBBArrElem(newLr.GetBBMember(), recomputeConflict);
1594
1595 /* update bb/loop same as for new LR. */
1596 ComputeBBForOldSplit(newLr, lr);
1597 /* Update the conflict interference for the original LR later. */
1598 for (auto loop : newLoops) {
1599 if (!ContainsLoop(*loop, origLoops)) {
1600 continue;
1601 }
1602 for (auto bbId : loop->GetLoopBBs()) {
1603 if (!IsBitArrElemSet(newLr.GetBBMember(), bbId)) {
1604 continue;
1605 }
1606 LiveUnit *lu = newLr.GetLiveUnitFromLuMap(bbId);
1607 if (lu->GetUseNum() != 0) {
1608 lu->SetNeedReload(true);
1609 }
1610 }
1611 }
1612 }
1613
SplitLrFixNewLrCallsAndRlod(LiveRange & newLr,const std::set<LoopDesc *,LoopDesc::LoopDescCmp> & origLoops)1614 void GraphColorRegAllocator::SplitLrFixNewLrCallsAndRlod(LiveRange &newLr,
1615 const std::set<LoopDesc*, LoopDesc::LoopDescCmp> &origLoops)
1616 {
1617 /* If a 2nd split loop is before the bb in 1st split bb. */
1618 newLr.SetNumCall(0);
1619 auto fixCallsAndRlod = [&newLr, &origLoops, this](uint32 bbID) {
1620 BB *bb = bbVec[bbID];
1621 for (auto loop : origLoops) {
1622 if (loop->GetHeader().GetLevel() >= bb->GetLevel()) {
1623 continue;
1624 }
1625 LiveUnit *lu = newLr.GetLiveUnitFromLuMap(bbID);
1626 if (lu->GetUseNum() != 0) {
1627 lu->SetNeedReload(true);
1628 }
1629 }
1630 LiveUnit *lu = newLr.GetLiveUnitFromLuMap(bbID);
1631 if (lu->HasCall()) {
1632 newLr.IncNumCall();
1633 }
1634 };
1635 ForEachBBArrElem(newLr.GetBBMember(), fixCallsAndRlod);
1636 }
1637
SplitLrFixOrigLrCalls(LiveRange & lr) const1638 void GraphColorRegAllocator::SplitLrFixOrigLrCalls(LiveRange &lr) const
1639 {
1640 lr.SetNumCall(0);
1641 auto fixOrigCalls = [&lr](uint32 bbID) {
1642 LiveUnit *lu = lr.GetLiveUnitFromLuMap(bbID);
1643 if (lu->HasCall()) {
1644 lr.IncNumCall();
1645 }
1646 };
1647 ForEachBBArrElem(lr.GetBBMember(), fixOrigCalls);
1648 }
1649
SplitLrUpdateInterference(LiveRange & lr)1650 void GraphColorRegAllocator::SplitLrUpdateInterference(LiveRange &lr)
1651 {
1652 /*
1653 * newLr is now a separate LR from the original lr.
1654 * Update the interference info.
1655 * Also recompute the forbidden info
1656 */
1657 lr.ClearForbidden();
1658 auto updateInterfrence = [&lr, this](regno_t regNO) {
1659 LiveRange *confLrVec = lrMap[regNO];
1660 if (IsBBsetOverlap(lr.GetBBMember(), confLrVec->GetBBMember(), bbBuckets)) {
1661 /* interfere */
1662 if (confLrVec->GetAssignedRegNO() && !lr.GetPregveto(confLrVec->GetAssignedRegNO())) {
1663 lr.InsertElemToForbidden(confLrVec->GetAssignedRegNO());
1664 }
1665 } else {
1666 /* no interference */
1667 lr.UnsetConflictBitArrElem(regNO);
1668 }
1669 };
1670 ForEachRegArrElem(lr.GetBBConflict(), updateInterfrence);
1671 }
1672
SplitLrUpdateRegInfo(const LiveRange & origLr,LiveRange & newLr,std::unordered_set<regno_t> & conflictRegs) const1673 void GraphColorRegAllocator::SplitLrUpdateRegInfo(const LiveRange &origLr, LiveRange &newLr,
1674 std::unordered_set<regno_t> &conflictRegs) const
1675 {
1676 for (regno_t regNO = kInvalidRegNO; regNO < kMaxRegNum; ++regNO) {
1677 if (origLr.GetPregveto(regNO)) {
1678 newLr.InsertElemToPregveto(regNO);
1679 }
1680 }
1681 for (auto regNO : conflictRegs) {
1682 if (!newLr.GetPregveto(regNO)) {
1683 newLr.InsertElemToForbidden(regNO);
1684 }
1685 }
1686 }
1687
SplitLrErrorCheckAndDebug(const LiveRange & origLr) const1688 void GraphColorRegAllocator::SplitLrErrorCheckAndDebug(const LiveRange &origLr) const
1689 {
1690 if (origLr.GetNumBBMembers() == 0) {
1691 DEBUG_ASSERT(origLr.GetNumBBConflicts() == 0, "Error: member and conflict not match");
1692 }
1693 }
1694
1695 /*
1696 * Pick a starting BB, then expand to maximize the new LR.
1697 * Return the new LR.
1698 */
SplitLr(LiveRange & lr)1699 void GraphColorRegAllocator::SplitLr(LiveRange &lr)
1700 {
1701 if (!SplitLrShouldSplit(lr)) {
1702 return;
1703 }
1704 LiveRange *newLr = NewLiveRange();
1705 /*
1706 * For the new LR, whenever a BB with either a def or
1707 * use is added, then add the registers that the neighbor
1708 * is using to the conflict register set indicating that these
1709 * registers cannot be used for the new LR's color.
1710 */
1711 std::unordered_set<regno_t> conflictRegs;
1712 if (!SplitLrFindCandidateLr(lr, *newLr, conflictRegs)) {
1713 return;
1714 }
1715 #ifdef REUSE_SPILLMEM
1716 /* Copy the original conflict vector for spill reuse optimization */
1717 lr.SetOldConflict(memPool->NewArray<uint64>(regBuckets));
1718 for (uint32 i = 0; i < regBuckets; ++i) {
1719 lr.SetBBConflictElem(static_cast<int32>(i), lr.GetBBConflictElem(static_cast<int32>(i)));
1720 }
1721 #endif /* REUSE_SPILLMEM */
1722
1723 std::set<LoopDesc*, LoopDesc::LoopDescCmp> newLoops;
1724 std::set<LoopDesc*, LoopDesc::LoopDescCmp> origLoops;
1725 GetAllLrMemberLoops(*newLr, newLoops);
1726 GetAllLrMemberLoops(lr, origLoops);
1727 SplitLrHandleLoops(lr, *newLr, origLoops, newLoops);
1728 SplitLrFixNewLrCallsAndRlod(*newLr, origLoops);
1729 SplitLrFixOrigLrCalls(lr);
1730
1731 SplitLrUpdateRegInfo(lr, *newLr, conflictRegs);
1732
1733 /* At this point, newLr should be unconstrained. */
1734 lr.SetSplitLr(*newLr);
1735
1736 newLr->SetRegNO(lr.GetRegNO());
1737 newLr->SetRegType(lr.GetRegType());
1738 newLr->SetID(lr.GetID());
1739 newLr->CopyRematerialization(lr);
1740 SplitLrUpdateInterference(lr);
1741
1742 AddCalleeUsed(newLr->GetAssignedRegNO(), newLr->GetRegType());
1743
1744 /* For the new LR, update assignment for local RA */
1745 ForEachBBArrElem(newLr->GetBBMember(),
1746 [&newLr, this](uint32 bbID) { SetBBInfoGlobalAssigned(bbID, newLr->GetAssignedRegNO()); });
1747
1748 UpdatePregvetoForNeighbors(*newLr);
1749
1750 SplitLrErrorCheckAndDebug(lr);
1751 }
1752
ColorForOptPrologEpilog()1753 void GraphColorRegAllocator::ColorForOptPrologEpilog()
1754 {
1755 #ifdef OPTIMIZE_FOR_PROLOG
1756 if (!doOptProlog) {
1757 return;
1758 }
1759 for (auto lr : intDelayed) {
1760 if (!AssignColorToLr(*lr, true)) {
1761 lr->SetSpilled(true);
1762 }
1763 }
1764 for (auto lr : fpDelayed) {
1765 if (!AssignColorToLr(*lr, true)) {
1766 lr->SetSpilled(true);
1767 }
1768 }
1769 #endif
1770 }
1771
1772 /*
1773 * From the sorted list of constrained LRs, pick the most profitable LR.
1774 * Split the LR into LRnew1 LRnew2 where LRnew1 has the maximum number of
1775 * BB and is colorable.
1776 * The starting BB for traversal must have a color available.
1777 *
1778 * Assign a color, update neighbor's forbidden list.
1779 *
1780 * Update the conflict graph by change the interference list.
1781 * In the case of both LRnew1 and LRnew2 conflicts with a BB, this BB's
1782 * #neightbors increased. If this BB was unconstrained, must check if
1783 * it is still unconstrained. Move to constrained if necessary.
1784 *
1785 * Color the unconstrained LRs.
1786 */
SplitAndColorForEachLr(MapleVector<LiveRange * > & targetLrVec)1787 void GraphColorRegAllocator::SplitAndColorForEachLr(MapleVector<LiveRange *> &targetLrVec)
1788 {
1789 while (!targetLrVec.empty()) {
1790 auto highestIt = GetHighPriorityLr(targetLrVec);
1791 LiveRange *lr = *highestIt;
1792 /* check those lrs in lr->sconflict which is in unconstrained whether it turns to constrined */
1793 if (highestIt != targetLrVec.end()) {
1794 targetLrVec.erase(highestIt);
1795 } else {
1796 DEBUG_ASSERT(false, "Error: not in targetLrVec");
1797 }
1798 if (AssignColorToLr(*lr)) {
1799 continue;
1800 }
1801 #ifdef USE_SPLIT
1802 SplitLr(*lr);
1803 #endif /* USE_SPLIT */
1804 /*
1805 * When LR is spilled, it potentially has no conflicts as
1806 * each def/use is spilled/reloaded.
1807 */
1808 #ifdef COLOR_SPLIT
1809 if (!AssignColorToLr(*lr)) {
1810 #endif /* COLOR_SPLIT */
1811 lr->SetSpilled(true);
1812 hasSpill = true;
1813 #ifdef COLOR_SPLIT
1814 }
1815 #endif /* COLOR_SPLIT */
1816 }
1817 }
1818
SplitAndColor()1819 void GraphColorRegAllocator::SplitAndColor()
1820 {
1821 /* handle mustAssigned */
1822 if (needDump) {
1823 LogInfo::MapleLogger() << " starting mustAssigned : \n";
1824 }
1825 SplitAndColorForEachLr(mustAssigned);
1826
1827 if (needDump) {
1828 LogInfo::MapleLogger() << " starting unconstrainedPref : \n";
1829 }
1830 /* assign color for unconstained */
1831 SplitAndColorForEachLr(unconstrainedPref);
1832
1833 if (needDump) {
1834 LogInfo::MapleLogger() << " starting constrained : \n";
1835 }
1836 /* handle constrained */
1837 SplitAndColorForEachLr(constrained);
1838
1839 if (needDump) {
1840 LogInfo::MapleLogger() << " starting unconstrained : \n";
1841 }
1842 /* assign color for unconstained */
1843 SplitAndColorForEachLr(unconstrained);
1844
1845 #ifdef OPTIMIZE_FOR_PROLOG
1846 if (doOptProlog) {
1847 ColorForOptPrologEpilog();
1848 }
1849 #endif /* OPTIMIZE_FOR_PROLOG */
1850 }
1851
HandleLocalRegAssignment(regno_t regNO,LocalRegAllocator & localRa,bool isInt)1852 void GraphColorRegAllocator::HandleLocalRegAssignment(regno_t regNO, LocalRegAllocator &localRa, bool isInt)
1853 {
1854 /* vreg, get a reg for it if not assigned already. */
1855 if (!localRa.IsInRegAssigned(regNO, isInt) && !localRa.isInRegSpilled(regNO, isInt)) {
1856 /* find an available phys reg */
1857 bool founded = false;
1858 LiveRange *lr = lrMap[regNO];
1859 regno_t maxIntReg = R0 + MaxIntPhysRegNum();
1860 regno_t maxFpReg = V0 + MaxFloatPhysRegNum();
1861 regno_t startReg = isInt ? R0 : V0;
1862 regno_t endReg = isInt ? maxIntReg : maxFpReg;
1863 for (uint32 preg = startReg; preg <= endReg; ++preg) {
1864 if (!localRa.IsPregAvailable(preg, isInt)) {
1865 continue;
1866 }
1867 if (lr->GetNumCall() != 0 && !AArch64Abi::IsCalleeSavedReg(static_cast<AArch64reg>(preg))) {
1868 continue;
1869 }
1870 if (lr->GetPregveto(preg)) {
1871 continue;
1872 }
1873 regno_t assignedReg = preg;
1874 localRa.ClearPregs(assignedReg, isInt);
1875 localRa.SetPregUsed(assignedReg, isInt);
1876 localRa.SetRegAssigned(regNO, isInt);
1877 localRa.SetRegAssignmentMap(isInt, regNO, assignedReg);
1878 lr->SetAssignedRegNO(assignedReg);
1879 founded = true;
1880 break;
1881 }
1882 if (!founded) {
1883 localRa.SetRegSpilled(regNO, isInt);
1884 lr->SetSpilled(true);
1885 }
1886 }
1887 }
1888
UpdateLocalRegDefUseCount(regno_t regNO,LocalRegAllocator & localRa,bool isDef,bool isInt) const1889 void GraphColorRegAllocator::UpdateLocalRegDefUseCount(regno_t regNO, LocalRegAllocator &localRa, bool isDef,
1890 bool isInt) const
1891 {
1892 auto usedIt = localRa.GetUseInfo().find(regNO);
1893 if (usedIt != localRa.GetUseInfo().end() && !isDef) {
1894 /* reg use, decrement count */
1895 DEBUG_ASSERT(usedIt->second > 0, "Incorrect local ra info");
1896 localRa.SetUseInfoElem(regNO, usedIt->second - 1);
1897 if (!AArch64isa::IsPhysicalRegister(static_cast<AArch64reg>(regNO)) && localRa.IsInRegAssigned(regNO, isInt)) {
1898 localRa.IncUseInfoElem(localRa.GetRegAssignmentItem(isInt, regNO));
1899 }
1900 if (needDump) {
1901 LogInfo::MapleLogger() << "\t\treg " << regNO << " update #use to " << localRa.GetUseInfoElem(regNO)
1902 << "\n";
1903 }
1904 }
1905
1906 auto defIt = localRa.GetDefInfo().find(regNO);
1907 if (defIt != localRa.GetDefInfo().end() && isDef) {
1908 /* reg def, decrement count */
1909 DEBUG_ASSERT(defIt->second > 0, "Incorrect local ra info");
1910 localRa.SetDefInfoElem(regNO, defIt->second - 1);
1911 if (!AArch64isa::IsPhysicalRegister(static_cast<AArch64reg>(regNO)) && localRa.IsInRegAssigned(regNO, isInt)) {
1912 localRa.IncDefInfoElem(localRa.GetRegAssignmentItem(isInt, regNO));
1913 }
1914 if (needDump) {
1915 LogInfo::MapleLogger() << "\t\treg " << regNO << " update #def to " << localRa.GetDefInfoElem(regNO)
1916 << "\n";
1917 }
1918 }
1919 }
1920
UpdateLocalRegConflict(regno_t regNO,LocalRegAllocator & localRa,bool isInt)1921 void GraphColorRegAllocator::UpdateLocalRegConflict(regno_t regNO, LocalRegAllocator &localRa, bool isInt)
1922 {
1923 LiveRange *lr = lrMap[regNO];
1924 if (lr->GetNumBBConflicts() == 0) {
1925 return;
1926 }
1927 if (!localRa.IsInRegAssigned(regNO, isInt)) {
1928 return;
1929 }
1930 regno_t preg = localRa.GetRegAssignmentItem(isInt, regNO);
1931 ForEachRegArrElem(lr->GetBBConflict(), [&preg, this](regno_t regNO) { lrMap[regNO]->InsertElemToPregveto(preg); });
1932 }
1933
HandleLocalRaDebug(regno_t regNO,const LocalRegAllocator & localRa,bool isInt) const1934 void GraphColorRegAllocator::HandleLocalRaDebug(regno_t regNO, const LocalRegAllocator &localRa, bool isInt) const
1935 {
1936 LogInfo::MapleLogger() << "HandleLocalReg " << regNO << "\n";
1937 LogInfo::MapleLogger() << "\tregUsed:";
1938 uint64 regUsed = localRa.GetPregUsed(isInt);
1939 regno_t base = isInt ? R0 : V0;
1940 regno_t end = isInt ? (RLR - R0) : (V31 - V0);
1941
1942 for (uint32 i = 0; i <= end; ++i) {
1943 if ((regUsed & (1ULL << i)) != 0) {
1944 LogInfo::MapleLogger() << " " << (i + base);
1945 }
1946 }
1947 LogInfo::MapleLogger() << "\n";
1948 LogInfo::MapleLogger() << "\tregs:";
1949 uint64 regs = localRa.GetPregs(isInt);
1950 for (uint32 regnoInLoop = 0; regnoInLoop <= end; ++regnoInLoop) {
1951 if ((regs & (1ULL << regnoInLoop)) != 0) {
1952 LogInfo::MapleLogger() << " " << (regnoInLoop + base);
1953 }
1954 }
1955 LogInfo::MapleLogger() << "\n";
1956 }
1957
HandleLocalReg(Operand & op,LocalRegAllocator & localRa,const BBAssignInfo * bbInfo,bool isDef,bool isInt)1958 void GraphColorRegAllocator::HandleLocalReg(Operand &op, LocalRegAllocator &localRa, const BBAssignInfo *bbInfo,
1959 bool isDef, bool isInt)
1960 {
1961 if (!op.IsRegister()) {
1962 return;
1963 }
1964 auto ®Opnd = static_cast<RegOperand &>(op);
1965 regno_t regNO = regOpnd.GetRegisterNumber();
1966
1967 if (IsUnconcernedReg(regOpnd)) {
1968 return;
1969 }
1970
1971 /* is this a local register ? */
1972 if (regNO >= kAllRegNum && !IsLocalReg(regNO)) {
1973 return;
1974 }
1975
1976 if (needDump) {
1977 HandleLocalRaDebug(regNO, localRa, isInt);
1978 }
1979
1980 if (regOpnd.IsPhysicalRegister()) {
1981 /* conflict with preg is record in lr->pregveto and BBAssignInfo->globalsAssigned */
1982 UpdateLocalRegDefUseCount(regNO, localRa, isDef, isInt);
1983 /* See if it is needed by global RA */
1984 if (localRa.GetUseInfoElem(regNO) == 0 && localRa.GetDefInfoElem(regNO) == 0) {
1985 if (bbInfo && !bbInfo->GetGlobalsAssigned(regNO)) {
1986 /* This phys reg is now available for assignment for a vreg */
1987 localRa.SetPregs(regNO, isInt);
1988 if (needDump) {
1989 LogInfo::MapleLogger() << "\t\tlast ref, phys-reg " << regNO << " now available\n";
1990 }
1991 }
1992 }
1993 } else {
1994 HandleLocalRegAssignment(regNO, localRa, isInt);
1995 UpdateLocalRegDefUseCount(regNO, localRa, isDef, isInt);
1996 UpdateLocalRegConflict(regNO, localRa, isInt);
1997 if (localRa.GetUseInfoElem(regNO) == 0 && localRa.GetDefInfoElem(regNO) == 0 &&
1998 localRa.IsInRegAssigned(regNO, isInt)) {
1999 /* last ref of vreg, release assignment */
2000 localRa.SetPregs(localRa.GetRegAssignmentItem(isInt, regNO), isInt);
2001 if (needDump) {
2002 LogInfo::MapleLogger() << "\t\tlast ref, release reg " << localRa.GetRegAssignmentItem(isInt, regNO)
2003 << " for " << regNO << "\n";
2004 }
2005 }
2006 }
2007 }
2008
LocalRaRegSetEraseReg(LocalRegAllocator & localRa,regno_t regNO) const2009 void GraphColorRegAllocator::LocalRaRegSetEraseReg(LocalRegAllocator &localRa, regno_t regNO) const
2010 {
2011 bool isInt = AArch64isa::IsGPRegister(static_cast<AArch64reg>(regNO));
2012 if (localRa.IsPregAvailable(regNO, isInt)) {
2013 localRa.ClearPregs(regNO, isInt);
2014 }
2015 }
2016
LocalRaInitRegSet(LocalRegAllocator & localRa,uint32 bbID)2017 bool GraphColorRegAllocator::LocalRaInitRegSet(LocalRegAllocator &localRa, uint32 bbID)
2018 {
2019 bool needLocalRa = false;
2020 /* Note physical regs start from R0, V0. */
2021 localRa.InitPregs(MaxIntPhysRegNum(), MaxFloatPhysRegNum(), cgFunc->GetCG()->GenYieldPoint(), intSpillRegSet,
2022 fpSpillRegSet);
2023
2024 localRa.ClearUseInfo();
2025 localRa.ClearDefInfo();
2026 LocalRaInfo *lraInfo = localRegVec[bbID];
2027 DEBUG_ASSERT(lraInfo != nullptr, "lraInfo not be nullptr");
2028 for (const auto &useCntPair : lraInfo->GetUseCnt()) {
2029 regno_t regNO = useCntPair.first;
2030 if (regNO >= kAllRegNum) {
2031 needLocalRa = true;
2032 }
2033 localRa.SetUseInfoElem(useCntPair.first, useCntPair.second);
2034 }
2035 for (const auto &defCntPair : lraInfo->GetDefCnt()) {
2036 regno_t regNO = defCntPair.first;
2037 if (regNO >= kAllRegNum) {
2038 needLocalRa = true;
2039 }
2040 localRa.SetDefInfoElem(defCntPair.first, defCntPair.second);
2041 }
2042 return needLocalRa;
2043 }
2044
LocalRaInitAllocatableRegs(LocalRegAllocator & localRa,uint32 bbID)2045 void GraphColorRegAllocator::LocalRaInitAllocatableRegs(LocalRegAllocator &localRa, uint32 bbID)
2046 {
2047 BBAssignInfo *bbInfo = bbRegInfo[bbID];
2048 if (bbInfo != nullptr) {
2049 for (regno_t regNO = kInvalidRegNO; regNO < kMaxRegNum; ++regNO) {
2050 if (bbInfo->GetGlobalsAssigned(regNO)) {
2051 LocalRaRegSetEraseReg(localRa, regNO);
2052 }
2053 }
2054 }
2055 }
2056
LocalRaForEachDefOperand(const Insn & insn,LocalRegAllocator & localRa,const BBAssignInfo * bbInfo)2057 void GraphColorRegAllocator::LocalRaForEachDefOperand(const Insn &insn, LocalRegAllocator &localRa,
2058 const BBAssignInfo *bbInfo)
2059 {
2060 const InsnDesc *md = insn.GetDesc();
2061 uint32 opndNum = insn.GetOperandSize();
2062 for (uint32 i = 0; i < opndNum; ++i) {
2063 Operand &opnd = insn.GetOperand(i);
2064 /* handle def opnd */
2065 if (!md->GetOpndDes(i)->IsRegDef()) {
2066 continue;
2067 }
2068 auto ®Opnd = static_cast<RegOperand &>(opnd);
2069 bool isInt = (regOpnd.GetRegisterType() == kRegTyInt);
2070 HandleLocalReg(opnd, localRa, bbInfo, true, isInt);
2071 }
2072 }
2073
LocalRaForEachUseOperand(const Insn & insn,LocalRegAllocator & localRa,const BBAssignInfo * bbInfo)2074 void GraphColorRegAllocator::LocalRaForEachUseOperand(const Insn &insn, LocalRegAllocator &localRa,
2075 const BBAssignInfo *bbInfo)
2076 {
2077 const InsnDesc *md = insn.GetDesc();
2078 uint32 opndNum = insn.GetOperandSize();
2079 for (uint32 i = 0; i < opndNum; ++i) {
2080 Operand &opnd = insn.GetOperand(i);
2081 if (opnd.IsList()) {
2082 continue;
2083 } else if (opnd.IsMemoryAccessOperand()) {
2084 auto &memOpnd = static_cast<MemOperand &>(opnd);
2085 Operand *base = memOpnd.GetBaseRegister();
2086 Operand *offset = memOpnd.GetIndexRegister();
2087 if (base != nullptr) {
2088 HandleLocalReg(*base, localRa, bbInfo, false, true);
2089 }
2090 if (!memOpnd.IsIntactIndexed() && base != nullptr) {
2091 HandleLocalReg(*base, localRa, bbInfo, true, true);
2092 }
2093 if (offset != nullptr) {
2094 HandleLocalReg(*offset, localRa, bbInfo, false, true);
2095 }
2096 } else if (md->GetOpndDes(i)->IsRegUse()) {
2097 auto ®Opnd = static_cast<RegOperand &>(opnd);
2098 bool isInt = (regOpnd.GetRegisterType() == kRegTyInt);
2099 HandleLocalReg(opnd, localRa, bbInfo, false, isInt);
2100 }
2101 }
2102 }
2103
LocalRaPrepareBB(BB & bb,LocalRegAllocator & localRa)2104 void GraphColorRegAllocator::LocalRaPrepareBB(BB &bb, LocalRegAllocator &localRa)
2105 {
2106 BBAssignInfo *bbInfo = bbRegInfo[bb.GetId()];
2107 FOR_BB_INSNS(insn, &bb) {
2108 if (!insn->IsMachineInstruction()) {
2109 continue;
2110 }
2111
2112 /*
2113 * Use reverse operand order, assuming use first then def for allocation.
2114 * need to free the use resource so it can be reused for def.
2115 */
2116 LocalRaForEachUseOperand(*insn, localRa, bbInfo);
2117 LocalRaForEachDefOperand(*insn, localRa, bbInfo);
2118 }
2119 }
2120
LocalRaFinalAssignment(const LocalRegAllocator & localRa,BBAssignInfo & bbInfo)2121 void GraphColorRegAllocator::LocalRaFinalAssignment(const LocalRegAllocator &localRa, BBAssignInfo &bbInfo)
2122 {
2123 for (const auto &intRegAssignmentMapPair : localRa.GetIntRegAssignmentMap()) {
2124 regno_t regNO = intRegAssignmentMapPair.second;
2125 if (needDump) {
2126 LogInfo::MapleLogger() << "[" << intRegAssignmentMapPair.first << "," << regNO << "],";
2127 }
2128 /* Might need to get rid of this copy. */
2129 bbInfo.SetRegMapElem(intRegAssignmentMapPair.first, regNO);
2130 AddCalleeUsed(regNO, kRegTyInt);
2131 }
2132 for (const auto &fpRegAssignmentMapPair : localRa.GetFpRegAssignmentMap()) {
2133 regno_t regNO = fpRegAssignmentMapPair.second;
2134 if (needDump) {
2135 LogInfo::MapleLogger() << "[" << fpRegAssignmentMapPair.first << "," << regNO << "],";
2136 }
2137 /* Might need to get rid of this copy. */
2138 bbInfo.SetRegMapElem(fpRegAssignmentMapPair.first, regNO);
2139 AddCalleeUsed(regNO, kRegTyFloat);
2140 }
2141 }
2142
LocalRaDebug(const BB & bb,const LocalRegAllocator & localRa) const2143 void GraphColorRegAllocator::LocalRaDebug(const BB &bb, const LocalRegAllocator &localRa) const
2144 {
2145 LogInfo::MapleLogger() << "bb " << bb.GetId() << " local ra INT need " << localRa.GetNumIntPregUsed() << " regs\n";
2146 LogInfo::MapleLogger() << "bb " << bb.GetId() << " local ra FP need " << localRa.GetNumFpPregUsed() << " regs\n";
2147 LogInfo::MapleLogger() << "\tpotential assignments:";
2148 for (auto it : localRa.GetIntRegAssignmentMap()) {
2149 LogInfo::MapleLogger() << "[" << it.first << "," << it.second << "],";
2150 }
2151 for (auto it : localRa.GetFpRegAssignmentMap()) {
2152 LogInfo::MapleLogger() << "[" << it.first << "," << it.second << "],";
2153 }
2154 LogInfo::MapleLogger() << "\n";
2155 }
2156
2157 /*
2158 * When do_allocate is false, it is prepass:
2159 * Traverse each BB, keep track of the number of registers required
2160 * for local registers in the BB. Communicate this to global RA.
2161 *
2162 * When do_allocate is true:
2163 * Allocate local registers for each BB based on unused registers
2164 * from global RA. Spill if no register available.
2165 */
LocalRegisterAllocator(bool doAllocate)2166 void GraphColorRegAllocator::LocalRegisterAllocator(bool doAllocate)
2167 {
2168 if (needDump) {
2169 if (doAllocate) {
2170 LogInfo::MapleLogger() << "LRA allocation start\n";
2171 PrintBBAssignInfo();
2172 } else {
2173 LogInfo::MapleLogger() << "LRA preprocessing start\n";
2174 }
2175 }
2176 LocalRegAllocator *localRa = memPool->New<LocalRegAllocator>(*cgFunc, alloc);
2177 for (auto *bb : bfs->sortedBBs) {
2178 uint32 bbID = bb->GetId();
2179
2180 LocalRaInfo *lraInfo = localRegVec[bb->GetId()];
2181 if (lraInfo == nullptr) {
2182 /* No locals to allocate */
2183 continue;
2184 }
2185
2186 localRa->ClearLocalRaInfo();
2187 bool needLocalRa = LocalRaInitRegSet(*localRa, bbID);
2188 if (!needLocalRa) {
2189 /* Only physical regs in bb, no local ra needed. */
2190 continue;
2191 }
2192
2193 if (doAllocate) {
2194 LocalRaInitAllocatableRegs(*localRa, bbID);
2195 }
2196
2197 LocalRaPrepareBB(*bb, *localRa);
2198
2199 BBAssignInfo *bbInfo = bbRegInfo[bb->GetId()];
2200 if (bbInfo == nullptr) {
2201 bbInfo = memPool->New<BBAssignInfo>(alloc);
2202 bbRegInfo[bbID] = bbInfo;
2203 bbInfo->InitGlobalAssigned();
2204 }
2205 bbInfo->SetIntLocalRegsNeeded(localRa->GetNumIntPregUsed());
2206 bbInfo->SetFpLocalRegsNeeded(localRa->GetNumFpPregUsed());
2207
2208 if (doAllocate) {
2209 if (needDump) {
2210 LogInfo::MapleLogger() << "\tbb(" << bb->GetId() << ")final local ra assignments:";
2211 }
2212 LocalRaFinalAssignment(*localRa, *bbInfo);
2213 if (needDump) {
2214 LogInfo::MapleLogger() << "\n";
2215 }
2216 } else if (needDump) {
2217 LocalRaDebug(*bb, *localRa);
2218 }
2219 }
2220 }
2221
GetConsistentReuseMem(const uint64 * conflict,const std::set<MemOperand * > & usedMemOpnd,uint32 size,RegType regType)2222 MemOperand *GraphColorRegAllocator::GetConsistentReuseMem(const uint64 *conflict,
2223 const std::set<MemOperand *> &usedMemOpnd, uint32 size,
2224 RegType regType)
2225 {
2226 std::set<LiveRange *, SetLiveRangeCmpFunc> sconflict;
2227 regno_t regNO;
2228 for (uint32 i = 0; i < regBuckets; ++i) {
2229 for (uint32 b = 0; b < kU64; ++b) {
2230 if ((conflict[i] & (1ULL << b)) != 0) {
2231 continue;
2232 }
2233 regNO = i * kU64 + b;
2234 if (regNO >= numVregs) {
2235 break;
2236 }
2237 if (GetLiveRange(regNO) != nullptr) {
2238 (void)sconflict.insert(lrMap[regNO]);
2239 }
2240 }
2241 }
2242
2243 for (auto *noConflictLr : sconflict) {
2244 if (noConflictLr == nullptr || noConflictLr->GetRegType() != regType || noConflictLr->GetSpillSize() != size) {
2245 continue;
2246 }
2247 if (usedMemOpnd.find(noConflictLr->GetSpillMem()) == usedMemOpnd.end()) {
2248 return noConflictLr->GetSpillMem();
2249 }
2250 }
2251 return nullptr;
2252 }
2253
GetCommonReuseMem(const uint64 * conflict,const std::set<MemOperand * > & usedMemOpnd,uint32 size,RegType regType)2254 MemOperand *GraphColorRegAllocator::GetCommonReuseMem(const uint64 *conflict, const std::set<MemOperand *> &usedMemOpnd,
2255 uint32 size, RegType regType)
2256 {
2257 regno_t regNO;
2258 for (uint32 i = 0; i < regBuckets; ++i) {
2259 for (uint32 b = 0; b < kU64; ++b) {
2260 if ((conflict[i] & (1ULL << b)) != 0) {
2261 continue;
2262 }
2263 regNO = i * kU64 + b;
2264 if (regNO >= numVregs) {
2265 break;
2266 }
2267 LiveRange *noConflictLr = GetLiveRange(regNO);
2268 if (noConflictLr == nullptr || noConflictLr->GetRegType() != regType ||
2269 noConflictLr->GetSpillSize() != size) {
2270 continue;
2271 }
2272 if (usedMemOpnd.find(noConflictLr->GetSpillMem()) == usedMemOpnd.end()) {
2273 return noConflictLr->GetSpillMem();
2274 }
2275 }
2276 }
2277 return nullptr;
2278 }
2279
2280 /* See if any of the non-conflict LR is spilled and use its memOpnd. */
GetReuseMem(uint32 vregNO,uint32 size,RegType regType)2281 MemOperand *GraphColorRegAllocator::GetReuseMem(uint32 vregNO, uint32 size, RegType regType)
2282 {
2283 if (cgFunc->GetMirModule().GetSrcLang() != kSrcLangC) {
2284 return nullptr;
2285 }
2286 if (IsLocalReg(vregNO)) {
2287 return nullptr;
2288 }
2289
2290 LiveRange *lr = lrMap[vregNO];
2291 const uint64 *conflict;
2292 if (lr->GetSplitLr() != nullptr) {
2293 /*
2294 * For split LR, the vreg liveness is optimized, but for spill location
2295 * the stack location needs to be maintained for the entire LR.
2296 */
2297 return nullptr;
2298 } else {
2299 conflict = lr->GetBBConflict();
2300 }
2301
2302 std::set<MemOperand *> usedMemOpnd;
2303 auto updateMemOpnd = [&usedMemOpnd, this](regno_t regNO) {
2304 if (regNO >= numVregs) {
2305 return;
2306 }
2307 LiveRange *lrInner = GetLiveRange(regNO);
2308 if (lrInner && lrInner->GetSpillMem() != nullptr) {
2309 (void)usedMemOpnd.insert(lrInner->GetSpillMem());
2310 }
2311 };
2312 ForEachRegArrElem(conflict, updateMemOpnd);
2313 uint32 regSize = (size <= k32) ? k32 : k64;
2314 /*
2315 * This is to order the search so memOpnd given out is consistent.
2316 * When vreg#s do not change going through VtableImpl.mpl file
2317 * then this can be simplified.
2318 */
2319 #ifdef CONSISTENT_MEMOPND
2320 return GetConsistentReuseMem(conflict, usedMemOpnd, regSize, regType);
2321 #else /* CONSISTENT_MEMOPND */
2322 return GetCommonReuseMem(conflict, usedMemOpnd, regSize, regType);
2323 #endif /* CONSISTENT_MEMOPNDi */
2324 }
2325
GetSpillMem(uint32 vregNO,bool isDest,Insn & insn,AArch64reg regNO,bool & isOutOfRange) const2326 MemOperand *GraphColorRegAllocator::GetSpillMem(uint32 vregNO, bool isDest, Insn &insn, AArch64reg regNO,
2327 bool &isOutOfRange) const
2328 {
2329 auto *a64CGFunc = static_cast<AArch64CGFunc *>(cgFunc);
2330 MemOperand *memOpnd = a64CGFunc->GetOrCreatSpillMem(vregNO);
2331 return (a64CGFunc->AdjustMemOperandIfOffsetOutOfRange(memOpnd, vregNO, isDest, insn, regNO, isOutOfRange));
2332 }
2333
SpillOperandForSpillPre(Insn & insn,const Operand & opnd,RegOperand & phyOpnd,uint32 spillIdx,bool needSpill)2334 void GraphColorRegAllocator::SpillOperandForSpillPre(Insn &insn, const Operand &opnd, RegOperand &phyOpnd,
2335 uint32 spillIdx, bool needSpill)
2336 {
2337 if (!needSpill) {
2338 return;
2339 }
2340 auto ®Opnd = static_cast<const RegOperand &>(opnd);
2341 uint32 regNO = regOpnd.GetRegisterNumber();
2342 LiveRange *lr = lrMap[regNO];
2343
2344 auto *a64CGFunc = static_cast<AArch64CGFunc *>(cgFunc);
2345
2346 MemOperand *spillMem = CreateSpillMem(spillIdx, kSpillMemPre);
2347 DEBUG_ASSERT(spillMem != nullptr, "spillMem nullptr check");
2348
2349 uint32 regSize = regOpnd.GetSize();
2350 PrimType stype;
2351 RegType regType = regOpnd.GetRegisterType();
2352 if (regType == kRegTyInt) {
2353 stype = (regSize <= k32) ? PTY_i32 : PTY_i64;
2354 } else {
2355 stype = (regSize <= k32) ? PTY_f32 : PTY_f64;
2356 }
2357
2358 if (a64CGFunc->IsImmediateOffsetOutOfRange(*spillMem, k64)) {
2359 regno_t pregNO = R16;
2360 spillMem =
2361 &a64CGFunc->SplitOffsetWithAddInstruction(*spillMem, k64, static_cast<AArch64reg>(pregNO), false, &insn);
2362 }
2363 Insn &stInsn =
2364 cgFunc->GetInsnBuilder()->BuildInsn(a64CGFunc->PickStInsn(spillMem->GetSize(), stype), phyOpnd, *spillMem);
2365 std::string comment = " SPILL for spill vreg: " + std::to_string(regNO) + " op:" + kOpcodeInfo.GetName(lr->GetOp());
2366 stInsn.SetComment(comment);
2367 insn.GetBB()->InsertInsnBefore(insn, stInsn);
2368 }
2369
GetSpillOrReuseMem(LiveRange & lr,uint32 regSize,bool & isOutOfRange,Insn & insn,bool isDef)2370 MemOperand *GraphColorRegAllocator::GetSpillOrReuseMem(LiveRange &lr, uint32 regSize, bool &isOutOfRange, Insn &insn,
2371 bool isDef)
2372 {
2373 (void)regSize;
2374 MemOperand *memOpnd = nullptr;
2375 if (lr.GetSpillMem() != nullptr) {
2376 /* the saved memOpnd cannot be out-of-range */
2377 memOpnd = lr.GetSpillMem();
2378 } else {
2379 #ifdef REUSE_SPILLMEM
2380 memOpnd = GetReuseMem(lr.GetRegNO(), regSize, lr.GetRegType());
2381 if (memOpnd != nullptr) {
2382 lr.SetSpillMem(*memOpnd);
2383 lr.SetSpillSize((regSize <= k32) ? k32 : k64);
2384 } else {
2385 #endif /* REUSE_SPILLMEM */
2386 regno_t baseRegNO;
2387 if (!isDef && lr.GetRegNO() == kRegTyInt) {
2388 /* src will use its' spill reg as baseRegister when offset out-of-range
2389 * add x16, x29, #max-offset //out-of-range
2390 * ldr x16, [x16, #offset] //reload
2391 * mov xd, x16
2392 */
2393 baseRegNO = lr.GetSpillReg();
2394 if (baseRegNO > RLAST_INT_REG) {
2395 baseRegNO = R16;
2396 }
2397 } else {
2398 /* dest will use R16 as baseRegister when offset out-of-range
2399 * mov x16, xs
2400 * add x17, x29, #max-offset //out-of-range
2401 * str x16, [x17, #offset] //spill
2402 */
2403 baseRegNO = R16;
2404 }
2405 DEBUG_ASSERT(baseRegNO != kRinvalid, "invalid base register number");
2406 memOpnd = GetSpillMem(lr.GetRegNO(), isDef, insn, static_cast<AArch64reg>(baseRegNO), isOutOfRange);
2407 /* dest's spill reg can only be R15 and R16 () */
2408 if (isOutOfRange && isDef) {
2409 DEBUG_ASSERT(lr.GetSpillReg() != R16, "can not find valid memopnd's base register");
2410 }
2411 #ifdef REUSE_SPILLMEM
2412 if (isOutOfRange == 0) {
2413 lr.SetSpillMem(*memOpnd);
2414 lr.SetSpillSize((regSize <= k32) ? k32 : k64);
2415 }
2416 }
2417 #endif /* REUSE_SPILLMEM */
2418 }
2419 return memOpnd;
2420 }
2421
2422 /* Try to find available reg for spill. */
SetAvailableSpillReg(std::unordered_set<regno_t> & cannotUseReg,LiveRange & lr,uint64 & usedRegMask)2423 bool GraphColorRegAllocator::SetAvailableSpillReg(std::unordered_set<regno_t> &cannotUseReg, LiveRange &lr,
2424 uint64 &usedRegMask)
2425 {
2426 bool isInt = (lr.GetRegType() == kRegTyInt);
2427 regno_t base = isInt ? R0 : V0;
2428 uint32 pregInterval = isInt ? 0 : (V0 - R30);
2429 MapleSet<uint32> &callerRegSet = isInt ? intCallerRegSet : fpCallerRegSet;
2430 MapleSet<uint32> &calleeRegSet = isInt ? intCalleeRegSet : fpCalleeRegSet;
2431
2432 for (const auto &it : callerRegSet) {
2433 regno_t spillReg = it + base;
2434 if (cannotUseReg.find(spillReg) == cannotUseReg.end() &&
2435 (usedRegMask & (1ULL << (spillReg - pregInterval))) == 0) {
2436 lr.SetAssignedRegNO(spillReg);
2437 usedRegMask |= 1ULL << (spillReg - pregInterval);
2438 return true;
2439 }
2440 }
2441 for (const auto &it : calleeRegSet) {
2442 regno_t spillReg = it + base;
2443 if (cannotUseReg.find(spillReg) == cannotUseReg.end() &&
2444 (usedRegMask & (1ULL << (spillReg - pregInterval))) == 0) {
2445 lr.SetAssignedRegNO(spillReg);
2446 usedRegMask |= 1ULL << (spillReg - pregInterval);
2447 return true;
2448 }
2449 }
2450 return false;
2451 }
2452
CollectCannotUseReg(std::unordered_set<regno_t> & cannotUseReg,const LiveRange & lr,Insn & insn)2453 void GraphColorRegAllocator::CollectCannotUseReg(std::unordered_set<regno_t> &cannotUseReg, const LiveRange &lr,
2454 Insn &insn)
2455 {
2456 /* Find the bb in the conflict LR that actually conflicts with the current bb. */
2457 for (regno_t regNO = kRinvalid; regNO < kMaxRegNum; ++regNO) {
2458 if (lr.GetPregveto(regNO)) {
2459 (void)cannotUseReg.insert(regNO);
2460 }
2461 }
2462 auto updateCannotUse = [&insn, &cannotUseReg, this](regno_t regNO) {
2463 LiveRange *conflictLr = lrMap[regNO];
2464 /*
2465 * conflictLr->GetAssignedRegNO() might be zero
2466 * caller save will be inserted so the assigned reg can be released actually
2467 */
2468 if ((conflictLr->GetAssignedRegNO() > 0) && IsBitArrElemSet(conflictLr->GetBBMember(), insn.GetBB()->GetId())) {
2469 if (!AArch64Abi::IsCalleeSavedReg(static_cast<AArch64reg>(conflictLr->GetAssignedRegNO())) &&
2470 conflictLr->GetNumCall() && !conflictLr->GetProcessed()) {
2471 return;
2472 }
2473 (void)cannotUseReg.insert(conflictLr->GetAssignedRegNO());
2474 }
2475 };
2476 ForEachRegArrElem(lr.GetBBConflict(), updateCannotUse);
2477 #ifdef USE_LRA
2478 if (!doLRA) {
2479 return;
2480 }
2481 BBAssignInfo *bbInfo = bbRegInfo[insn.GetBB()->GetId()];
2482 if (bbInfo != nullptr) {
2483 for (const auto ®MapPair : bbInfo->GetRegMap()) {
2484 (void)cannotUseReg.insert(regMapPair.second);
2485 }
2486 }
2487 #endif /* USE_LRA */
2488 }
2489
PickRegForSpill(uint64 & usedRegMask,RegType regType,uint32 spillIdx,bool & needSpillLr)2490 regno_t GraphColorRegAllocator::PickRegForSpill(uint64 &usedRegMask, RegType regType, uint32 spillIdx,
2491 bool &needSpillLr)
2492 {
2493 regno_t base;
2494 regno_t spillReg;
2495 uint32 pregInterval;
2496 bool isIntReg = (regType == kRegTyInt);
2497 if (isIntReg) {
2498 base = R0;
2499 pregInterval = 0;
2500 } else {
2501 base = V0;
2502 pregInterval = V0 - R30;
2503 }
2504
2505 /* Temporary find a unused reg to spill */
2506 uint32 maxPhysRegNum = isIntReg ? MaxIntPhysRegNum() : MaxFloatPhysRegNum();
2507 for (spillReg = (maxPhysRegNum + base); spillReg > base; --spillReg) {
2508 if (spillReg >= k64BitSize) {
2509 spillReg = k64BitSize - 1;
2510 }
2511 if ((usedRegMask & (1ULL << (spillReg - pregInterval))) == 0) {
2512 usedRegMask |= (1ULL << (spillReg - pregInterval));
2513 needSpillLr = true;
2514 return spillReg;
2515 }
2516 }
2517
2518 DEBUG_ASSERT(false, "can not find spillReg");
2519 return 0;
2520 }
2521
2522 /* return true if need extra spill */
SetRegForSpill(LiveRange & lr,Insn & insn,uint32 spillIdx,uint64 & usedRegMask,bool isDef)2523 bool GraphColorRegAllocator::SetRegForSpill(LiveRange &lr, Insn &insn, uint32 spillIdx, uint64 &usedRegMask, bool isDef)
2524 {
2525 std::unordered_set<regno_t> cannotUseReg;
2526 /* SPILL COALESCE */
2527 if (!isDef && (insn.GetMachineOpcode() == MOP_xmovrr || insn.GetMachineOpcode() == MOP_wmovrr)) {
2528 auto &ropnd = static_cast<RegOperand &>(insn.GetOperand(0));
2529 if (ropnd.IsPhysicalRegister()) {
2530 lr.SetAssignedRegNO(ropnd.GetRegisterNumber());
2531 return false;
2532 }
2533 }
2534
2535 CollectCannotUseReg(cannotUseReg, lr, insn);
2536
2537 if (SetAvailableSpillReg(cannotUseReg, lr, usedRegMask)) {
2538 return false;
2539 }
2540
2541 bool needSpillLr = false;
2542 if (!lr.GetAssignedRegNO()) {
2543 /*
2544 * All regs are assigned and none are free.
2545 * Pick a reg to spill and reuse for this spill.
2546 * Need to make sure the reg picked is not assigned to this insn,
2547 * else there will be conflict.
2548 */
2549 RegType regType = lr.GetRegType();
2550 regno_t spillReg = PickRegForSpill(usedRegMask, regType, spillIdx, needSpillLr);
2551 if (insn.GetMachineOpcode() == MOP_lazy_ldr && spillReg == R17) {
2552 CHECK_FATAL(false, "register IP1(R17) may be changed when lazy_ldr");
2553 }
2554 lr.SetAssignedRegNO(spillReg);
2555 }
2556 return needSpillLr;
2557 }
2558
2559 /* get spill reg and check if need extra spill */
GetSpillReg(Insn & insn,LiveRange & lr,const uint32 & spillIdx,uint64 & usedRegMask,bool isDef)2560 bool GraphColorRegAllocator::GetSpillReg(Insn &insn, LiveRange &lr, const uint32 &spillIdx, uint64 &usedRegMask,
2561 bool isDef)
2562 {
2563 bool needSpillLr = false;
2564 /*
2565 * Find a spill reg for the BB among interfereing LR.
2566 * Without LRA, this info is very inaccurate. It will falsely interfere
2567 * with all locals which the spill might not be interfering.
2568 * For now, every instance of the spill requires a brand new reg assignment.
2569 */
2570 if (needDump) {
2571 LogInfo::MapleLogger() << "LR-regNO " << lr.GetRegNO() << " spilled, finding a spill reg\n";
2572 }
2573 if (insn.IsBranch() || insn.IsCall() || (insn.GetMachineOpcode() == MOP_clinit_tail) ||
2574 (insn.GetNext() && isDef && insn.GetNext()->GetMachineOpcode() == MOP_clinit_tail)) {
2575 /*
2576 * When a cond branch reg is spilled, it cannot
2577 * restore the value after the branch since it can be the target from other br.
2578 * To do it properly, it will require creating a intermediate bb for the reload.
2579 * Use x16, it is taken out from available since it is used as a global in the system.
2580 */
2581 lr.SetAssignedRegNO(R16);
2582 } else {
2583 lr.SetAssignedRegNO(0);
2584 needSpillLr = SetRegForSpill(lr, insn, spillIdx, usedRegMask, isDef);
2585 AddCalleeUsed(lr.GetAssignedRegNO(), lr.GetRegType());
2586 }
2587 return needSpillLr;
2588 }
2589
2590 // find prev use/def after prev call
EncountPrevRef(const BB & pred,LiveRange & lr,bool isDef,std::vector<bool> & visitedMap)2591 bool GraphColorRegAllocator::EncountPrevRef(const BB &pred, LiveRange &lr, bool isDef, std::vector<bool> &visitedMap)
2592 {
2593 if (!visitedMap[pred.GetId()] && lr.FindInLuMap(pred.GetId()) != lr.EndOfLuMap()) {
2594 LiveUnit *lu = lr.GetLiveUnitFromLuMap(pred.GetId());
2595 if (lu->GetDefNum() || lu->GetUseNum() || lu->HasCall()) {
2596 MapleMap<uint32, uint32> refs = lr.GetRefs(pred.GetId());
2597 auto it = refs.rbegin();
2598 bool findPrevRef = (it->second & kIsCall) == 0;
2599 return findPrevRef;
2600 }
2601 if (lu->HasCall()) {
2602 return false;
2603 }
2604 }
2605 visitedMap[pred.GetId()] = true;
2606 bool found = true;
2607 for (auto predBB : pred.GetPreds()) {
2608 if (!visitedMap[predBB->GetId()]) {
2609 found &= EncountPrevRef(*predBB, lr, isDef, visitedMap);
2610 }
2611 }
2612 return found;
2613 }
2614
FoundPrevBeforeCall(Insn & insn,LiveRange & lr,bool isDef)2615 bool GraphColorRegAllocator::FoundPrevBeforeCall(Insn &insn, LiveRange &lr, bool isDef)
2616 {
2617 bool hasFind = true;
2618 std::vector<bool> visitedMap(bbVec.size() + 1, false);
2619 for (auto pred : insn.GetBB()->GetPreds()) {
2620 hasFind &= EncountPrevRef(*pred, lr, isDef, visitedMap);
2621 if (!hasFind) {
2622 return false;
2623 }
2624 }
2625 return insn.GetBB()->GetPreds().size() == 0 ? false : true;
2626 }
2627
2628 // find next def before next call ? and no next use
EncountNextRef(const BB & succ,LiveRange & lr,bool isDef,std::vector<bool> & visitedMap)2629 bool GraphColorRegAllocator::EncountNextRef(const BB &succ, LiveRange &lr, bool isDef, std::vector<bool> &visitedMap)
2630 {
2631 if (lr.FindInLuMap(succ.GetId()) != lr.EndOfLuMap()) {
2632 LiveUnit *lu = lr.GetLiveUnitFromLuMap(succ.GetId());
2633 bool findNextDef = false;
2634 if (lu->GetDefNum() || lu->HasCall()) {
2635 MapleMap<uint32, uint32> refs = lr.GetRefs(succ.GetId());
2636 for (auto it = refs.begin(); it != refs.end(); ++it) {
2637 if ((it->second & kIsDef) != 0) {
2638 findNextDef = true;
2639 break;
2640 }
2641 if ((it->second & kIsCall) != 0) {
2642 break;
2643 }
2644 if ((it->second & kIsUse) != 0) {
2645 continue;
2646 }
2647 }
2648 return findNextDef;
2649 }
2650 if (lu->HasCall()) {
2651 return false;
2652 }
2653 }
2654 visitedMap[succ.GetId()] = true;
2655 bool found = true;
2656 for (auto succBB : succ.GetSuccs()) {
2657 if (!visitedMap[succBB->GetId()]) {
2658 found &= EncountNextRef(*succBB, lr, isDef, visitedMap);
2659 if (!found) {
2660 return false;
2661 }
2662 }
2663 }
2664 return found;
2665 }
2666
FoundNextBeforeCall(Insn & insn,LiveRange & lr,bool isDef)2667 bool GraphColorRegAllocator::FoundNextBeforeCall(Insn &insn, LiveRange &lr, bool isDef)
2668 {
2669 bool haveFind = true;
2670 std::vector<bool> visitedMap(bbVec.size() + 1, false);
2671 for (auto succ : insn.GetBB()->GetSuccs()) {
2672 haveFind &= EncountNextRef(*succ, lr, isDef, visitedMap);
2673 if (!haveFind) {
2674 return false;
2675 }
2676 }
2677 return insn.GetBB()->GetSuccs().size() > 0;
2678 }
2679
HavePrevRefInCurBB(Insn & insn,LiveRange & lr,bool & contSearch) const2680 bool GraphColorRegAllocator::HavePrevRefInCurBB(Insn &insn, LiveRange &lr, bool &contSearch) const
2681 {
2682 LiveUnit *lu = lr.GetLiveUnitFromLuMap(insn.GetBB()->GetId());
2683 bool findPrevRef = false;
2684 if (lu->GetDefNum() || lu->GetUseNum() || lu->HasCall()) {
2685 MapleMap<uint32, uint32> refs = lr.GetRefs(insn.GetBB()->GetId());
2686 for (auto it = refs.rbegin(); it != refs.rend(); ++it) {
2687 if (it->first >= insn.GetId()) {
2688 continue;
2689 }
2690 if ((it->second & kIsCall) != 0) {
2691 contSearch = false;
2692 break;
2693 }
2694 if (((it->second & kIsUse) != 0) || ((it->second & kIsDef) != 0)) {
2695 findPrevRef = true;
2696 contSearch = false;
2697 break;
2698 }
2699 }
2700 }
2701 return findPrevRef;
2702 }
2703
HaveNextDefInCurBB(Insn & insn,LiveRange & lr,bool & contSearch) const2704 bool GraphColorRegAllocator::HaveNextDefInCurBB(Insn &insn, LiveRange &lr, bool &contSearch) const
2705 {
2706 LiveUnit *lu = lr.GetLiveUnitFromLuMap(insn.GetBB()->GetId());
2707 bool findNextDef = false;
2708 if (lu->GetDefNum() || lu->GetUseNum() || lu->HasCall()) {
2709 MapleMap<uint32, uint32> refs = lr.GetRefs(insn.GetBB()->GetId());
2710 for (auto it = refs.begin(); it != refs.end(); ++it) {
2711 if (it->first <= insn.GetId()) {
2712 continue;
2713 }
2714 if ((it->second & kIsCall) != 0) {
2715 contSearch = false;
2716 break;
2717 }
2718 if ((it->second & kIsDef) != 0) {
2719 findNextDef = true;
2720 contSearch = false;
2721 }
2722 }
2723 }
2724 return findNextDef;
2725 }
2726
NeedCallerSave(Insn & insn,LiveRange & lr,bool isDef)2727 bool GraphColorRegAllocator::NeedCallerSave(Insn &insn, LiveRange &lr, bool isDef)
2728 {
2729 if (doLRA) {
2730 return true;
2731 }
2732 if (lr.HasDefUse()) {
2733 return true;
2734 }
2735
2736 bool contSearch = true;
2737 bool needed = true;
2738 if (isDef) {
2739 needed = !HaveNextDefInCurBB(insn, lr, contSearch);
2740 } else {
2741 needed = !HavePrevRefInCurBB(insn, lr, contSearch);
2742 }
2743 if (!contSearch) {
2744 return needed;
2745 }
2746
2747 if (isDef) {
2748 needed = true;
2749 } else {
2750 needed = !FoundPrevBeforeCall(insn, lr, isDef);
2751 }
2752 return needed;
2753 }
2754
MarkUsedRegs(Operand & opnd,uint64 & usedRegMask)2755 void GraphColorRegAllocator::MarkUsedRegs(Operand &opnd, uint64 &usedRegMask)
2756 {
2757 auto ®Opnd = static_cast<RegOperand &>(opnd);
2758 uint32 pregInterval = (regOpnd.GetRegisterType() == kRegTyInt) ? 0 : (V0 - R30);
2759 uint32 vregNO = regOpnd.GetRegisterNumber();
2760 LiveRange *lr = GetLiveRange(vregNO);
2761 if (lr != nullptr) {
2762 if (lr->IsSpilled()) {
2763 lr->SetAssignedRegNO(0);
2764 }
2765 if (lr->GetAssignedRegNO() != 0) {
2766 usedRegMask |= (1ULL << (lr->GetAssignedRegNO() - pregInterval));
2767 }
2768 if (lr->GetSplitLr() && lr->GetSplitLr()->GetAssignedRegNO()) {
2769 usedRegMask |= (1ULL << (lr->GetSplitLr()->GetAssignedRegNO() - pregInterval));
2770 }
2771 }
2772 }
2773
DumpWorkCandAndOcc()2774 void CallerSavePre::DumpWorkCandAndOcc()
2775 {
2776 if (workCand->GetTheOperand()->IsRegister()) {
2777 LogInfo::MapleLogger() << "Cand R";
2778 LogInfo::MapleLogger() << static_cast<RegOperand *>(workCand->GetTheOperand())->GetRegisterNumber() << '\n';
2779 } else {
2780 LogInfo::MapleLogger() << "Cand Index" << workCand->GetIndex() << '\n';
2781 }
2782 for (CgOccur *occ : allOccs) {
2783 occ->Dump();
2784 LogInfo::MapleLogger() << '\n';
2785 }
2786 }
2787
ComputeAvail()2788 void CallerSavePre::ComputeAvail()
2789 {
2790 bool changed = true;
2791 while (changed) {
2792 changed = false;
2793 for (auto *phiOcc : phiOccs) {
2794 if (phiOcc->IsNotAvailable()) {
2795 continue;
2796 }
2797 size_t killedCnt = 0;
2798 for (auto *opndOcc : phiOcc->GetPhiOpnds()) {
2799 auto defOcc = opndOcc->GetDef();
2800 if (defOcc == nullptr) {
2801 continue;
2802 }
2803 // for not move load too far from use site, set not-fully-available-phi killing availibity of phiOpnd
2804 if ((defOcc->GetOccType() == kOccPhiocc && !static_cast<CgPhiOcc *>(defOcc)->IsFullyAvailable()) ||
2805 defOcc->GetOccType() == kOccStore) {
2806 ++killedCnt;
2807 opndOcc->SetHasRealUse(false);
2808 // opnd at back-edge is killed, set phi not avail
2809 if (dom->Dominate(*phiOcc->GetBB(), *opndOcc->GetBB())) {
2810 killedCnt = phiOcc->GetPhiOpnds().size();
2811 break;
2812 }
2813 if (opndOcc->GetBB()->IsSoloGoto() &&
2814 loopInfo.GetBBLoopParent(opndOcc->GetBB()->GetId()) != nullptr) {
2815 killedCnt = phiOcc->GetPhiOpnds().size();
2816 break;
2817 }
2818 continue;
2819 }
2820 }
2821 if (killedCnt == phiOcc->GetPhiOpnds().size()) {
2822 changed |= !phiOcc->IsNotAvailable();
2823 phiOcc->SetAvailability(kNotAvailable);
2824 } else if (killedCnt > 0) {
2825 changed |= !phiOcc->IsPartialAvailable();
2826 phiOcc->SetAvailability(kPartialAvailable);
2827 } else {
2828 } // fully available is default state
2829 }
2830 }
2831 }
2832
ComputeVarAndDfPhis()2833 void CallerSavePre::ComputeVarAndDfPhis()
2834 {
2835 dfPhiDfns.clear();
2836 PreWorkCand *workCand = GetWorkCand();
2837 for (auto *realOcc : workCand->GetRealOccs()) {
2838 BB *defBB = realOcc->GetBB();
2839 GetIterDomFrontier(defBB, &dfPhiDfns);
2840 }
2841 }
2842
ApplySSAPRE()2843 void CallerSavePre::ApplySSAPRE()
2844 {
2845 // #0 build worklist
2846 uint32 cnt = 0;
2847 constexpr uint32 preLimit = UINT32_MAX;
2848 while (!workList.empty()) {
2849 ++cnt;
2850 if (cnt == preLimit) {
2851 beyondLimit = true;
2852 }
2853 workCand = workList.front();
2854 workCand->SetIndex(static_cast<int32>(cnt));
2855 workLr = regAllocator->GetLiveRange(static_cast<RegOperand *>(workCand->GetTheOperand())->GetRegisterNumber());
2856 DEBUG_ASSERT(workLr != nullptr, "exepected non null lr");
2857 workList.pop_front();
2858 if (workCand->GetRealOccs().empty()) {
2859 continue;
2860 }
2861
2862 allOccs.clear();
2863 phiOccs.clear();
2864 // #1 Insert PHI; results in allOccs and phiOccs
2865 ComputeVarAndDfPhis();
2866 CreateSortedOccs();
2867 if (workCand->GetRealOccs().empty()) {
2868 continue;
2869 }
2870 // #2 Rename
2871 ComputeDS();
2872 ComputeAvail();
2873 DEBUG_ASSERT(workLr->GetProcessed() == false, "exepected unprocessed");
2874 workLr->SetProcessed();
2875 }
2876 }
2877
OptCallerSave()2878 void GraphColorRegAllocator::OptCallerSave()
2879 {
2880 CallerSavePre callerSavePre(this, *cgFunc, domInfo, loopInfo, *memPool, *memPool, kLoadPre, UINT32_MAX);
2881 callerSavePre.SetDump(needDump);
2882 callerSavePre.ApplySSAPRE();
2883 }
2884
LrGetBadReg(const LiveRange & lr) const2885 bool GraphColorRegAllocator::LrGetBadReg(const LiveRange &lr) const
2886 {
2887 if (lr.IsSpilled()) {
2888 return true;
2889 }
2890 if (lr.GetNumCall() != 0 && !AArch64Abi::IsCalleeSavedReg(static_cast<AArch64reg>(lr.GetAssignedRegNO()))) {
2891 return true;
2892 }
2893 return false;
2894 }
2895
MarkCalleeSaveRegs()2896 void GraphColorRegAllocator::MarkCalleeSaveRegs()
2897 {
2898 for (auto regNO : intCalleeUsed) {
2899 static_cast<AArch64CGFunc *>(cgFunc)->AddtoCalleeSaved(static_cast<AArch64reg>(regNO));
2900 }
2901 for (auto regNO : fpCalleeUsed) {
2902 static_cast<AArch64CGFunc *>(cgFunc)->AddtoCalleeSaved(static_cast<AArch64reg>(regNO));
2903 }
2904 }
2905 } /* namespace maplebe */
2906