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