• 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 "loop.h"
17 #include "aarch64_ra_opt.h"
18 
19 namespace maplebe {
20 using namespace std;
PropagateX0CanReplace(Operand * opnd,regno_t replaceReg) const21 bool RaX0Opt::PropagateX0CanReplace(Operand *opnd, regno_t replaceReg) const
22 {
23     if (opnd != nullptr) {
24         RegOperand *regopnd = static_cast<RegOperand *>(opnd);
25         regno_t regCandidate = regopnd->GetRegisterNumber();
26         if (regCandidate == replaceReg) {
27             return true;
28         }
29     }
30     return false;
31 }
32 
33 /*
34  * Replace replace_reg with rename_reg.
35  * return true if there is a redefinition that needs to terminate the propagation.
36  */
PropagateRenameReg(Insn * nInsn,const X0OptInfo & optVal) const37 bool RaX0Opt::PropagateRenameReg(Insn *nInsn, const X0OptInfo &optVal) const
38 {
39     uint32 renameReg = static_cast<RegOperand *>(optVal.GetRenameOpnd())->GetRegisterNumber();
40     const InsnDesc *md = nInsn->GetDesc();
41     CHECK_FATAL(nInsn->GetOperandSize() >= 1, "value overflow");
42     int32 lastOpndId = static_cast<int32>(nInsn->GetOperandSize() - 1);
43     for (int32_t i = lastOpndId; i >= 0; i--) {
44         Operand &opnd = nInsn->GetOperand(static_cast<uint32>(i));
45 
46         if (opnd.IsList()) {
47             /* call parameters */
48         } else if (opnd.IsMemoryAccessOperand()) {
49             MemOperand &memopnd = static_cast<MemOperand &>(opnd);
50             if (PropagateX0CanReplace(memopnd.GetBaseRegister(), optVal.GetReplaceReg())) {
51                 RegOperand *renameOpnd = static_cast<RegOperand *>(optVal.GetRenameOpnd());
52                 memopnd.SetBaseRegister(*renameOpnd);
53             }
54             if (PropagateX0CanReplace(memopnd.GetIndexRegister(), optVal.GetReplaceReg())) {
55                 RegOperand *renameOpnd = static_cast<RegOperand *>(optVal.GetRenameOpnd());
56                 memopnd.SetIndexRegister(*renameOpnd);
57             }
58         } else if (opnd.IsRegister()) {
59             bool isdef = (md->GetOpndDes(i))->IsRegDef();
60             RegOperand &regopnd = static_cast<RegOperand &>(opnd);
61             regno_t regCandidate = regopnd.GetRegisterNumber();
62             if (isdef) {
63                 /* Continue if both replace_reg & rename_reg are not redefined. */
64                 if (regCandidate == optVal.GetReplaceReg() || regCandidate == renameReg) {
65                     return true;
66                 }
67             } else {
68                 if (regCandidate == optVal.GetReplaceReg()) {
69                     nInsn->SetOperand(static_cast<uint32>(i), *optVal.GetRenameOpnd());
70                 }
71             }
72         }
73     }
74     return false; /* false == no redefinition */
75 }
76 
77 /* Propagate x0 from a call return value to a def of x0.
78  * This eliminates some local reloads under high register pressure, since
79  * the use has been replaced by x0.
80  */
PropagateX0DetectX0(const Insn * insn,X0OptInfo & optVal) const81 bool RaX0Opt::PropagateX0DetectX0(const Insn *insn, X0OptInfo &optVal) const
82 {
83     if (insn->GetMachineOpcode() != MOP_xmovrr && insn->GetMachineOpcode() != MOP_wmovrr) {
84         return false;
85     }
86     RegOperand &movSrc = static_cast<RegOperand &>(insn->GetOperand(1));
87     if (movSrc.GetRegisterNumber() != R0) {
88         return false;
89     }
90 
91     optVal.SetMovSrc(&movSrc);
92     return true;
93 }
94 
PropagateX0DetectRedefine(const InsnDesc * md,const Insn * ninsn,const X0OptInfo & optVal,uint32 index) const95 bool RaX0Opt::PropagateX0DetectRedefine(const InsnDesc *md, const Insn *ninsn, const X0OptInfo &optVal,
96                                         uint32 index) const
97 {
98     bool isdef = (md->GetOpndDes(static_cast<int>(index)))->IsRegDef();
99     if (isdef) {
100         RegOperand &opnd = static_cast<RegOperand &>(ninsn->GetOperand(index));
101         if (opnd.GetRegisterNumber() == optVal.GetReplaceReg()) {
102             return true;
103         }
104     }
105     return false;
106 }
107 
PropagateX0Optimize(const BB * bb,const Insn * insn,X0OptInfo & optVal)108 bool RaX0Opt::PropagateX0Optimize(const BB *bb, const Insn *insn, X0OptInfo &optVal)
109 {
110     bool redefined = false;
111     for (Insn *ninsn = insn->GetNext(); (ninsn != nullptr) && ninsn != bb->GetLastInsn()->GetNext();
112          ninsn = ninsn->GetNext()) {
113         if (!ninsn->IsMachineInstruction()) {
114             continue;
115         }
116 
117         if (ninsn->IsCall()) {
118             break;
119         }
120 
121         /* Will continue as long as the reg being replaced is not redefined.
122          * Does not need to check for x0 redefinition.  The mov instruction src
123          * being replaced already defines x0 and will terminate this loop.
124          */
125         const InsnDesc *md = ninsn->GetDesc();
126         for (uint32 i = 0; i < ninsn->GetDefRegs().size(); i++) {
127             redefined = PropagateX0DetectRedefine(md, ninsn, optVal, i);
128             if (redefined) {
129                 break;
130             }
131         }
132         if (redefined) {
133             break;
134         }
135 
136         /* Look for move where src is the register equivalent to x0. */
137         if (ninsn->GetMachineOpcode() != MOP_xmovrr && ninsn->GetMachineOpcode() != MOP_wmovrr) {
138             continue;
139         }
140 
141         Operand *src = &ninsn->GetOperand(1);
142         RegOperand *srcreg = static_cast<RegOperand *>(src);
143         if (srcreg->GetRegisterNumber() != optVal.GetReplaceReg()) {
144             continue;
145         }
146 
147         /* Setup for the next optmization pattern. */
148         Operand *dst = &ninsn->GetOperand(0);
149         RegOperand *dstreg = static_cast<RegOperand *>(dst);
150         if (dstreg->GetRegisterNumber() != R0) {
151             /* This is to set up for further propagation later. */
152             if (srcreg->GetRegisterNumber() == optVal.GetReplaceReg()) {
153                 if (optVal.GetRenameInsn() != nullptr) {
154                     redefined = true;
155                     break;
156                 } else {
157                     optVal.SetRenameInsn(ninsn);
158                     optVal.SetRenameOpnd(dst);
159                     optVal.SetRenameReg(dstreg->GetRegisterNumber());
160                 }
161             }
162             continue;
163         }
164 
165         if (redefined) {
166             break;
167         }
168 
169         /* x0 = x0 */
170         ninsn->SetOperand(1, *optVal.GetMovSrc());
171         break;
172     }
173 
174     return redefined;
175 }
176 
PropagateX0ForCurrBb(BB * bb,const X0OptInfo & optVal)177 bool RaX0Opt::PropagateX0ForCurrBb(BB *bb, const X0OptInfo &optVal)
178 {
179     bool redefined = false;
180     for (Insn *ninsn = optVal.GetRenameInsn()->GetNext(); (ninsn != nullptr) && ninsn != bb->GetLastInsn()->GetNext();
181          ninsn = ninsn->GetNext()) {
182         if (!ninsn->IsMachineInstruction()) {
183             continue;
184         }
185         redefined = PropagateRenameReg(ninsn, optVal);
186         if (redefined) {
187             break;
188         }
189     }
190     if (!redefined) {
191         auto it = bb->GetLiveOutRegNO().find(optVal.GetReplaceReg());
192         if (it != bb->GetLiveOutRegNO().end()) {
193             bb->EraseLiveOutRegNO(it);
194         }
195         uint32 renameReg = static_cast<RegOperand *>(optVal.GetRenameOpnd())->GetRegisterNumber();
196         bb->InsertLiveOutRegNO(renameReg);
197     }
198     return redefined;
199 }
200 
PropagateX0ForNextBb(BB * nextBb,const X0OptInfo & optVal)201 void RaX0Opt::PropagateX0ForNextBb(BB *nextBb, const X0OptInfo &optVal)
202 {
203     bool redefined = false;
204     for (Insn *ninsn = nextBb->GetFirstInsn(); ninsn != nextBb->GetLastInsn()->GetNext(); ninsn = ninsn->GetNext()) {
205         if (!ninsn->IsMachineInstruction()) {
206             continue;
207         }
208         redefined = PropagateRenameReg(ninsn, optVal);
209         if (redefined) {
210             break;
211         }
212     }
213     if (!redefined) {
214         auto it = nextBb->GetLiveOutRegNO().find(optVal.GetReplaceReg());
215         if (it != nextBb->GetLiveOutRegNO().end()) {
216             nextBb->EraseLiveOutRegNO(it);
217         }
218         uint32 renameReg = static_cast<RegOperand *>(optVal.GetRenameOpnd())->GetRegisterNumber();
219         nextBb->InsertLiveOutRegNO(renameReg);
220     }
221 }
222 
223 /*
224  * Perform optimization.
225  * First propagate x0 in a bb.
226  * Second propagation see comment in function.
227  */
PropagateX0()228 void RaX0Opt::PropagateX0()
229 {
230     FOR_ALL_BB(bb, cgFunc) {
231         X0OptInfo optVal;
232 
233         Insn *insn = bb->GetFirstInsn();
234         while ((insn != nullptr) && !insn->IsMachineInstruction()) {
235             insn = insn->GetNext();
236             continue;
237         }
238         if (insn == nullptr) {
239             continue;
240         }
241         if (!PropagateX0DetectX0(insn, optVal)) {
242             continue;
243         }
244 
245         /* At this point the 1st insn is a mov from x0. */
246         RegOperand &movDst = static_cast<RegOperand &>(insn->GetOperand(0));
247         optVal.SetReplaceReg(movDst.GetRegisterNumber());
248         optVal.ResetRenameInsn();
249         bool redefined = PropagateX0Optimize(bb, insn, optVal);
250         if (redefined || (optVal.GetRenameInsn() == nullptr)) {
251             continue;
252         }
253 
254         /* Next pattern to help LSRA.  Short cross bb live interval.
255          *  Straight line code.  Convert reg2 into bb local.
256          *  bb1
257          *     mov  reg2 <- x0          =>   mov  reg2 <- x0
258          *     mov  reg1 <- reg2             mov  reg1 <- reg2
259          *     call                          call
260          *  bb2  : livein< reg1 reg2 >
261          *     use          reg2             use          reg1
262          *     ....
263          *     reg2 not liveout
264          *
265          * Can allocate caller register for reg2.
266          *
267          * Further propagation of very short live interval cross bb reg
268          */
269         if (optVal.GetRenameReg() < kMaxRegNum) { /* dont propagate physical reg */
270             continue;
271         }
272         BB *nextBb = bb->GetNext();
273         if (nextBb == nullptr) {
274             break;
275         }
276         if (bb->GetSuccs().size() != 1 || nextBb->GetPreds().size() != 1) {
277             continue;
278         }
279         if (bb->GetSuccs().front() != nextBb || nextBb->GetPreds().front() != bb) {
280             continue;
281         }
282         if (bb->GetLiveOutRegNO().find(optVal.GetReplaceReg()) == bb->GetLiveOutRegNO().end() ||
283             bb->GetLiveOutRegNO().find(optVal.GetRenameReg()) == bb->GetLiveOutRegNO().end() ||
284             nextBb->GetLiveOutRegNO().find(optVal.GetReplaceReg()) != nextBb->GetLiveOutRegNO().end()) {
285             continue;
286         }
287         /* Replace replace_reg by rename_reg. */
288         redefined = PropagateX0ForCurrBb(bb, optVal);
289         if (redefined) {
290             continue;
291         }
292         PropagateX0ForNextBb(nextBb, optVal);
293     }
294 }
295 
PrintRenameInfo(regno_t regno) const296 void VregRename::PrintRenameInfo(regno_t regno) const
297 {
298     VregRenameInfo *info = (regno <= maxRegnoSeen) ? renameInfo[regno] : nullptr;
299     if (info == nullptr || (info->numDefs == 0 && info->numUses == 0)) {
300         return;
301     }
302     LogInfo::MapleLogger() << "reg: " << regno;
303     if (info->firstBBLevelSeen) {
304         LogInfo::MapleLogger() << " fromLevel " << info->firstBBLevelSeen->GetInternalFlag2();
305     }
306     if (info->lastBBLevelSeen) {
307         LogInfo::MapleLogger() << " toLevel " << info->lastBBLevelSeen->GetInternalFlag2();
308     }
309     if (info->numDefs) {
310         LogInfo::MapleLogger() << " defs " << info->numDefs;
311     }
312     if (info->numUses) {
313         LogInfo::MapleLogger() << " uses " << info->numUses;
314     }
315     if (info->numDefs) {
316         LogInfo::MapleLogger() << " innerDefs " << info->numInnerDefs;
317     }
318     if (info->numUses) {
319         LogInfo::MapleLogger() << " innerUses " << info->numInnerUses;
320     }
321     LogInfo::MapleLogger() << "\n";
322 }
323 
PrintAllRenameInfo() const324 void VregRename::PrintAllRenameInfo() const
325 {
326     for (uint32 regno = 0; regno < cgFunc->GetMaxRegNum(); ++regno) {
327         PrintRenameInfo(regno);
328     }
329 }
330 
IsProfitableToRename(const VregRenameInfo * info) const331 bool VregRename::IsProfitableToRename(const VregRenameInfo *info) const
332 {
333     if ((info->numInnerDefs == 0) && (info->numUses != info->numInnerUses)) {
334         return true;
335     }
336     return false;
337 }
338 
RenameProfitableVreg(RegOperand & ropnd,const LoopDesc & loop)339 void VregRename::RenameProfitableVreg(RegOperand &ropnd, const LoopDesc &loop)
340 {
341     regno_t vreg = ropnd.GetRegisterNumber();
342     VregRenameInfo *info = (vreg <= maxRegnoSeen) ? renameInfo[vreg] : nullptr;
343     if ((info == nullptr) || (!IsProfitableToRename(info))) {
344         return;
345     }
346 
347     uint32 size = (ropnd.GetSize() == k64BitSize) ? k8ByteSize : k4ByteSize;
348     regno_t newRegno = cgFunc->NewVReg(ropnd.GetRegisterType(), size);
349     RegOperand *renameVreg = &cgFunc->CreateVirtualRegisterOperand(newRegno);
350 
351     const BB &header = loop.GetHeader();
352     for (auto pred : header.GetPreds()) {
353         if (loop.IsBackEdge(*pred, loop.GetHeader())) {
354             continue;
355         }
356         MOperator mOp = (ropnd.GetRegisterType() == kRegTyInt) ? ((size == k8BitSize) ? MOP_xmovrr : MOP_wmovrr)
357                                                                : ((size == k8BitSize) ? MOP_xvmovd : MOP_xvmovs);
358         Insn &newInsn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, *renameVreg, ropnd);
359         Insn *last = pred->GetLastInsn();
360         if (last) {
361             if (last->IsBranch()) {
362                 last->GetBB()->InsertInsnBefore(*last, newInsn);
363             } else {
364                 last->GetBB()->InsertInsnAfter(*last, newInsn);
365             }
366         } else {
367             pred->AppendInsn(newInsn);
368         }
369     }
370 
371     for (auto bbId : loop.GetLoopBBs()) {
372         auto *bb = cgFunc->GetBBFromID(bbId);
373         FOR_BB_INSNS(insn, bb) {
374             if (insn->IsImmaterialInsn() || !insn->IsMachineInstruction()) {
375                 continue;
376             }
377             for (uint32 i = 0; i < insn->GetOperandSize(); ++i) {
378                 Operand *opnd = &insn->GetOperand(i);
379                 if (opnd->IsList()) {
380                     /* call parameters */
381                 } else if (opnd->IsMemoryAccessOperand()) {
382                     MemOperand *memopnd = static_cast<MemOperand *>(opnd);
383                     RegOperand *base = static_cast<RegOperand *>(memopnd->GetBaseRegister());
384                     MemOperand *newMemOpnd = nullptr;
385                     if (base != nullptr && base->IsVirtualRegister() && base->GetRegisterNumber() == vreg) {
386                         newMemOpnd = static_cast<MemOperand *>(memopnd->Clone(*cgFunc->GetMemoryPool()));
387                         newMemOpnd->SetBaseRegister(*renameVreg);
388                         insn->SetOperand(i, *newMemOpnd);
389                     }
390                     RegOperand *offset = static_cast<RegOperand *>(memopnd->GetIndexRegister());
391                     if (offset != nullptr && offset->IsVirtualRegister() && offset->GetRegisterNumber() == vreg) {
392                         if (newMemOpnd == nullptr) {
393                             newMemOpnd = static_cast<MemOperand *>(memopnd->Clone(*cgFunc->GetMemoryPool()));
394                         }
395                         newMemOpnd->SetIndexRegister(*renameVreg);
396                         insn->SetOperand(i, *newMemOpnd);
397                     }
398                 } else if (opnd->IsRegister() && static_cast<RegOperand *>(opnd)->IsVirtualRegister() &&
399                            static_cast<RegOperand *>(opnd)->GetRegisterNumber() == vreg) {
400                     insn->SetOperand(i, *renameVreg);
401                 }
402             }
403         }
404     }
405 }
406 
RenameFindLoopVregs(const LoopDesc & loop)407 void VregRename::RenameFindLoopVregs(const LoopDesc &loop)
408 {
409     for (auto bbId : loop.GetLoopBBs()) {
410         auto *bb = cgFunc->GetBBFromID(bbId);
411         FOR_BB_INSNS(insn, bb) {
412             if (insn->IsImmaterialInsn() || !insn->IsMachineInstruction()) {
413                 continue;
414             }
415             for (uint32 i = 0; i < insn->GetOperandSize(); ++i) {
416                 Operand *opnd = &insn->GetOperand(i);
417                 if (opnd->IsList()) {
418                     /* call parameters */
419                 } else if (opnd->IsMemoryAccessOperand()) {
420                     MemOperand *memopnd = static_cast<MemOperand *>(opnd);
421                     RegOperand *base = static_cast<RegOperand *>(memopnd->GetBaseRegister());
422                     if (base != nullptr && base->IsVirtualRegister()) {
423                         RenameProfitableVreg(*base, loop);
424                     }
425                     RegOperand *offset = static_cast<RegOperand *>(memopnd->GetIndexRegister());
426                     if (offset != nullptr && offset->IsVirtualRegister()) {
427                         RenameProfitableVreg(*offset, loop);
428                     }
429                 } else if (opnd->IsRegister() && static_cast<RegOperand *>(opnd)->IsVirtualRegister() &&
430                            static_cast<RegOperand *>(opnd)->GetRegisterNumber() != ccRegno) {
431                     RenameProfitableVreg(static_cast<RegOperand &>(*opnd), loop);
432                 }
433             }
434         }
435     }
436 }
437 
438 /* Only the bb level is important, not the bb itself.
439  * So if multiple bbs have the same level, only one bb represents the level
440  */
UpdateVregInfo(regno_t vreg,BB * bb,bool isInner,bool isDef)441 void VregRename::UpdateVregInfo(regno_t vreg, BB *bb, bool isInner, bool isDef)
442 {
443     VregRenameInfo *info = renameInfo[vreg];
444     if (info == nullptr) {
445         info = memPool->New<VregRenameInfo>();
446         renameInfo[vreg] = info;
447         if (vreg > maxRegnoSeen) {
448             maxRegnoSeen = vreg;
449         }
450     }
451     if (isDef) {
452         info->numDefs++;
453         if (isInner) {
454             info->numInnerDefs++;
455         }
456     } else {
457         info->numUses++;
458         if (isInner) {
459             info->numInnerUses++;
460         }
461     }
462     if (info->firstBBLevelSeen) {
463         if (info->firstBBLevelSeen->GetInternalFlag2() > bb->GetInternalFlag2()) {
464             info->firstBBLevelSeen = bb;
465         }
466     } else {
467         info->firstBBLevelSeen = bb;
468     }
469     if (info->lastBBLevelSeen) {
470         if (info->lastBBLevelSeen->GetInternalFlag2() < bb->GetInternalFlag2()) {
471             info->lastBBLevelSeen = bb;
472         }
473     } else {
474         info->lastBBLevelSeen = bb;
475     }
476 }
477 
RenameGetFuncVregInfo()478 void VregRename::RenameGetFuncVregInfo()
479 {
480     FOR_ALL_BB(bb, cgFunc) {
481         auto *loop = loopInfo.GetBBLoopParent(bb->GetId());
482         bool isInner = loop ? loop->GetChildLoops().empty() : false;
483         FOR_BB_INSNS(insn, bb) {
484             if (insn->IsImmaterialInsn() || !insn->IsMachineInstruction()) {
485                 continue;
486             }
487             const InsnDesc *md = insn->GetDesc();
488             for (uint32 i = 0; i < insn->GetOperandSize(); ++i) {
489                 Operand *opnd = &insn->GetOperand(i);
490                 if (opnd->IsList()) {
491                     /* call parameters */
492                 } else if (opnd->IsMemoryAccessOperand()) {
493                     MemOperand *memopnd = static_cast<MemOperand *>(opnd);
494                     RegOperand *base = static_cast<RegOperand *>(memopnd->GetBaseRegister());
495                     if (base != nullptr && base->IsVirtualRegister()) {
496                         regno_t vreg = base->GetRegisterNumber();
497                         UpdateVregInfo(vreg, bb, isInner, false);
498                     }
499                     RegOperand *offset = static_cast<RegOperand *>(memopnd->GetIndexRegister());
500                     if (offset != nullptr && offset->IsVirtualRegister()) {
501                         regno_t vreg = offset->GetRegisterNumber();
502                         UpdateVregInfo(vreg, bb, isInner, false);
503                     }
504                 } else if (opnd->IsRegister() && static_cast<RegOperand *>(opnd)->IsVirtualRegister() &&
505                            static_cast<RegOperand *>(opnd)->GetRegisterNumber() != ccRegno) {
506                     bool isdef = (md->opndMD[i])->IsRegDef();
507                     regno_t vreg = static_cast<RegOperand *>(opnd)->GetRegisterNumber();
508                     UpdateVregInfo(vreg, bb, isInner, isdef);
509                 }
510             }
511         }
512     }
513 }
514 
RenameFindVregsToRename(const LoopDesc & loop)515 void VregRename::RenameFindVregsToRename(const LoopDesc &loop)
516 {
517     if (loop.GetChildLoops().empty()) {
518         RenameFindLoopVregs(loop);
519         return;
520     }
521     for (const auto inner : loop.GetChildLoops()) {
522         RenameFindVregsToRename(*inner);
523     }
524 }
525 
VregLongLiveRename()526 void VregRename::VregLongLiveRename()
527 {
528     if (loopInfo.GetLoops().empty()) {
529         return;
530     }
531     RenameGetFuncVregInfo();
532     for (const auto *loop : loopInfo.GetLoops()) {
533         RenameFindVregsToRename(*loop);
534     }
535 }
536 
Run()537 void AArch64RaOpt::Run()
538 {
539     RaX0Opt x0Opt(cgFunc);
540     x0Opt.PropagateX0();
541 
542     if (cgFunc->GetMirModule().GetSrcLang() == kSrcLangC && CGOptions::DoVregRename()) {
543         /* loop detection considers EH bb.  That is not handled.  So C only for now. */
544         auto *loop = memPool->New<LoopAnalysis>(*cgFunc, *memPool, domInfo);
545         loop->Analysis();
546         VregRename rename(cgFunc, memPool, *loop);
547         Bfs localBfs(*cgFunc, *memPool);
548         rename.bfs = &localBfs;
549         rename.bfs->ComputeBlockOrder();
550         rename.VregLongLiveRename();
551     }
552 }
553 } /* namespace maplebe */
554