• 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 "reg_alloc_basic.h"
17 #include "cg.h"
18 
19 namespace maplebe {
20 /*
21  *  NB. As an optimization we can use X8 as a scratch (temporary)
22  *     register if the return value is not returned through memory.
23  */
HandleRegOpnd(Operand & opnd)24 Operand *DefaultO0RegAllocator::HandleRegOpnd(Operand &opnd)
25 {
26     DEBUG_ASSERT(opnd.IsRegister(), "Operand should be register operand");
27     auto &regOpnd = static_cast<RegOperand &>(opnd);
28     if (regOpnd.IsOfCC()) {
29         return &opnd;
30     }
31     if (!regInfo->IsVirtualRegister(regOpnd)) {
32         availRegSet[regOpnd.GetRegisterNumber()] = false;
33         (void)liveReg.insert(regOpnd.GetRegisterNumber());
34         return &regOpnd;
35     }
36     auto regMapIt = regMap.find(regOpnd.GetRegisterNumber());
37     if (regMapIt != regMap.end()) { /* already allocated this register */
38         DEBUG_ASSERT(regMapIt->second < regInfo->GetAllRegNum(), "must be a physical register");
39         regno_t newRegNO = regMapIt->second;
40         availRegSet[newRegNO] = false; /* make sure the real register can not be allocated and live */
41         (void)liveReg.insert(newRegNO);
42         (void)allocatedSet.insert(&opnd);
43         return &cgFunc->GetOpndBuilder()->CreatePReg(newRegNO, regOpnd.GetSize(), regOpnd.GetRegisterType());
44     }
45     if (AllocatePhysicalRegister(regOpnd)) {
46         (void)allocatedSet.insert(&opnd);
47         auto regMapItSecond = regMap.find(regOpnd.GetRegisterNumber());
48         DEBUG_ASSERT(regMapItSecond != regMap.end(), " ERROR: can not find register number in regmap ");
49         return &cgFunc->GetOpndBuilder()->CreatePReg(regMapItSecond->second, regOpnd.GetSize(),
50                                                      regOpnd.GetRegisterType());
51     }
52 
53     /* use 0 register as spill register */
54     regno_t regNO = 0;
55     return &cgFunc->GetOpndBuilder()->CreatePReg(regNO, regOpnd.GetSize(), regOpnd.GetRegisterType());
56 }
57 
HandleMemOpnd(Operand & opnd)58 Operand *DefaultO0RegAllocator::HandleMemOpnd(Operand &opnd)
59 {
60     DEBUG_ASSERT(opnd.IsMemoryAccessOperand(), "Operand should be memory access operand");
61     auto *memOpnd = static_cast<MemOperand *>(&opnd);
62     Operand *res = nullptr;
63     if (memOpnd->GetBaseRegister() != nullptr) {
64         res = AllocSrcOpnd(*memOpnd->GetBaseRegister());
65         memOpnd->SetBaseRegister(static_cast<RegOperand &>(*res));
66     }
67     if (memOpnd->GetIndexRegister() != nullptr) {
68         res = AllocSrcOpnd(*memOpnd->GetIndexRegister());
69         memOpnd->SetIndexRegister(static_cast<RegOperand &>(*res));
70     }
71     (void)allocatedSet.insert(&opnd);
72     return memOpnd;
73 }
74 
AllocSrcOpnd(Operand & opnd)75 Operand *DefaultO0RegAllocator::AllocSrcOpnd(Operand &opnd)
76 {
77     if (opnd.IsRegister()) {
78         if (regInfo->IsUnconcernedReg(static_cast<RegOperand &>(opnd))) {
79             return &opnd;
80         }
81         return HandleRegOpnd(opnd);
82     } else if (opnd.IsMemoryAccessOperand()) {
83         return HandleMemOpnd(opnd);
84     }
85     DEBUG_ASSERT(false, "NYI");
86     return nullptr;
87 }
88 
AllocDestOpnd(Operand & opnd,const Insn & insn)89 Operand *DefaultO0RegAllocator::AllocDestOpnd(Operand &opnd, const Insn &insn)
90 {
91     if (!opnd.IsRegister()) {
92         DEBUG_ASSERT(false, "result operand must be of type register");
93         return nullptr;
94     }
95     auto &regOpnd = static_cast<RegOperand &>(opnd);
96     if (regInfo->IsUnconcernedReg(static_cast<RegOperand &>(opnd))) {
97         return &opnd;
98     }
99     if (!regInfo->IsVirtualRegister(regOpnd)) {
100         auto reg = regOpnd.GetRegisterNumber();
101         availRegSet[reg] = true;
102         uint32 id = GetRegLivenessId(regOpnd.GetRegisterNumber());
103         if (id != 0 && id <= insn.GetId()) {
104             ReleaseReg(reg);
105         }
106         return &opnd;
107     }
108 
109     auto regMapIt = regMap.find(regOpnd.GetRegisterNumber());
110     if (regMapIt != regMap.end()) {
111         regno_t reg = regMapIt->second;
112         if (!insn.IsCondDef()) {
113             uint32 id = GetRegLivenessId(regOpnd.GetRegisterNumber());
114             if (id != 0 && id <= insn.GetId()) {
115                 ReleaseReg(reg);
116             }
117         }
118     } else {
119         /* AllocatePhysicalRegister insert a mapping from vreg no to phy reg no into regMap */
120         if (AllocatePhysicalRegister(regOpnd)) {
121             regMapIt = regMap.find(regOpnd.GetRegisterNumber());
122             if (!insn.IsCondDef()) {
123                 uint32 id = GetRegLivenessId(regOpnd.GetRegisterNumber());
124                 if (id && (id <= insn.GetId())) {
125                     ReleaseReg(regMapIt->second);
126                 }
127             }
128         } else {
129             /* For register spill. use 0 register as spill register */
130             regno_t regNO = 0;
131             return &cgFunc->GetOpndBuilder()->CreatePReg(regNO, regOpnd.GetSize(), regOpnd.GetRegisterType());
132         }
133     }
134     (void)allocatedSet.insert(&opnd);
135     return &cgFunc->GetOpndBuilder()->CreatePReg(regMapIt->second, regOpnd.GetSize(), regOpnd.GetRegisterType());
136 }
137 
GetPhysicalRegisterBank(RegType regTy,regno_t & begin,regno_t & end) const138 void DefaultO0RegAllocator::GetPhysicalRegisterBank(RegType regTy, regno_t &begin, regno_t &end) const
139 {
140     switch (regTy) {
141         case kRegTyVary:
142         case kRegTyCc:
143             break;
144         case kRegTyInt:
145             begin = *regInfo->GetIntRegs().begin();
146             end = *regInfo->GetIntRegs().rbegin();
147             break;
148         case kRegTyFloat:
149             begin = *regInfo->GetFpRegs().begin();
150             end = *regInfo->GetFpRegs().rbegin();
151             break;
152         default:
153             DEBUG_ASSERT(false, "NYI");
154             break;
155     }
156 }
157 
InitAvailReg()158 void DefaultO0RegAllocator::InitAvailReg()
159 {
160     for (auto it : regInfo->GetAllRegs()) {
161         availRegSet[it] = true;
162     }
163 }
164 
ReleaseReg(const RegOperand & regOpnd)165 void DefaultO0RegAllocator::ReleaseReg(const RegOperand &regOpnd)
166 {
167     ReleaseReg(regMap[regOpnd.GetRegisterNumber()]);
168 }
169 
ReleaseReg(regno_t reg)170 void DefaultO0RegAllocator::ReleaseReg(regno_t reg)
171 {
172     DEBUG_ASSERT(reg < regInfo->GetAllRegNum(), "can't release virtual register");
173     liveReg.erase(reg);
174     /* Special registers can not be allocated */
175     if (!regInfo->IsUnconcernedReg(reg)) {
176         availRegSet[reg] = true;
177     }
178 }
179 
180 /* trying to allocate a physical register to opnd. return true if success */
AllocatePhysicalRegister(const RegOperand & opnd)181 bool DefaultO0RegAllocator::AllocatePhysicalRegister(const RegOperand &opnd)
182 {
183     RegType regType = opnd.GetRegisterType();
184     regno_t regNo = opnd.GetRegisterNumber();
185     regno_t regStart = 0;
186     regno_t regEnd = 0;
187     GetPhysicalRegisterBank(regType, regStart, regEnd);
188 
189     const auto opndRegIt = regLiveness.find(regNo);
190     for (regno_t reg = regStart; reg <= regEnd; ++reg) {
191         if (!availRegSet[reg]) {
192             continue;
193         }
194 
195         if (opndRegIt != regLiveness.end()) {
196             const auto regIt = regLiveness.find(reg);
197             DEBUG_ASSERT(opndRegIt->second.size() == 1, "NIY, opnd reg liveness range must be 1.");
198             if (regIt != regLiveness.end() && CheckRangesOverlap(opndRegIt->second.front(), regIt->second)) {
199                 continue;
200             }
201         }
202 
203         regMap[opnd.GetRegisterNumber()] = reg;
204         availRegSet[reg] = false;
205         (void)liveReg.insert(reg); /* this register is live now */
206         return true;
207     }
208     return false;
209 }
210 
211 /* If opnd is a callee saved register, save it in the prolog and restore it in the epilog */
SaveCalleeSavedReg(const RegOperand & regOpnd)212 void DefaultO0RegAllocator::SaveCalleeSavedReg(const RegOperand &regOpnd)
213 {
214     regno_t regNO = regOpnd.GetRegisterNumber();
215     auto phyReg = regInfo->IsVirtualRegister(regOpnd) ? regMap[regNO] : regNO;
216     /* when yieldpoint is enabled, skip the reserved register for yieldpoint. */
217     if (cgFunc->GetCG()->GenYieldPoint() && (regInfo->IsYieldPointReg(phyReg))) {
218         return;
219     }
220 
221     if (regInfo->IsCalleeSavedReg(phyReg)) {
222         calleeSaveUsed.insert(phyReg);
223     }
224 }
225 
GetRegLivenessId(regno_t regNo)226 uint32 DefaultO0RegAllocator::GetRegLivenessId(regno_t regNo)
227 {
228     auto regIt = regLiveness.find(regNo);
229     return ((regIt == regLiveness.end()) ? 0 : regIt->second.back().second);
230 }
231 
CheckRangesOverlap(const std::pair<uint32,uint32> & range1,const MapleVector<std::pair<uint32,uint32>> & ranges2) const232 bool DefaultO0RegAllocator::CheckRangesOverlap(const std::pair<uint32, uint32> &range1,
233                                                const MapleVector<std::pair<uint32, uint32>> &ranges2) const
234 {
235     /*
236      * Check whether range1 and ranges2 overlap.
237      * The ranges2 is sorted.
238      */
239     auto pos = std::lower_bound(
240         ranges2.begin(), ranges2.end(), range1,
241         [](const std::pair<uint32, uint32> &r2, const std::pair<uint32, uint32> &r1) { return r1.first >= r2.second; });
242     if (pos == ranges2.end()) {
243         return false;
244     }
245     auto &range2 = *pos;
246     if (std::max(range1.first, range2.first) <= std::min(range1.second, range2.second)) {
247         return true;
248     }
249     return false;
250 }
251 
SetupRegLiveness(BB * bb)252 void DefaultO0RegAllocator::SetupRegLiveness(BB *bb)
253 {
254     regLiveness.clear();
255 
256     uint32 id = 1;
257     FOR_BB_INSNS_REV(insn, bb) {
258         if (!insn->IsMachineInstruction()) {
259             continue;
260         }
261         insn->SetId(id);
262         id++;
263         uint32 opndNum = insn->GetOperandSize();
264         const InsnDesc *curMd = insn->GetDesc();
265         for (uint32 i = 0; i < opndNum; i++) {
266             Operand &opnd = insn->GetOperand(i);
267             const OpndDesc *opndDesc = curMd->GetOpndDes(i);
268             if (opnd.IsRegister()) {
269                 /* def-use is processed by use */
270                 SetupRegLiveness(static_cast<RegOperand &>(opnd), insn->GetId(), !opndDesc->IsUse());
271             } else if (opnd.IsMemoryAccessOperand()) {
272                 SetupRegLiveness(static_cast<MemOperand &>(opnd), insn->GetId());
273             } else if (opnd.IsList()) {
274                 SetupRegLiveness(static_cast<ListOperand &>(opnd), insn->GetId(), opndDesc->IsDef());
275             }
276         }
277     }
278 
279     /* clear the last empty range */
280     for (auto &regLivenessIt : regLiveness) {
281         auto &regLivenessRanges = regLivenessIt.second;
282         if (regLivenessRanges.back().first == 0) {
283             regLivenessRanges.pop_back();
284         }
285     }
286 }
287 
SetupRegLiveness(MemOperand & opnd,uint32 insnId)288 void DefaultO0RegAllocator::SetupRegLiveness(MemOperand &opnd, uint32 insnId)
289 {
290     /* base regOpnd is use in O0 */
291     if (opnd.GetBaseRegister()) {
292         SetupRegLiveness(*opnd.GetBaseRegister(), insnId, false);
293     }
294     /* index regOpnd must be use */
295     if (opnd.GetIndexRegister()) {
296         SetupRegLiveness(*opnd.GetIndexRegister(), insnId, false);
297     }
298 }
299 
SetupRegLiveness(ListOperand & opnd,uint32 insnId,bool isDef)300 void DefaultO0RegAllocator::SetupRegLiveness(ListOperand &opnd, uint32 insnId, bool isDef)
301 {
302     for (RegOperand *regOpnd : opnd.GetOperands()) {
303         SetupRegLiveness(*regOpnd, insnId, isDef);
304     }
305 }
306 
SetupRegLiveness(RegOperand & opnd,uint32 insnId,bool isDef)307 void DefaultO0RegAllocator::SetupRegLiveness(RegOperand &opnd, uint32 insnId, bool isDef)
308 {
309     MapleVector<std::pair<uint32, uint32>> ranges(alloc.Adapter());
310     auto regLivenessIt = regLiveness.emplace(opnd.GetRegisterNumber(), ranges).first;
311     auto &regLivenessRanges = regLivenessIt->second;
312     if (regLivenessRanges.empty()) {
313         regLivenessRanges.push_back(std::make_pair(0, 0));
314     }
315     auto &regLivenessLastRange = regLivenessRanges.back();
316     if (regLivenessLastRange.first == 0) {
317         regLivenessLastRange.first = insnId;
318     }
319     regLivenessLastRange.second = insnId;
320 
321     /* create new range, only phyReg need to be segmented */
322     if (isDef && regInfo->IsAvailableReg(opnd.GetRegisterNumber())) {
323         regLivenessRanges.push_back(std::make_pair(0, 0));
324     }
325 }
326 
AllocHandleDestList(Insn & insn,Operand & opnd,uint32 idx)327 void DefaultO0RegAllocator::AllocHandleDestList(Insn &insn, Operand &opnd, uint32 idx)
328 {
329     if (!opnd.IsList()) {
330         return;
331     }
332     auto *listOpnds = &static_cast<ListOperand &>(opnd);
333     auto *listOpndsNew = &cgFunc->GetOpndBuilder()->CreateList();
334     for (auto *dstOpnd : listOpnds->GetOperands()) {
335         if (allocatedSet.find(dstOpnd) != allocatedSet.end()) {
336             auto &regOpnd = static_cast<RegOperand &>(*dstOpnd);
337             SaveCalleeSavedReg(regOpnd);
338             listOpndsNew->PushOpnd(cgFunc->GetOpndBuilder()->CreatePReg(regMap[regOpnd.GetRegisterNumber()],
339                                                                         regOpnd.GetSize(), regOpnd.GetRegisterType()));
340             continue; /* already allocated */
341         }
342         RegOperand *regOpnd = static_cast<RegOperand *>(AllocDestOpnd(*dstOpnd, insn));
343         DEBUG_ASSERT(regOpnd != nullptr, "null ptr check");
344         auto physRegno = regOpnd->GetRegisterNumber();
345         availRegSet[physRegno] = false;
346         (void)liveReg.insert(physRegno);
347         listOpndsNew->PushOpnd(
348             cgFunc->GetOpndBuilder()->CreatePReg(physRegno, regOpnd->GetSize(), regOpnd->GetRegisterType()));
349     }
350     insn.SetOperand(idx, *listOpndsNew);
351     for (auto *dstOpnd : listOpndsNew->GetOperands()) {
352         uint32 id = GetRegLivenessId(dstOpnd->GetRegisterNumber());
353         if (id != 0 && id <= insn.GetId()) {
354             ReleaseReg(*dstOpnd);
355         }
356     }
357 }
358 
AllocHandleDest(Insn & insn,Operand & opnd,uint32 idx)359 void DefaultO0RegAllocator::AllocHandleDest(Insn &insn, Operand &opnd, uint32 idx)
360 {
361     if (allocatedSet.find(&opnd) != allocatedSet.end()) {
362         /* free the live range of this register */
363         auto &regOpnd = static_cast<RegOperand &>(opnd);
364         SaveCalleeSavedReg(regOpnd);
365         if (insn.IsAtomicStore() || insn.IsSpecialIntrinsic()) {
366             /* remember the physical machine register assigned */
367             regno_t regNO = regOpnd.GetRegisterNumber();
368             rememberRegs.push_back(regInfo->IsVirtualRegister(regOpnd) ? regMap[regNO] : regNO);
369         } else if (!insn.IsCondDef()) {
370             uint32 id = GetRegLivenessId(regOpnd.GetRegisterNumber());
371             if (id != 0 && id <= insn.GetId()) {
372                 ReleaseReg(regOpnd);
373             }
374         }
375         insn.SetOperand(idx, cgFunc->GetOpndBuilder()->CreatePReg(regMap[regOpnd.GetRegisterNumber()],
376                                                                   regOpnd.GetSize(), regOpnd.GetRegisterType()));
377         return; /* already allocated */
378     }
379 
380     if (opnd.IsRegister()) {
381         insn.SetOperand(idx, *AllocDestOpnd(opnd, insn));
382         SaveCalleeSavedReg(static_cast<RegOperand &>(opnd));
383     }
384 }
385 
AllocHandleSrcList(Insn & insn,Operand & opnd,uint32 idx)386 void DefaultO0RegAllocator::AllocHandleSrcList(Insn &insn, Operand &opnd, uint32 idx)
387 {
388     if (!opnd.IsList()) {
389         return;
390     }
391     auto *listOpnds = &static_cast<ListOperand &>(opnd);
392     auto *listOpndsNew = &cgFunc->GetOpndBuilder()->CreateList();
393     for (auto *srcOpnd : listOpnds->GetOperands()) {
394         if (allocatedSet.find(srcOpnd) != allocatedSet.end()) {
395             auto *regOpnd = static_cast<RegOperand *>(srcOpnd);
396             regno_t reg = regMap[regOpnd->GetRegisterNumber()];
397             availRegSet[reg] = false;
398             (void)liveReg.insert(reg); /* this register is live now */
399             listOpndsNew->PushOpnd(
400                 cgFunc->GetOpndBuilder()->CreatePReg(reg, regOpnd->GetSize(), regOpnd->GetRegisterType()));
401             continue; /* already allocated */
402         }
403         RegOperand *regOpnd = static_cast<RegOperand *>(AllocSrcOpnd(*srcOpnd));
404         CHECK_NULL_FATAL(regOpnd);
405         listOpndsNew->PushOpnd(*regOpnd);
406     }
407     insn.SetOperand(idx, *listOpndsNew);
408 }
409 
AllocHandleSrc(Insn & insn,Operand & opnd,uint32 idx)410 void DefaultO0RegAllocator::AllocHandleSrc(Insn &insn, Operand &opnd, uint32 idx)
411 {
412     if (allocatedSet.find(&opnd) != allocatedSet.end() && opnd.IsRegister()) {
413         auto *regOpnd = &static_cast<RegOperand &>(opnd);
414         regno_t reg = regMap[regOpnd->GetRegisterNumber()];
415         availRegSet[reg] = false;
416         (void)liveReg.insert(reg); /* this register is live now */
417         insn.SetOperand(idx, cgFunc->GetOpndBuilder()->CreatePReg(reg, regOpnd->GetSize(), regOpnd->GetRegisterType()));
418     } else {
419         Operand *srcOpnd = AllocSrcOpnd(opnd);
420         CHECK_NULL_FATAL(srcOpnd);
421         insn.SetOperand(idx, *srcOpnd);
422     }
423 }
424 
AllocateRegisters()425 bool DefaultO0RegAllocator::AllocateRegisters()
426 {
427     InitAvailReg();
428     cgFunc->SetIsAfterRegAlloc();
429 
430     FOR_ALL_BB_REV(bb, cgFunc) {
431         if (bb->IsEmpty()) {
432             continue;
433         }
434 
435         SetupRegLiveness(bb);
436         FOR_BB_INSNS_REV(insn, bb) {
437             if (!insn->IsMachineInstruction()) {
438                 continue;
439             }
440 
441             /* handle inline assembly first due to specific def&use order */
442             if (insn->IsAsmInsn()) {
443                 AllocHandleDestList(*insn, insn->GetOperand(kAsmClobberListOpnd), kAsmClobberListOpnd);
444                 AllocHandleDestList(*insn, insn->GetOperand(kAsmOutputListOpnd), kAsmOutputListOpnd);
445                 AllocHandleSrcList(*insn, insn->GetOperand(kAsmInputListOpnd), kAsmInputListOpnd);
446             }
447 
448             const InsnDesc *curMd = insn->GetDesc();
449 
450             for (uint32 i = 0; i < insn->GetOperandSize() && !insn->IsAsmInsn(); ++i) { /* the dest registers */
451                 Operand &opnd = insn->GetOperand(i);
452                 if (!(opnd.IsRegister() && curMd->GetOpndDes(i)->IsDef())) {
453                     continue;
454                 }
455                 if (opnd.IsList()) {
456                     AllocHandleDestList(*insn, opnd, i);
457                 } else {
458                     AllocHandleDest(*insn, opnd, i);
459                 }
460             }
461 
462             for (uint32 i = 0; i < insn->GetOperandSize() && !insn->IsAsmInsn(); ++i) { /* the src registers */
463                 Operand &opnd = insn->GetOperand(i);
464                 if (!((opnd.IsRegister() && curMd->GetOpndDes(i)->IsUse()) || opnd.IsMemoryAccessOperand())) {
465                     continue;
466                 }
467                 if (opnd.IsList()) {
468                     AllocHandleSrcList(*insn, opnd, i);
469                 } else {
470                     AllocHandleSrc(*insn, opnd, i);
471                 }
472             }
473 
474             /* hack. a better way to handle intrinsics? */
475             for (auto rememberReg : rememberRegs) {
476                 DEBUG_ASSERT(rememberReg != regInfo->GetInvalidReg(), "not a valid register");
477                 ReleaseReg(rememberReg);
478             }
479             rememberRegs.clear();
480         }
481     }
482     /*
483      * we store both FP/LR if using FP or if not using FP, but func has a call
484      * Using FP, record it for saving
485      * notice the order here : the first callee saved reg is expected to be RFP.
486      */
487     regInfo->Fini();
488     regInfo->SaveCalleeSavedReg(calleeSaveUsed);
489     return true;
490 }
491 } /* namespace maplebe */
492