• 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_strldr.h"
17 #include "aarch64_reaching.h"
18 #include "aarch64_cgfunc.h"
19 #include "common_utils.h"
20 
21 namespace maplebe {
22 using namespace maple;
23 
SelectMovMop(bool isFloatOrSIMD,bool is64Bit)24 static MOperator SelectMovMop(bool isFloatOrSIMD, bool is64Bit)
25 {
26     return isFloatOrSIMD ? (is64Bit ? MOP_xvmovd : MOP_xvmovs) : (is64Bit ? MOP_xmovrr : MOP_wmovrr);
27 }
28 
Run()29 void AArch64StoreLoadOpt::Run()
30 {
31     DoStoreLoadOpt();
32 }
33 
34 /*
35  * Transfer: store x100, [MEM]
36  *           ... // May exist branches.
37  *           load  x200, [MEM]
38  *       ==>
39  *        OPT_VERSION_STR_LIVE:
40  *           store x100, [MEM]
41  *           ... // May exist branches. if x100 not dead here.
42  *           mov   x200, x100
43  *       OPT_VERSION_STR_DIE:
44  *           store x100, [MEM]
45  *           mov x9000(new reg), x100
46  *           ... // May exist branches. if x100 dead here.
47  *           mov   x200, x9000
48  *  Params:
49  *    strInsn: indicate store insn.
50  *    strSrcIdx: index of source register operand of store insn. (x100 in this example)
51  *    memSeq: represent first memOpreand or second memOperand
52  *    memUseInsnSet: insns using memOperand
53  */
DoLoadToMoveTransfer(Insn & strInsn,short strSrcIdx,short memSeq,const InsnSet & memUseInsnSet)54 void AArch64StoreLoadOpt::DoLoadToMoveTransfer(Insn &strInsn, short strSrcIdx, short memSeq,
55                                                const InsnSet &memUseInsnSet)
56 {
57     /* stp instruction need two registers, str only need one register */
58     DEBUG_ASSERT(strSrcIdx < kDivide2, "CG internal error.");
59     /* Find x100's definition insn. */
60     InsnSet regDefInsnSet = cgFunc.GetRD()->FindDefForRegOpnd(strInsn, strSrcIdx);
61     DEBUG_ASSERT(!regDefInsnSet.empty(), "RegOperand is used before defined");
62     if (regDefInsnSet.size() != 1) {
63         return;
64     }
65     std::map<Insn *, bool> InsnState;
66     for (auto *ldrInsn : memUseInsnSet) {
67         InsnState[ldrInsn] = true;
68     }
69     for (auto *ldrInsn : memUseInsnSet) {
70         if (!ldrInsn->IsLoad() || (ldrInsn->GetDefRegs().size() > 1) || ldrInsn->GetBB()->IsCleanup()) {
71             continue;
72         }
73 
74         if (HasMemBarrier(*ldrInsn, strInsn)) {
75             continue;
76         }
77 
78         /* ldr x200, [mem], mem index is 1, x200 index is 0 */
79         InsnSet memDefInsnSet = cgFunc.GetRD()->FindDefForMemOpnd(*ldrInsn, kInsnSecondOpnd);
80         DEBUG_ASSERT(!memDefInsnSet.empty(), "load insn should have definitions.");
81         /* If load has multiple definition, continue. */
82         if (memDefInsnSet.size() > 1) {
83             InsnState[ldrInsn] = false;
84             continue;
85         }
86 
87         Operand &resOpnd = ldrInsn->GetOperand(kInsnFirstOpnd);
88         Operand &srcOpnd = strInsn.GetOperand(static_cast<uint32>(strSrcIdx));
89         if (resOpnd.GetSize() != srcOpnd.GetSize()) {
90             return;
91         }
92 
93         auto &resRegOpnd = static_cast<RegOperand &>(resOpnd);
94         auto &srcRegOpnd = static_cast<RegOperand &>(srcOpnd);
95         if (resRegOpnd.GetRegisterType() != srcRegOpnd.GetRegisterType()) {
96             continue;
97         }
98 
99         /* Check if use operand of store is live at load insn. */
100         if (cgFunc.GetRD()->RegIsLiveBetweenInsn(srcRegOpnd.GetRegisterNumber(), strInsn, *ldrInsn)) {
101             GenerateMoveLiveInsn(resRegOpnd, srcRegOpnd, *ldrInsn, strInsn, memSeq);
102             InsnState[ldrInsn] = false;
103         } else if (!cgFunc.IsAfterRegAlloc()) {
104             GenerateMoveDeadInsn(resRegOpnd, srcRegOpnd, *ldrInsn, strInsn, memSeq);
105         }
106 
107         if (CG_DEBUG_FUNC(cgFunc)) {
108             LogInfo::MapleLogger() << "Do store-load optimization 1: str version";
109             LogInfo::MapleLogger() << cgFunc.GetName() << '\n';
110             LogInfo::MapleLogger() << "Store insn: ";
111             strInsn.Dump();
112             LogInfo::MapleLogger() << "Load insn: ";
113             ldrInsn->Dump();
114         }
115     }
116     auto it = memUseInsnSet.begin();
117     ++it;
118     for (; it != memUseInsnSet.end(); ++it) {
119         Insn *curInsn = *it;
120         if (InsnState[curInsn] == false) {
121             continue;
122         }
123         if (!curInsn->IsLoad() || (curInsn->GetDefRegs().size() > 1) || curInsn->GetBB()->IsCleanup()) {
124             continue;
125         }
126         InsnSet memDefInsnSet = cgFunc.GetRD()->FindDefForMemOpnd(*curInsn, kInsnSecondOpnd);
127         DEBUG_ASSERT(!memDefInsnSet.empty(), "load insn should have definitions.");
128         if (memDefInsnSet.size() > 1) {
129             continue;
130         }
131         auto prevIt = it;
132         do {
133             --prevIt;
134             Insn *prevInsn = *prevIt;
135             if (InsnState[prevInsn] == false) {
136                 continue;
137             }
138             if (prevInsn->GetBB() != curInsn->GetBB()) {
139                 break;
140             }
141             if (!prevInsn->IsLoad() || (prevInsn->GetDefRegs().size() > 1) || prevInsn->GetBB()->IsCleanup()) {
142                 continue;
143             }
144             InsnSet memoryDefInsnSet = cgFunc.GetRD()->FindDefForMemOpnd(*curInsn, kInsnSecondOpnd);
145             DEBUG_ASSERT(!memoryDefInsnSet.empty(), "load insn should have definitions.");
146             if (memoryDefInsnSet.size() > 1) {
147                 break;
148             }
149             Operand &resOpnd = curInsn->GetOperand(kInsnFirstOpnd);
150             Operand &srcOpnd = prevInsn->GetOperand(kInsnFirstOpnd);
151             if (resOpnd.GetSize() != srcOpnd.GetSize()) {
152                 continue;
153             }
154 
155             auto &resRegOpnd = static_cast<RegOperand &>(resOpnd);
156             auto &srcRegOpnd = static_cast<RegOperand &>(srcOpnd);
157             if (resRegOpnd.GetRegisterType() != srcRegOpnd.GetRegisterType()) {
158                 continue;
159             }
160             /* Check if use operand of store is live at load insn. */
161             if (cgFunc.GetRD()
162                     ->FindRegDefBetweenInsn(srcRegOpnd.GetRegisterNumber(), prevInsn->GetNext(), curInsn->GetPrev())
163                     .empty()) {
164                 GenerateMoveLiveInsn(resRegOpnd, srcRegOpnd, *curInsn, *prevInsn, memSeq);
165                 InsnState[curInsn] = false;
166             }
167             break;
168         } while (prevIt != memUseInsnSet.begin());
169     }
170 }
171 
GenerateMoveLiveInsn(RegOperand & resRegOpnd,RegOperand & srcRegOpnd,Insn & ldrInsn,Insn & strInsn,short memSeq)172 void AArch64StoreLoadOpt::GenerateMoveLiveInsn(RegOperand &resRegOpnd, RegOperand &srcRegOpnd, Insn &ldrInsn,
173                                                Insn &strInsn, short memSeq)
174 {
175     MOperator movMop = SelectMovMop(resRegOpnd.IsOfFloatOrSIMDClass(), resRegOpnd.GetSize() == k64BitSize);
176     Insn *movInsn = nullptr;
177     if (str2MovMap[&strInsn][memSeq] != nullptr && !cgFunc.IsAfterRegAlloc()) {
178         Insn *movInsnOfStr = str2MovMap[&strInsn][memSeq];
179         auto &vregOpnd = static_cast<RegOperand &>(movInsnOfStr->GetOperand(kInsnFirstOpnd));
180         movInsn = &cgFunc.GetInsnBuilder()->BuildInsn(movMop, resRegOpnd, vregOpnd);
181     } else {
182         movInsn = &cgFunc.GetInsnBuilder()->BuildInsn(movMop, resRegOpnd, srcRegOpnd);
183     }
184     if (&resRegOpnd == &srcRegOpnd && cgFunc.IsAfterRegAlloc()) {
185         ldrInsn.GetBB()->RemoveInsn(ldrInsn);
186         cgFunc.GetRD()->InitGenUse(*ldrInsn.GetBB(), false);
187         return;
188     }
189     movInsn->SetId(ldrInsn.GetId());
190     ldrInsn.GetBB()->ReplaceInsn(ldrInsn, *movInsn);
191     if (CG_DEBUG_FUNC(cgFunc)) {
192         LogInfo::MapleLogger() << "replace ldrInsn:\n";
193         ldrInsn.Dump();
194         LogInfo::MapleLogger() << "with movInsn:\n";
195         movInsn->Dump();
196     }
197     /* Add comment. */
198     MapleString newComment = ldrInsn.GetComment();
199     if (strInsn.IsStorePair()) {
200         newComment += ";  stp-load live version.";
201     } else {
202         newComment += ";  str-load live version.";
203     }
204     movInsn->SetComment(newComment);
205     cgFunc.GetRD()->InitGenUse(*ldrInsn.GetBB(), false);
206 }
207 
GenerateMoveDeadInsn(RegOperand & resRegOpnd,RegOperand & srcRegOpnd,Insn & ldrInsn,Insn & strInsn,short memSeq)208 void AArch64StoreLoadOpt::GenerateMoveDeadInsn(RegOperand &resRegOpnd, RegOperand &srcRegOpnd, Insn &ldrInsn,
209                                                Insn &strInsn, short memSeq)
210 {
211     Insn *newMovInsn = nullptr;
212     RegOperand *vregOpnd = nullptr;
213 
214     if (str2MovMap[&strInsn][memSeq] == nullptr) {
215         RegType regTy = srcRegOpnd.IsOfFloatOrSIMDClass() ? kRegTyFloat : kRegTyInt;
216         regno_t vRegNO = cgFunc.NewVReg(regTy, srcRegOpnd.GetSize() <= k32BitSize ? k4ByteSize : k8ByteSize);
217         /* generate a new vreg, check if the size of DataInfo is big enough */
218         if (vRegNO >= cgFunc.GetRD()->GetRegSize(*strInsn.GetBB())) {
219             cgFunc.GetRD()->EnlargeRegCapacity(vRegNO);
220         }
221         vregOpnd = &cgFunc.CreateVirtualRegisterOperand(vRegNO);
222         MOperator newMop = SelectMovMop(resRegOpnd.IsOfFloatOrSIMDClass(), resRegOpnd.GetSize() == k64BitSize);
223         newMovInsn = &cgFunc.GetInsnBuilder()->BuildInsn(newMop, *vregOpnd, srcRegOpnd);
224         newMovInsn->SetId(strInsn.GetId() + memSeq + 1);
225         strInsn.GetBB()->InsertInsnAfter(strInsn, *newMovInsn);
226         str2MovMap[&strInsn][memSeq] = newMovInsn;
227         /* update DataInfo */
228         cgFunc.GetRD()->UpdateInOut(*strInsn.GetBB(), true);
229     } else {
230         newMovInsn = str2MovMap[&strInsn][memSeq];
231         vregOpnd = &static_cast<RegOperand &>(newMovInsn->GetOperand(kInsnFirstOpnd));
232     }
233     MOperator movMop = SelectMovMop(resRegOpnd.IsOfFloatOrSIMDClass(), resRegOpnd.GetSize() == k64BitSize);
234     Insn &movInsn = cgFunc.GetInsnBuilder()->BuildInsn(movMop, resRegOpnd, *vregOpnd);
235     movInsn.SetId(ldrInsn.GetId());
236     ldrInsn.GetBB()->ReplaceInsn(ldrInsn, movInsn);
237     if (CG_DEBUG_FUNC(cgFunc)) {
238         LogInfo::MapleLogger() << "replace ldrInsn:\n";
239         ldrInsn.Dump();
240         LogInfo::MapleLogger() << "with movInsn:\n";
241         movInsn.Dump();
242     }
243 
244     /* Add comment. */
245     MapleString newComment = ldrInsn.GetComment();
246     if (strInsn.IsStorePair()) {
247         newComment += ";  stp-load die version.";
248     } else {
249         newComment += ";  str-load die version.";
250     }
251     movInsn.SetComment(newComment);
252     cgFunc.GetRD()->InitGenUse(*ldrInsn.GetBB(), false);
253 }
254 
HasMemBarrier(const Insn & ldrInsn,const Insn & strInsn) const255 bool AArch64StoreLoadOpt::HasMemBarrier(const Insn &ldrInsn, const Insn &strInsn) const
256 {
257     if (!cgFunc.GetMirModule().IsCModule()) {
258         return false;
259     }
260     const Insn *currInsn = strInsn.GetNext();
261     while (currInsn != &ldrInsn) {
262         if (currInsn == nullptr) {
263             return false;
264         }
265         if (currInsn->IsMachineInstruction() && currInsn->IsCall()) {
266             return true;
267         }
268         currInsn = currInsn->GetNext();
269     }
270     return false;
271 }
272 
273 /*
274  * Transfer: store wzr, [MEM]
275  *           ... // May exist branches.
276  *           load  x200, [MEM]
277  *        ==>
278  *        OPT_VERSION_STP_ZERO / OPT_VERSION_STR_ZERO:
279  *            store wzr, [MEM]
280  *            ... // May exist branches. if x100 not dead here.
281  *            mov   x200, wzr
282  *
283  *  Params:
284  *    stInsn: indicate store insn.
285  *    strSrcIdx: index of source register operand of store insn. (wzr in this example)
286  *    memUseInsnSet: insns using memOperand
287  */
DoLoadZeroToMoveTransfer(const Insn & strInsn,short strSrcIdx,const InsnSet & memUseInsnSet) const288 void AArch64StoreLoadOpt::DoLoadZeroToMoveTransfer(const Insn &strInsn, short strSrcIdx,
289                                                    const InsnSet &memUseInsnSet) const
290 {
291     /* comment for strInsn should be only added once */
292     for (auto *ldrInsn : memUseInsnSet) {
293         /* Currently we don't support useInsn is ldp insn. */
294         if (!ldrInsn->IsLoad() || ldrInsn->GetDefRegs().size() > 1) {
295             continue;
296         }
297         if (HasMemBarrier(*ldrInsn, strInsn)) {
298             continue;
299         }
300         /* ldr reg, [mem], the index of [mem] is 1 */
301         InsnSet defInsnForUseInsns = cgFunc.GetRD()->FindDefForMemOpnd(*ldrInsn, 1);
302         /* If load has multiple definition, continue. */
303         if (defInsnForUseInsns.size() > 1) {
304             continue;
305         }
306 
307         auto &resOpnd = ldrInsn->GetOperand(0);
308         auto &srcOpnd = strInsn.GetOperand(static_cast<uint32>(strSrcIdx));
309 
310         if (resOpnd.GetSize() != srcOpnd.GetSize()) {
311             return;
312         }
313         RegOperand &resRegOpnd = static_cast<RegOperand &>(resOpnd);
314         MOperator movMop = SelectMovMop(resRegOpnd.IsOfFloatOrSIMDClass(), resRegOpnd.GetSize() == k64BitSize);
315         Insn &movInsn = cgFunc.GetInsnBuilder()->BuildInsn(movMop, resOpnd, srcOpnd);
316         movInsn.SetId(ldrInsn->GetId());
317         ldrInsn->GetBB()->ReplaceInsn(*ldrInsn, movInsn);
318 
319         /* Add comment. */
320         MapleString newComment = ldrInsn->GetComment();
321         newComment += ",  str-load zero version";
322         movInsn.SetComment(newComment);
323     }
324 }
325 
CheckStoreOpCode(MOperator opCode) const326 bool AArch64StoreLoadOpt::CheckStoreOpCode(MOperator opCode) const
327 {
328     switch (opCode) {
329         case MOP_wstr:
330         case MOP_xstr:
331         case MOP_sstr:
332         case MOP_dstr:
333         case MOP_wstp:
334         case MOP_xstp:
335         case MOP_sstp:
336         case MOP_dstp:
337         case MOP_wstrb:
338         case MOP_wstrh:
339             return true;
340         default:
341             return false;
342     }
343 }
344 
MemPropInit()345 void AArch64StoreLoadOpt::MemPropInit()
346 {
347     propMode = kUndef;
348     amount = 0;
349     removeDefInsn = false;
350 }
351 
CheckReplaceReg(Insn & defInsn,Insn & currInsn,InsnSet & replaceRegDefSet,regno_t replaceRegNo)352 bool AArch64StoreLoadOpt::CheckReplaceReg(Insn &defInsn, Insn &currInsn, InsnSet &replaceRegDefSet,
353                                           regno_t replaceRegNo)
354 {
355     if (replaceRegDefSet.empty()) {
356         return true;
357     }
358     if (defInsn.GetBB() == currInsn.GetBB()) {
359         /* check replace reg def between defInsn and currInsn */
360         Insn *tmpInsn = defInsn.GetNext();
361         while (tmpInsn != nullptr && tmpInsn != &currInsn) {
362             if (replaceRegDefSet.find(tmpInsn) != replaceRegDefSet.end()) {
363                 return false;
364             }
365             tmpInsn = tmpInsn->GetNext();
366         }
367     } else {
368         regno_t defRegno = static_cast<RegOperand &>(defInsn.GetOperand(kInsnFirstOpnd)).GetRegisterNumber();
369         if (defRegno == replaceRegNo) {
370             uint32 defLoopId = 0;
371             uint32 curLoopId = 0;
372             if (defInsn.GetBB()->GetLoop()) {
373                 defLoopId = defInsn.GetBB()->GetLoop()->GetHeader()->GetId();
374             }
375             if (currInsn.GetBB()->GetLoop()) {
376                 curLoopId = currInsn.GetBB()->GetLoop()->GetHeader()->GetId();
377             }
378             if (defLoopId != curLoopId) {
379                 return false;
380             }
381         }
382         AArch64ReachingDefinition *a64RD = static_cast<AArch64ReachingDefinition *>(cgFunc.GetRD());
383         if (a64RD->HasRegDefBetweenInsnGlobal(replaceRegNo, defInsn, currInsn)) {
384             return false;
385         }
386     }
387 
388     if (replaceRegDefSet.size() == 1 && *replaceRegDefSet.begin() == &defInsn) {
389         /* lsl x1, x1, #3    <-----should be removed after replace MemOperand of ldrInsn.
390          * ldr x0, [x0,x1]   <-----should be single useInsn for x1
391          */
392         InsnSet newRegUseSet = cgFunc.GetRD()->FindUseForRegOpnd(defInsn, replaceRegNo, true);
393         if (newRegUseSet.size() != k1BitSize) {
394             return false;
395         }
396         removeDefInsn = true;
397     }
398     return true;
399 }
400 
CheckDefInsn(Insn & defInsn,Insn & currInsn)401 bool AArch64StoreLoadOpt::CheckDefInsn(Insn &defInsn, Insn &currInsn)
402 {
403     if (defInsn.GetOperandSize() < k2ByteSize) {
404         return false;
405     }
406     for (uint32 i = kInsnSecondOpnd; i < defInsn.GetOperandSize(); i++) {
407         Operand &opnd = defInsn.GetOperand(i);
408         if (defInsn.IsMove() && opnd.IsRegister() && !cgFunc.IsSPOrFP(static_cast<RegOperand &>(opnd))) {
409             return false;
410         }
411         if (opnd.IsRegister()) {
412             RegOperand &a64OpndTmp = static_cast<RegOperand &>(opnd);
413             regno_t replaceRegNo = a64OpndTmp.GetRegisterNumber();
414             InsnSet newRegDefSet = cgFunc.GetRD()->FindDefForRegOpnd(currInsn, replaceRegNo, true);
415             if (!CheckReplaceReg(defInsn, currInsn, newRegDefSet, replaceRegNo)) {
416                 return false;
417             }
418         }
419     }
420     return true;
421 }
422 
CheckNewAmount(const Insn & insn,uint32 newAmount)423 bool AArch64StoreLoadOpt::CheckNewAmount(const Insn &insn, uint32 newAmount)
424 {
425     MOperator mOp = insn.GetMachineOpcode();
426     switch (mOp) {
427         case MOP_wstrb:
428         case MOP_wldrsb:
429         case MOP_xldrsb:
430         case MOP_wldrb: {
431             return newAmount == 0;
432         }
433         case MOP_wstrh:
434         case MOP_wldrsh:
435         case MOP_xldrsh:
436         case MOP_wldrh: {
437             return (newAmount == 0) || (newAmount == k1BitSize);
438         }
439         case MOP_wstr:
440         case MOP_sstr:
441         case MOP_wldr:
442         case MOP_sldr:
443         case MOP_xldrsw: {
444             return (newAmount == 0) || (newAmount == k2BitSize);
445         }
446         case MOP_qstr:
447         case MOP_qldr: {
448             return (newAmount == 0) || (newAmount == k4BitSize);
449         }
450         default: {
451             return (newAmount == 0) || (newAmount == k3ByteSize);
452         }
453     }
454 }
455 
CheckNewMemOffset(const Insn & insn,MemOperand * newMemOpnd,uint32 opndIdx)456 bool AArch64StoreLoadOpt::CheckNewMemOffset(const Insn &insn, MemOperand *newMemOpnd, uint32 opndIdx)
457 {
458     AArch64CGFunc &a64CgFunc = static_cast<AArch64CGFunc &>(cgFunc);
459     if ((newMemOpnd->GetOffsetImmediate() != nullptr) &&
460         !a64CgFunc.IsOperandImmValid(insn.GetMachineOpcode(), newMemOpnd, opndIdx)) {
461         return false;
462     }
463     auto newAmount = newMemOpnd->ShiftAmount();
464     if (!CheckNewAmount(insn, newAmount)) {
465         return false;
466     }
467     /* is ldp or stp, addrMode must be BOI */
468     if ((opndIdx == kInsnThirdOpnd) && (newMemOpnd->GetAddrMode() != MemOperand::kAddrModeBOi)) {
469         return false;
470     }
471     return true;
472 }
473 
SelectReplaceExt(const Insn & defInsn,RegOperand & base,bool isSigned)474 MemOperand *AArch64StoreLoadOpt::SelectReplaceExt(const Insn &defInsn, RegOperand &base, bool isSigned)
475 {
476     MemOperand *newMemOpnd = nullptr;
477     RegOperand *newOffset = static_cast<RegOperand *>(&defInsn.GetOperand(kInsnSecondOpnd));
478     CHECK_FATAL(newOffset != nullptr, "newOffset is null!");
479     /* defInsn is extend, currMemOpnd is same extend or shift */
480     bool propExtend = (propMode == kPropShift) || ((propMode == kPropSignedExtend) && isSigned) ||
481                       ((propMode == kPropUnsignedExtend) && !isSigned);
482     if (propMode == kPropOffset) {
483         newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(MemOperand::kAddrModeBOrX, k64BitSize, base,
484                                                                            *newOffset, 0, isSigned);
485     } else if (propExtend) {
486         newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(MemOperand::kAddrModeBOrX, k64BitSize, base,
487                                                                            *newOffset, amount, isSigned);
488     } else {
489         return nullptr;
490     }
491     return newMemOpnd;
492 }
493 
HandleArithImmDef(RegOperand & replace,Operand * oldOffset,int64 defVal)494 MemOperand *AArch64StoreLoadOpt::HandleArithImmDef(RegOperand &replace, Operand *oldOffset, int64 defVal)
495 {
496     if (propMode != kPropBase) {
497         return nullptr;
498     }
499     OfstOperand *newOfstImm = nullptr;
500     if (oldOffset == nullptr) {
501         newOfstImm = &static_cast<AArch64CGFunc &>(cgFunc).CreateOfstOpnd(static_cast<uint64>(defVal), k32BitSize);
502     } else {
503         auto *ofstOpnd = static_cast<OfstOperand *>(oldOffset);
504         CHECK_FATAL(ofstOpnd != nullptr, "oldOffsetOpnd is null");
505         newOfstImm = &static_cast<AArch64CGFunc &>(cgFunc).CreateOfstOpnd(
506             static_cast<uint64>(defVal + ofstOpnd->GetValue()), k32BitSize);
507     }
508     CHECK_FATAL(newOfstImm != nullptr, "newOffset is null!");
509     return static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(MemOperand::kAddrModeBOi, k64BitSize, replace, nullptr,
510                                                                  newOfstImm, nullptr);
511 }
512 
513 /*
514  * limit to adjacent bb to avoid ra spill.
515  */
IsAdjacentBB(Insn & defInsn,Insn & curInsn) const516 bool AArch64StoreLoadOpt::IsAdjacentBB(Insn &defInsn, Insn &curInsn) const
517 {
518     if (defInsn.GetBB() == curInsn.GetBB()) {
519         return true;
520     }
521     for (auto *bb : defInsn.GetBB()->GetSuccs()) {
522         if (bb == curInsn.GetBB()) {
523             return true;
524         }
525         if (bb->IsSoloGoto()) {
526             BB *tragetBB = CGCFG::GetTargetSuc(*bb);
527             if (tragetBB == curInsn.GetBB()) {
528                 return true;
529             }
530         }
531     }
532     return false;
533 }
534 
535 /*
536  * currAddrMode | defMop       | propMode | replaceAddrMode
537  * =============================================================================
538  * boi          | addrri       | base     | boi, update imm(offset)
539  *              | addrrr       | base     | imm(offset) == 0(nullptr) ? borx : NA
540  *              | subrri       | base     | boi, update imm(offset)
541  *              | subrrr       | base     | NA
542  *              | adrpl12      | base     | imm(offset) == 0(nullptr) ? literal : NA
543  *              | movrr        | base     | boi
544  *              | movri        | base     | NA
545  *              | extend/lsl   | base     | NA
546  * =============================================================================
547  * borx         | addrri       | offset   | NA
548  * (noextend)   | addrrr       | offset   | NA
549  *              | subrri       | offset   | NA
550  *              | subrrr       | offset   | NA
551  *              | adrpl12      | offset   | NA
552  *              | movrr        | offset   | borx
553  *              | movri        | offset   | bori
554  *              | extend/lsl   | offset   | borx(with extend)
555  * =============================================================================
556  * borx         | addrri       | extend   | NA
557  * (extend)     | addrrr       | extend   | NA
558  *              | subrri       | extend   | NA
559  *              | subrrr       | extend   | NA
560  *              | adrpl12      | extend   | NA
561  *              | movrr        | extend   | borx
562  *              | movri        | extend   | NA
563  *              | extend/lsl   | extend   | borx(with extend)
564  * =============================================================================
565  */
SelectReplaceMem(Insn & defInsn,Insn & curInsn,RegOperand & base,Operand * offset)566 MemOperand *AArch64StoreLoadOpt::SelectReplaceMem(Insn &defInsn, Insn &curInsn, RegOperand &base, Operand *offset)
567 {
568     MemOperand *newMemOpnd = nullptr;
569     MOperator opCode = defInsn.GetMachineOpcode();
570     RegOperand *replace = static_cast<RegOperand *>(&defInsn.GetOperand(kInsnSecondOpnd));
571     switch (opCode) {
572         case MOP_xsubrri12:
573         case MOP_wsubrri12: {
574             if (!IsAdjacentBB(defInsn, curInsn)) {
575                 break;
576             }
577             auto &immOpnd = static_cast<ImmOperand &>(defInsn.GetOperand(kInsnThirdOpnd));
578             int64 defVal = -(immOpnd.GetValue());
579             newMemOpnd = HandleArithImmDef(*replace, offset, defVal);
580             break;
581         }
582         case MOP_xaddrri12:
583         case MOP_waddrri12: {
584             auto &immOpnd = static_cast<ImmOperand &>(defInsn.GetOperand(kInsnThirdOpnd));
585             int64 defVal = immOpnd.GetValue();
586             newMemOpnd = HandleArithImmDef(*replace, offset, defVal);
587             break;
588         }
589         case MOP_xaddrrr:
590         case MOP_waddrrr:
591         case MOP_dadd:
592         case MOP_sadd: {
593             if (propMode == kPropBase) {
594                 ImmOperand *ofstOpnd = static_cast<ImmOperand *>(offset);
595                 if (!ofstOpnd->IsZero()) {
596                     break;
597                 }
598                 RegOperand *newOffset = static_cast<RegOperand *>(&defInsn.GetOperand(kInsnThirdOpnd));
599                 CHECK_FATAL(newOffset != nullptr, "newOffset is null!");
600                 newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
601                     MemOperand::kAddrModeBOrX, k64BitSize, *replace, newOffset, nullptr, nullptr);
602             }
603             break;
604         }
605         case MOP_xadrpl12: {
606             if (propMode == kPropBase) {
607                 ImmOperand *ofstOpnd = static_cast<ImmOperand *>(offset);
608                 CHECK_FATAL(ofstOpnd != nullptr, "oldOffset is null!");
609                 int64 val = ofstOpnd->GetValue();
610                 StImmOperand *offset1 = static_cast<StImmOperand *>(&defInsn.GetOperand(kInsnThirdOpnd));
611                 CHECK_FATAL(offset1 != nullptr, "offset1 is null!");
612                 val += offset1->GetOffset();
613                 OfstOperand *newOfsetOpnd =
614                     &static_cast<AArch64CGFunc &>(cgFunc).CreateOfstOpnd(static_cast<uint64>(val), k32BitSize);
615                 CHECK_FATAL(newOfsetOpnd != nullptr, "newOfsetOpnd is null!");
616                 const MIRSymbol *addr = offset1->GetSymbol();
617                 /* do not guarantee rodata alignment at Os */
618                 if (CGOptions::OptimizeForSize() && addr->IsReadOnly()) {
619                     break;
620                 }
621                 newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
622                     MemOperand::kAddrModeLo12Li, k64BitSize, *replace, nullptr, newOfsetOpnd, addr);
623             }
624             break;
625         }
626         case MOP_xmovrr:
627         case MOP_wmovrr: {
628             if (propMode == kPropBase) {
629                 OfstOperand *offsetTmp = static_cast<OfstOperand *>(offset);
630                 CHECK_FATAL(offsetTmp != nullptr, "newOffset is null!");
631                 newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
632                     MemOperand::kAddrModeBOi, k64BitSize, *replace, nullptr, offsetTmp, nullptr);
633             } else if (propMode == kPropOffset) { /* if newOffset is SP, swap base and newOffset */
634                 if (cgFunc.IsSPOrFP(*replace)) {
635                     newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
636                         MemOperand::kAddrModeBOrX, k64BitSize, *replace, &base, nullptr, nullptr);
637                 } else {
638                     newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
639                         MemOperand::kAddrModeBOrX, k64BitSize, base, replace, nullptr, nullptr);
640                 }
641             } else if (propMode == kPropSignedExtend) {
642                 newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
643                     MemOperand::kAddrModeBOrX, k64BitSize, base, *replace, amount, true);
644             } else {
645                 newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(MemOperand::kAddrModeBOrX,
646                                                                                    k64BitSize, base, *replace, amount);
647             }
648             break;
649         }
650         case MOP_wmovri32:
651         case MOP_xmovri64: {
652             if (propMode == kPropOffset) {
653                 ImmOperand *imm = static_cast<ImmOperand *>(&defInsn.GetOperand(kInsnSecondOpnd));
654                 OfstOperand *newOffset = &static_cast<AArch64CGFunc &>(cgFunc).CreateOfstOpnd(
655                     static_cast<uint64>(imm->GetValue()), k32BitSize);
656                 CHECK_FATAL(newOffset != nullptr, "newOffset is null!");
657                 newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(MemOperand::kAddrModeBOi, k64BitSize,
658                                                                                    base, nullptr, newOffset, nullptr);
659             }
660             break;
661         }
662         case MOP_xlslrri6:
663         case MOP_wlslrri5: {
664             ImmOperand *imm = static_cast<ImmOperand *>(&defInsn.GetOperand(kInsnThirdOpnd));
665             RegOperand *newOffset = static_cast<RegOperand *>(&defInsn.GetOperand(kInsnSecondOpnd));
666             CHECK_FATAL(newOffset != nullptr, "newOffset is null!");
667             uint32 shift = static_cast<uint32>(imm->GetValue());
668             if (propMode == kPropOffset) {
669                 if ((shift < k4ByteSize) && (shift >= 0)) {
670                     newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
671                         MemOperand::kAddrModeBOrX, k64BitSize, base, *newOffset, shift);
672                 }
673             } else if (propMode == kPropShift) {
674                 shift += amount;
675                 if ((shift < k4ByteSize) && (shift >= 0)) {
676                     newMemOpnd = static_cast<AArch64CGFunc &>(cgFunc).CreateMemOperand(
677                         MemOperand::kAddrModeBOrX, k64BitSize, base, *newOffset, shift);
678                 }
679             }
680             break;
681         }
682         case MOP_xsxtw64: {
683             newMemOpnd = SelectReplaceExt(defInsn, base, true);
684             break;
685         }
686         case MOP_xuxtw64: {
687             newMemOpnd = SelectReplaceExt(defInsn, base, false);
688             break;
689         }
690         default:
691             break;
692     }
693     return newMemOpnd;
694 }
695 
ReplaceMemOpnd(Insn & insn,regno_t regNo,RegOperand & base,Operand * offset)696 bool AArch64StoreLoadOpt::ReplaceMemOpnd(Insn &insn, regno_t regNo, RegOperand &base, Operand *offset)
697 {
698     AArch64ReachingDefinition *a64RD = static_cast<AArch64ReachingDefinition *>(cgFunc.GetRD());
699     CHECK_FATAL((a64RD != nullptr), "check a64RD!");
700     InsnSet regDefSet = a64RD->FindDefForRegOpnd(insn, regNo, true);
701     if (regDefSet.size() != k1BitSize) {
702         return false;
703     }
704     Insn *regDefInsn = *regDefSet.begin();
705     if (!CheckDefInsn(*regDefInsn, insn)) {
706         return false;
707     }
708     MemOperand *newMemOpnd = SelectReplaceMem(*regDefInsn, insn, base, offset);
709     if (newMemOpnd == nullptr) {
710         return false;
711     }
712 
713     /* check new memOpnd */
714     if (newMemOpnd->GetBaseRegister() != nullptr) {
715         InsnSet regDefSetForNewBase =
716             a64RD->FindDefForRegOpnd(insn, newMemOpnd->GetBaseRegister()->GetRegisterNumber(), true);
717         if (regDefSetForNewBase.size() != k1BitSize) {
718             return false;
719         }
720     }
721     if (newMemOpnd->GetIndexRegister() != nullptr) {
722         InsnSet regDefSetForNewIndex =
723             a64RD->FindDefForRegOpnd(insn, newMemOpnd->GetIndexRegister()->GetRegisterNumber(), true);
724         if (regDefSetForNewIndex.size() != k1BitSize) {
725             return false;
726         }
727     }
728 
729     uint32 opndIdx;
730     if (insn.IsLoadPair() || insn.IsStorePair()) {
731         if (newMemOpnd->GetOffsetImmediate() == nullptr) {
732             return false;
733         }
734         opndIdx = kInsnThirdOpnd;
735     } else {
736         opndIdx = kInsnSecondOpnd;
737     }
738     if (!CheckNewMemOffset(insn, newMemOpnd, opndIdx)) {
739         return false;
740     }
741     if (CG_DEBUG_FUNC(cgFunc)) {
742         std::cout << "replace insn:" << std::endl;
743         insn.Dump();
744     }
745     insn.SetOperand(opndIdx, *newMemOpnd);
746     if (CG_DEBUG_FUNC(cgFunc)) {
747         std::cout << "new insn:" << std::endl;
748         insn.Dump();
749     }
750     if (removeDefInsn) {
751         if (CG_DEBUG_FUNC(cgFunc)) {
752             std::cout << "remove insn:" << std::endl;
753             regDefInsn->Dump();
754         }
755         regDefInsn->GetBB()->RemoveInsn(*regDefInsn);
756     }
757     cgFunc.GetRD()->InitGenUse(*regDefInsn->GetBB(), false);
758     cgFunc.GetRD()->UpdateInOut(*insn.GetBB(), false);
759     cgFunc.GetRD()->UpdateInOut(*insn.GetBB(), true);
760     return true;
761 }
762 
CanDoMemProp(const Insn * insn)763 bool AArch64StoreLoadOpt::CanDoMemProp(const Insn *insn)
764 {
765     if (!cgFunc.GetMirModule().IsCModule()) {
766         return false;
767     }
768     if (!insn->IsMachineInstruction()) {
769         return false;
770     }
771     if (insn->GetMachineOpcode() == MOP_qstr) {
772         return false;
773     }
774 
775     if (insn->IsLoad() || insn->IsStore()) {
776         if (insn->IsAtomic()) {
777             return false;
778         }
779         // It is not desired to propagate on 128bit reg with immediate offset
780         // which may cause linker to issue misalignment error
781         if (insn->IsAtomic() || insn->GetOperand(0).GetSize() == k128BitSize) {
782             return false;
783         }
784         MemOperand *currMemOpnd = static_cast<MemOperand *>(insn->GetMemOpnd());
785         return currMemOpnd != nullptr;
786     }
787     return false;
788 }
789 
SelectPropMode(const MemOperand & currMemOpnd)790 void AArch64StoreLoadOpt::SelectPropMode(const MemOperand &currMemOpnd)
791 {
792     MemOperand::AArch64AddressingMode currAddrMode = currMemOpnd.GetAddrMode();
793     switch (currAddrMode) {
794         case MemOperand::kAddrModeBOi: {
795             if (!currMemOpnd.IsPreIndexed() && !currMemOpnd.IsPostIndexed()) {
796                 propMode = kPropBase;
797             }
798             break;
799         }
800         case MemOperand::kAddrModeBOrX: {
801             propMode = kPropOffset;
802             amount = currMemOpnd.ShiftAmount();
803             if (currMemOpnd.GetExtendAsString() == "LSL") {
804                 if (amount != 0) {
805                     propMode = kPropShift;
806                 }
807                 break;
808             } else if (currMemOpnd.SignedExtend()) {
809                 propMode = kPropSignedExtend;
810             } else if (currMemOpnd.UnsignedExtend()) {
811                 propMode = kPropUnsignedExtend;
812             }
813             break;
814         }
815         default:
816             propMode = kUndef;
817     }
818 }
819 
820 /*
821  * Optimize: store x100, [MEM]
822  *           ... // May exist branches.
823  *           load  x200, [MEM]
824  *        ==>
825  *        OPT_VERSION_STP_LIVE / OPT_VERSION_STR_LIVE:
826  *           store x100, [MEM]
827  *           ... // May exist branches. if x100 not dead here.
828  *           mov   x200, x100
829  *        OPT_VERSION_STP_DIE / OPT_VERSION_STR_DIE:
830  *           store x100, [MEM]
831  *           mov x9000(new reg), x100
832  *           ... // May exist branches. if x100 dead here.
833  *           mov   x200, x9000
834  *
835  *  Note: x100 may be wzr/xzr registers.
836  */
DoStoreLoadOpt()837 void AArch64StoreLoadOpt::DoStoreLoadOpt()
838 {
839     AArch64CGFunc &a64CgFunc = static_cast<AArch64CGFunc &>(cgFunc);
840     if (a64CgFunc.IsIntrnCallForC()) {
841         return;
842     }
843     FOR_ALL_BB(bb, &a64CgFunc) {
844         FOR_BB_INSNS_SAFE(insn, bb, next) {
845             MOperator mOp = insn->GetMachineOpcode();
846             if (CanDoMemProp(insn)) {
847                 MemProp(*insn);
848             }
849             if (a64CgFunc.GetMirModule().IsCModule() && cgFunc.GetRD()->OnlyAnalysisReg()) {
850                 continue;
851             }
852             if (!insn->IsMachineInstruction() || !insn->IsStore() || !CheckStoreOpCode(mOp) ||
853                 (a64CgFunc.GetMirModule().IsCModule() && !a64CgFunc.IsAfterRegAlloc()) ||
854                 (!a64CgFunc.GetMirModule().IsCModule() && a64CgFunc.IsAfterRegAlloc())) {
855                 continue;
856             }
857             if (insn->IsStorePair()) {
858                 ProcessStrPair(*insn);
859                 continue;
860             }
861             ProcessStr(*insn);
862         }
863     }
864 }
865 
866 /*
867  * PropBase:
868  *   add/sub x1, x2, #immVal1
869  *   ...(no def of x2)
870  *   ldr/str x0, [x1, #immVal2]
871  *   ======>
872  *   add/sub x1, x2, #immVal1
873  *   ...
874  *   ldr/str x0, [x2, #(immVal1 + immVal2)/#(-immVal1 + immVal2)]
875  *
876  * PropOffset:
877  *   sxtw x2, w2
878  *   lsl x1, x2, #1~3
879  *   ...(no def of x2)
880  *   ldr/str x0, [x0, x1]
881  *   ======>
882  *   sxtw x2, w2
883  *   lsl x1, x2, #1~3
884  *   ...
885  *   ldr/str x0, [x0, w2, sxtw 1~3]
886  */
MemProp(Insn & insn)887 void AArch64StoreLoadOpt::MemProp(Insn &insn)
888 {
889     MemPropInit();
890     MemOperand *currMemOpnd = static_cast<MemOperand *>(insn.GetMemOpnd());
891     SelectPropMode(*currMemOpnd);
892     RegOperand *base = currMemOpnd->GetBaseRegister();
893     Operand *offset = currMemOpnd->GetOffset();
894     bool memReplaced = false;
895 
896     if (propMode == kUndef) {
897         return;
898     } else if (propMode == kPropBase) {
899         ImmOperand *immOffset = static_cast<ImmOperand *>(offset);
900         CHECK_FATAL(immOffset != nullptr, "immOffset is nullptr!");
901         regno_t baseRegNo = base->GetRegisterNumber();
902         memReplaced = ReplaceMemOpnd(insn, baseRegNo, *base, immOffset);
903     } else {
904         RegOperand *regOffset = static_cast<RegOperand *>(offset);
905         if (regOffset == nullptr) {
906             return;
907         }
908         regno_t offsetRegNo = regOffset->GetRegisterNumber();
909         memReplaced = ReplaceMemOpnd(insn, offsetRegNo, *base, regOffset);
910     }
911 
912     /* if prop success, find more prop chance */
913     if (memReplaced) {
914         MemProp(insn);
915     }
916 }
917 
918 /*
919  * Assume stack(FP) will not be varied out of pro/epi log
920  * PreIndex:
921  *   add/sub x1, x1 #immVal1
922  *   ...(no def/use of x1)
923  *   ldr/str x0, [x1]
924  *   ======>
925  *   ldr/str x0, [x1, #immVal1]!
926  *
927  * PostIndex:
928  *   ldr/str x0, [x1]
929  *   ...(no def/use of x1)
930  *   add/sub x1, x1, #immVal1
931  *   ======>
932  *   ldr/str x0, [x1],  #immVal1
933  */
StrLdrIndexModeOpt(Insn & currInsn)934 void AArch64StoreLoadOpt::StrLdrIndexModeOpt(Insn &currInsn)
935 {
936     auto *curMemopnd = static_cast<MemOperand *>(currInsn.GetMemOpnd());
937     DEBUG_ASSERT(curMemopnd != nullptr, " get memopnd failed");
938     /* one instruction cannot define one register twice */
939     if (!CanDoIndexOpt(*curMemopnd) || currInsn.IsRegDefined(curMemopnd->GetBaseRegister()->GetRegisterNumber())) {
940         return;
941     }
942     MemOperand *newMemopnd = SelectIndexOptMode(currInsn, *curMemopnd);
943     if (newMemopnd != nullptr) {
944         currInsn.SetMemOpnd(newMemopnd);
945     }
946 }
947 
CanDoIndexOpt(const MemOperand & MemOpnd)948 bool AArch64StoreLoadOpt::CanDoIndexOpt(const MemOperand &MemOpnd)
949 {
950     if (MemOpnd.GetAddrMode() != MemOperand::kAddrModeBOi || !MemOpnd.IsIntactIndexed()) {
951         return false;
952     }
953     DEBUG_ASSERT(MemOpnd.GetOffsetImmediate() != nullptr, " kAddrModeBOi memopnd have no offset imm");
954     if (!MemOpnd.GetOffsetImmediate()->IsImmOffset()) {
955         return false;
956     }
957     if (cgFunc.IsSPOrFP(*MemOpnd.GetBaseRegister())) {
958         return false;
959     }
960     OfstOperand *a64Ofst = MemOpnd.GetOffsetImmediate();
961     if (a64Ofst == nullptr) {
962         return false;
963     }
964     return a64Ofst->GetValue() == 0;
965 }
966 
GetOffsetForNewIndex(Insn & defInsn,Insn & insn,regno_t baseRegNO,uint32 memOpndSize)967 int64 AArch64StoreLoadOpt::GetOffsetForNewIndex(Insn &defInsn, Insn &insn, regno_t baseRegNO, uint32 memOpndSize)
968 {
969     bool subMode = defInsn.GetMachineOpcode() == MOP_wsubrri12 || defInsn.GetMachineOpcode() == MOP_xsubrri12;
970     bool addMode = defInsn.GetMachineOpcode() == MOP_waddrri12 || defInsn.GetMachineOpcode() == MOP_xaddrri12;
971     if (addMode || subMode) {
972         DEBUG_ASSERT(static_cast<RegOperand &>(defInsn.GetOperand(kInsnFirstOpnd)).GetRegisterNumber() == baseRegNO,
973                      "check def opnd");
974         auto &srcOpnd = static_cast<RegOperand &>(defInsn.GetOperand(kInsnSecondOpnd));
975         if (srcOpnd.GetRegisterNumber() == baseRegNO && defInsn.GetBB() == insn.GetBB()) {
976             int64 offsetVal = static_cast<ImmOperand &>(defInsn.GetOperand(kInsnThirdOpnd)).GetValue();
977             if (!MemOperand::IsSIMMOffsetOutOfRange(offsetVal, memOpndSize == k64BitSize, insn.IsLoadStorePair())) {
978                 return subMode ? -offsetVal : offsetVal;
979             }
980         }
981     }
982     return kMaxPimm8; /* simm max value cannot excced pimm max value */
983 };
984 
SelectIndexOptMode(Insn & insn,const MemOperand & curMemOpnd)985 MemOperand *AArch64StoreLoadOpt::SelectIndexOptMode(Insn &insn, const MemOperand &curMemOpnd)
986 {
987     AArch64ReachingDefinition *a64RD = static_cast<AArch64ReachingDefinition *>(cgFunc.GetRD());
988     DEBUG_ASSERT((a64RD != nullptr), "check a64RD!");
989     regno_t baseRegisterNO = curMemOpnd.GetBaseRegister()->GetRegisterNumber();
990     auto &a64cgFunc = static_cast<AArch64CGFunc &>(cgFunc);
991     /* pre index */
992     InsnSet regDefSet = a64RD->FindDefForRegOpnd(insn, baseRegisterNO, true);
993     if (regDefSet.size() == k1BitSize) {
994         Insn *defInsn = *regDefSet.begin();
995         int64 defOffset = GetOffsetForNewIndex(*defInsn, insn, baseRegisterNO, curMemOpnd.GetSize());
996         if (defOffset < kMaxPimm8) {
997             InsnSet tempCheck;
998             (void)a64RD->FindRegUseBetweenInsn(baseRegisterNO, defInsn->GetNext(), insn.GetPrev(), tempCheck);
999             if (tempCheck.empty() && (defInsn->GetBB() == insn.GetBB())) {
1000                 auto &newMem = a64cgFunc.CreateMemOpnd(*curMemOpnd.GetBaseRegister(), defOffset, curMemOpnd.GetSize());
1001                 DEBUG_ASSERT(newMem.GetOffsetImmediate() != nullptr, "need offset for memopnd in this case");
1002                 newMem.SetIndexOpt(MemOperand::kPreIndex);
1003                 insn.GetBB()->RemoveInsn(*defInsn);
1004                 return &newMem;
1005             }
1006         }
1007     }
1008     /* post index */
1009     std::vector<Insn *> refDefVec =
1010         a64RD->FindRegDefBetweenInsn(baseRegisterNO, &insn, insn.GetBB()->GetLastInsn(), true);
1011     if (!refDefVec.empty()) {
1012         Insn *defInsn = refDefVec.back();
1013         int64 defOffset = GetOffsetForNewIndex(*defInsn, insn, baseRegisterNO, curMemOpnd.GetSize());
1014         if (defOffset < kMaxPimm8) {
1015             InsnSet tempCheck;
1016             (void)a64RD->FindRegUseBetweenInsn(baseRegisterNO, insn.GetNext(), defInsn->GetPrev(), tempCheck);
1017             if (tempCheck.empty() && (defInsn->GetBB() == insn.GetBB())) {
1018                 auto &newMem = a64cgFunc.CreateMemOpnd(*curMemOpnd.GetBaseRegister(), defOffset, curMemOpnd.GetSize());
1019                 DEBUG_ASSERT(newMem.GetOffsetImmediate() != nullptr, "need offset for memopnd in this case");
1020                 newMem.SetIndexOpt(MemOperand::kPostIndex);
1021                 insn.GetBB()->RemoveInsn(*defInsn);
1022                 return &newMem;
1023             }
1024         }
1025     }
1026     return nullptr;
1027 }
1028 
ProcessStrPair(Insn & insn)1029 void AArch64StoreLoadOpt::ProcessStrPair(Insn &insn)
1030 {
1031     const short memIndex = 2;
1032     short regIndex = 0;
1033     Operand &opnd = insn.GetOperand(memIndex);
1034     auto &memOpnd = static_cast<MemOperand &>(opnd);
1035     RegOperand *base = memOpnd.GetBaseRegister();
1036     if ((base == nullptr) || !(cgFunc.GetRD()->IsFrameReg(*base))) {
1037         return;
1038     }
1039     if (cgFunc.IsAfterRegAlloc() && !insn.IsSpillInsn()) {
1040         return;
1041     }
1042     DEBUG_ASSERT(memOpnd.GetIndexRegister() == nullptr, "frame MemOperand must not be exist register index");
1043     InsnSet memUseInsnSet;
1044     for (int i = 0; i != kMaxMovNum; ++i) {
1045         memUseInsnSet.clear();
1046         if (i == 0) {
1047             regIndex = 0;
1048             memUseInsnSet = cgFunc.GetRD()->FindUseForMemOpnd(insn, memIndex);
1049         } else {
1050             regIndex = 1;
1051             memUseInsnSet = cgFunc.GetRD()->FindUseForMemOpnd(insn, memIndex, true);
1052         }
1053         if (memUseInsnSet.empty()) {
1054             return;
1055         }
1056         auto &regOpnd = static_cast<RegOperand &>(insn.GetOperand(static_cast<uint32>(regIndex)));
1057         if (regOpnd.GetRegisterNumber() == RZR) {
1058             DoLoadZeroToMoveTransfer(insn, regIndex, memUseInsnSet);
1059         } else {
1060             DoLoadToMoveTransfer(insn, regIndex, i, memUseInsnSet);
1061         }
1062     }
1063 }
1064 
ProcessStr(Insn & insn)1065 void AArch64StoreLoadOpt::ProcessStr(Insn &insn)
1066 {
1067     /* str x100, [mem], mem index is 1, x100 index is 0; */
1068     const short memIndex = 1;
1069     const short regIndex = 0;
1070     Operand &opnd = insn.GetOperand(memIndex);
1071     auto &memOpnd = static_cast<MemOperand &>(opnd);
1072     RegOperand *base = memOpnd.GetBaseRegister();
1073     if ((base == nullptr) || !(cgFunc.GetRD()->IsFrameReg(*base))) {
1074         return;
1075     }
1076 
1077     if (cgFunc.IsAfterRegAlloc() && !insn.IsSpillInsn()) {
1078         return;
1079     }
1080     DEBUG_ASSERT(memOpnd.GetIndexRegister() == nullptr, "frame MemOperand must not be exist register index");
1081 
1082     InsnSet memUseInsnSet = cgFunc.GetRD()->FindUseForMemOpnd(insn, memIndex);
1083     if (memUseInsnSet.empty()) {
1084         return;
1085     }
1086 
1087     auto *regOpnd = static_cast<RegOperand *>(&insn.GetOperand(regIndex));
1088     CHECK_NULL_FATAL(regOpnd);
1089     if (regOpnd->GetRegisterNumber() == RZR) {
1090         DoLoadZeroToMoveTransfer(insn, regIndex, memUseInsnSet);
1091     } else {
1092         DoLoadToMoveTransfer(insn, regIndex, 0, memUseInsnSet);
1093     }
1094     if (cgFunc.IsAfterRegAlloc() && insn.IsSpillInsn()) {
1095         InsnSet newmemUseInsnSet = cgFunc.GetRD()->FindUseForMemOpnd(insn, memIndex);
1096         if (newmemUseInsnSet.empty()) {
1097             insn.GetBB()->RemoveInsn(insn);
1098         }
1099     }
1100 }
1101 } /* namespace maplebe */
1102