• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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 &regOpnd) 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 &regOpnd, 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 &regOpnd = 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 &regOpnd = 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 &regOpnd = 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 &regOpnd = 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 &regOpnd = 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 &regOpnd = 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 &regMapPair : 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 &regOpnd = 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