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