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 "peep.h"
17 #include "cg.h"
18 #include "mpl_logging.h"
19 #include "common_utils.h"
20 #if TARGAARCH64
21 #include "aarch64_peep.h"
22 #elif TARGRISCV64
23 #include "riscv64_peep.h"
24 #elif defined TARGX86_64
25 #include "x64_peep.h"
26 #endif
27 #if TARGARM32
28 #include "arm32_peep.h"
29 #endif
30
31 namespace maplebe {
32 #if TARGAARCH64
IsCCRegCrossVersion(Insn & startInsn,Insn & endInsn,const RegOperand & ccReg)33 bool CGPeepPattern::IsCCRegCrossVersion(Insn &startInsn, Insn &endInsn, const RegOperand &ccReg)
34 {
35 if (startInsn.GetBB() != endInsn.GetBB()) {
36 return true;
37 }
38 CHECK_FATAL(ssaInfo != nullptr, "must have ssaInfo");
39 CHECK_FATAL(ccReg.IsSSAForm(), "cc reg must be ssa form");
40 for (auto *curInsn = startInsn.GetNext(); curInsn != nullptr && curInsn != &endInsn; curInsn = curInsn->GetNext()) {
41 if (!curInsn->IsMachineInstruction()) {
42 continue;
43 }
44 if (curInsn->IsCall()) {
45 return true;
46 }
47 uint32 opndNum = curInsn->GetOperandSize();
48 for (uint32 i = 0; i < opndNum; ++i) {
49 Operand &opnd = curInsn->GetOperand(i);
50 if (!opnd.IsRegister()) {
51 continue;
52 }
53 auto ®Opnd = static_cast<RegOperand &>(opnd);
54 if (!curInsn->IsRegDefined(regOpnd.GetRegisterNumber())) {
55 continue;
56 }
57 if (static_cast<RegOperand &>(opnd).IsOfCC()) {
58 VRegVersion *ccVersion = ssaInfo->FindSSAVersion(ccReg.GetRegisterNumber());
59 VRegVersion *curCCVersion = ssaInfo->FindSSAVersion(regOpnd.GetRegisterNumber());
60 CHECK_FATAL(ccVersion != nullptr && curCCVersion != nullptr,
61 "RegVersion must not be null based on ssa");
62 CHECK_FATAL(!ccVersion->IsDeleted() && !curCCVersion->IsDeleted(), "deleted version");
63 if (ccVersion->GetVersionIdx() != curCCVersion->GetVersionIdx()) {
64 return true;
65 }
66 }
67 }
68 }
69 return false;
70 }
71
GetLogValueAtBase2(int64 val) const72 int64 CGPeepPattern::GetLogValueAtBase2(int64 val) const
73 {
74 return (__builtin_popcountll(static_cast<uint64>(val)) == 1) ? (__builtin_ffsll(val) - 1) : -1;
75 }
76
GetAllUseInsn(const RegOperand & defReg)77 InsnSet CGPeepPattern::GetAllUseInsn(const RegOperand &defReg)
78 {
79 InsnSet allUseInsn;
80 if ((ssaInfo != nullptr) && defReg.IsSSAForm()) {
81 VRegVersion *defVersion = ssaInfo->FindSSAVersion(defReg.GetRegisterNumber());
82 CHECK_FATAL(defVersion != nullptr, "useVRegVersion must not be null based on ssa");
83 for (auto insnInfo : defVersion->GetAllUseInsns()) {
84 Insn *secondInsn = insnInfo.second->GetInsn();
85 allUseInsn.emplace(secondInsn);
86 }
87 }
88 return allUseInsn;
89 }
90
GetDefInsn(const RegOperand & useReg)91 Insn *CGPeepPattern::GetDefInsn(const RegOperand &useReg)
92 {
93 if (!useReg.IsSSAForm()) {
94 return nullptr;
95 }
96 regno_t useRegNO = useReg.GetRegisterNumber();
97 VRegVersion *useVersion = ssaInfo->FindSSAVersion(useRegNO);
98 DEBUG_ASSERT(useVersion != nullptr, "useVRegVersion must not be null based on ssa");
99 CHECK_FATAL(!useVersion->IsDeleted(), "deleted version");
100 DUInsnInfo *defInfo = useVersion->GetDefInsnInfo();
101 return defInfo == nullptr ? nullptr : defInfo->GetInsn();
102 }
103
DumpAfterPattern(std::vector<Insn * > & prevInsns,const Insn * replacedInsn,const Insn * newInsn)104 void CGPeepPattern::DumpAfterPattern(std::vector<Insn *> &prevInsns, const Insn *replacedInsn, const Insn *newInsn)
105 {
106 LogInfo::MapleLogger() << ">>>>>>> In " << GetPatternName() << " : <<<<<<<\n";
107 if (!prevInsns.empty()) {
108 if ((replacedInsn == nullptr) && (newInsn == nullptr)) {
109 LogInfo::MapleLogger() << "======= RemoveInsns : {\n";
110 } else {
111 LogInfo::MapleLogger() << "======= PrevInsns : {\n";
112 }
113 for (auto *prevInsn : prevInsns) {
114 if (prevInsn != nullptr) {
115 LogInfo::MapleLogger() << "[primal form] ";
116 prevInsn->Dump();
117 if (ssaInfo != nullptr) {
118 LogInfo::MapleLogger() << "[ssa form] ";
119 ssaInfo->DumpInsnInSSAForm(*prevInsn);
120 }
121 }
122 }
123 LogInfo::MapleLogger() << "}\n";
124 }
125 if (replacedInsn != nullptr) {
126 LogInfo::MapleLogger() << "======= OldInsn :\n";
127 LogInfo::MapleLogger() << "[primal form] ";
128 replacedInsn->Dump();
129 if (ssaInfo != nullptr) {
130 LogInfo::MapleLogger() << "[ssa form] ";
131 ssaInfo->DumpInsnInSSAForm(*replacedInsn);
132 }
133 }
134 if (newInsn != nullptr) {
135 LogInfo::MapleLogger() << "======= NewInsn :\n";
136 LogInfo::MapleLogger() << "[primal form] ";
137 newInsn->Dump();
138 if (ssaInfo != nullptr) {
139 LogInfo::MapleLogger() << "[ssa form] ";
140 ssaInfo->DumpInsnInSSAForm(*newInsn);
141 }
142 }
143 }
144
145 /* Check if a regOpnd is live after insn. True if live, otherwise false. */
IfOperandIsLiveAfterInsn(const RegOperand & regOpnd,Insn & insn)146 bool CGPeepPattern::IfOperandIsLiveAfterInsn(const RegOperand ®Opnd, Insn &insn)
147 {
148 for (Insn *nextInsn = insn.GetNext(); nextInsn != nullptr; nextInsn = nextInsn->GetNext()) {
149 if (!nextInsn->IsMachineInstruction()) {
150 continue;
151 }
152 int32 lastOpndId = static_cast<int32>(nextInsn->GetOperandSize() - 1);
153 for (int32 i = lastOpndId; i >= 0; --i) {
154 Operand &opnd = nextInsn->GetOperand(static_cast<uint32>(i));
155 if (opnd.IsMemoryAccessOperand()) {
156 auto &mem = static_cast<MemOperand &>(opnd);
157 Operand *base = mem.GetBaseRegister();
158 Operand *offset = mem.GetOffset();
159
160 if (base != nullptr && base->IsRegister()) {
161 auto *tmpRegOpnd = static_cast<RegOperand *>(base);
162 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
163 return true;
164 }
165 }
166 if (offset != nullptr && offset->IsRegister()) {
167 auto *tmpRegOpnd = static_cast<RegOperand *>(offset);
168 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
169 return true;
170 }
171 }
172 } else if (opnd.IsList()) {
173 auto &opndList = static_cast<ListOperand&>(opnd).GetOperands();
174 if (find(opndList.begin(), opndList.end(), ®Opnd) != opndList.end()) {
175 return true;
176 }
177 }
178
179 if (!opnd.IsRegister()) {
180 continue;
181 }
182 auto &tmpRegOpnd = static_cast<RegOperand &>(opnd);
183 if (opnd.IsRegister() && tmpRegOpnd.GetRegisterNumber() != regOpnd.GetRegisterNumber()) {
184 continue;
185 }
186 const InsnDesc *md = nextInsn->GetDesc();
187 auto *regProp = (md->opndMD[static_cast<uint64>(i)]);
188 bool isUse = regProp->IsUse();
189 /* if noUse Redefined, no need to check live-out. */
190 return isUse;
191 }
192 }
193 /* Check if it is live-out. */
194 return FindRegLiveOut(regOpnd, *insn.GetBB());
195 }
196
197 /* entrance for find if a regOpnd is live-out. */
FindRegLiveOut(const RegOperand & regOpnd,const BB & bb)198 bool CGPeepPattern::FindRegLiveOut(const RegOperand ®Opnd, const BB &bb)
199 {
200 /*
201 * Each time use peephole, index is initialized by the constructor,
202 * and the internal_flags3 should be cleared.
203 */
204 if (PeepOptimizer::index == 0) {
205 FOR_ALL_BB(currbb, cgFunc) {
206 currbb->SetInternalFlag3(0);
207 }
208 }
209 /* before each invoke check function, increase index. */
210 ++PeepOptimizer::index;
211 return CheckOpndLiveinSuccs(regOpnd, bb);
212 }
213
214 /* Check regOpnd in succs/ehSuccs. True is live-out, otherwise false. */
CheckOpndLiveinSuccs(const RegOperand & regOpnd,const BB & bb) const215 bool CGPeepPattern::CheckOpndLiveinSuccs(const RegOperand ®Opnd, const BB &bb) const
216 {
217 for (auto succ : bb.GetSuccs()) {
218 DEBUG_ASSERT(succ->GetInternalFlag3() <= PeepOptimizer::index, "internal error.");
219 if (succ->GetInternalFlag3() == PeepOptimizer::index) {
220 continue;
221 }
222 succ->SetInternalFlag3(PeepOptimizer::index);
223 ReturnType result = IsOpndLiveinBB(regOpnd, *succ);
224 if (result == kResNotFind) {
225 if (CheckOpndLiveinSuccs(regOpnd, *succ)) {
226 return true;
227 }
228 continue;
229 } else if (result == kResUseFirst) {
230 return true;
231 } else if (result == kResDefFirst) {
232 continue;
233 }
234 }
235 for (auto ehSucc : bb.GetEhSuccs()) {
236 DEBUG_ASSERT(ehSucc->GetInternalFlag3() <= PeepOptimizer::index, "internal error.");
237 if (ehSucc->GetInternalFlag3() == PeepOptimizer::index) {
238 continue;
239 }
240 ehSucc->SetInternalFlag3(PeepOptimizer::index);
241 ReturnType result = IsOpndLiveinBB(regOpnd, *ehSucc);
242 if (result == kResNotFind) {
243 if (CheckOpndLiveinSuccs(regOpnd, *ehSucc)) {
244 return true;
245 }
246 continue;
247 } else if (result == kResUseFirst) {
248 return true;
249 } else if (result == kResDefFirst) {
250 continue;
251 }
252 }
253 return CheckRegLiveinReturnBB(regOpnd, bb);
254 }
255
256 /* Check if the reg is used in return BB */
CheckRegLiveinReturnBB(const RegOperand & regOpnd,const BB & bb) const257 bool CGPeepPattern::CheckRegLiveinReturnBB(const RegOperand ®Opnd, const BB &bb) const
258 {
259 #if TARGAARCH64 || TARGRISCV64
260 if (bb.GetKind() == BB::kBBReturn) {
261 regno_t regNO = regOpnd.GetRegisterNumber();
262 RegType regType = regOpnd.GetRegisterType();
263 if (regType == kRegTyVary) {
264 return false;
265 }
266 PrimType returnType = cgFunc->GetFunction().GetReturnType()->GetPrimType();
267 regno_t returnReg = R0;
268 if (IsPrimitiveFloat(returnType)) {
269 returnReg = V0;
270 } else if (IsPrimitiveInteger(returnType)) {
271 returnReg = R0;
272 }
273 if (regNO == returnReg) {
274 return true;
275 }
276 }
277 #endif
278 return false;
279 }
280
281 /*
282 * Check regNO in current bb:
283 * kResUseFirst:first find use point; kResDefFirst:first find define point;
284 * kResNotFind:cannot find regNO, need to continue searching.
285 */
IsOpndLiveinBB(const RegOperand & regOpnd,const BB & bb) const286 ReturnType CGPeepPattern::IsOpndLiveinBB(const RegOperand ®Opnd, const BB &bb) const
287 {
288 FOR_BB_INSNS_CONST(insn, &bb) {
289 if (!insn->IsMachineInstruction()) {
290 continue;
291 }
292 const InsnDesc *md = insn->GetDesc();
293 int32 lastOpndId = static_cast<int32>(insn->GetOperandSize() - 1);
294 for (int32 i = lastOpndId; i >= 0; --i) {
295 Operand &opnd = insn->GetOperand(static_cast<uint32>(i));
296 auto *regProp = (md->opndMD[static_cast<uint64>(i)]);
297 if (opnd.IsConditionCode()) {
298 if (regOpnd.GetRegisterNumber() == kRFLAG) {
299 bool isUse = regProp->IsUse();
300 if (isUse) {
301 return kResUseFirst;
302 }
303 DEBUG_ASSERT(regProp->IsDef(), "register should be redefined.");
304 return kResDefFirst;
305 }
306 } else if (opnd.IsList()) {
307 auto &listOpnd = static_cast<ListOperand &>(opnd);
308 if (insn->GetMachineOpcode() == MOP_asm) {
309 if (static_cast<uint32>(i) == kAsmOutputListOpnd || static_cast<uint32>(i) == kAsmClobberListOpnd) {
310 for (auto op : listOpnd.GetOperands()) {
311 if (op->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
312 return kResDefFirst;
313 }
314 }
315 continue;
316 } else if (static_cast<uint32>(i) != kAsmInputListOpnd) {
317 continue;
318 }
319 /* fall thru for kAsmInputListOpnd */
320 }
321 for (auto op : listOpnd.GetOperands()) {
322 if (op->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
323 return kResUseFirst;
324 }
325 }
326 } else if (opnd.IsMemoryAccessOperand()) {
327 auto &mem = static_cast<MemOperand &>(opnd);
328 Operand *base = mem.GetBaseRegister();
329 Operand *offset = mem.GetOffset();
330
331 if (base != nullptr) {
332 DEBUG_ASSERT(base->IsRegister(), "internal error.");
333 auto *tmpRegOpnd = static_cast<RegOperand *>(base);
334 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
335 return kResUseFirst;
336 }
337 }
338 if (offset != nullptr && offset->IsRegister()) {
339 auto *tmpRegOpnd = static_cast<RegOperand *>(offset);
340 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
341 return kResUseFirst;
342 }
343 }
344 } else if (opnd.IsRegister()) {
345 auto &tmpRegOpnd = static_cast<RegOperand &>(opnd);
346 if (tmpRegOpnd.GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
347 bool isUse = regProp->IsUse();
348 if (isUse) {
349 return kResUseFirst;
350 }
351 DEBUG_ASSERT(regProp->IsDef(), "register should be redefined.");
352 return kResDefFirst;
353 }
354 }
355 }
356 }
357 return kResNotFind;
358 }
359
logValueAtBase2(int64 val) const360 int PeepPattern::logValueAtBase2(int64 val) const
361 {
362 return (__builtin_popcountll(static_cast<uint64>(val)) == 1) ? (__builtin_ffsll(val) - 1) : (-1);
363 }
364
365 /* Check if a regOpnd is live after insn. True if live, otherwise false. */
IfOperandIsLiveAfterInsn(const RegOperand & regOpnd,Insn & insn)366 bool PeepPattern::IfOperandIsLiveAfterInsn(const RegOperand ®Opnd, Insn &insn)
367 {
368 for (Insn *nextInsn = insn.GetNext(); nextInsn != nullptr; nextInsn = nextInsn->GetNext()) {
369 if (!nextInsn->IsMachineInstruction()) {
370 continue;
371 }
372 int32 lastOpndId = static_cast<int32>(nextInsn->GetOperandSize() - 1);
373 for (int32 i = lastOpndId; i >= 0; --i) {
374 Operand &opnd = nextInsn->GetOperand(static_cast<uint32>(i));
375 if (opnd.IsMemoryAccessOperand()) {
376 auto &mem = static_cast<MemOperand &>(opnd);
377 Operand *base = mem.GetBaseRegister();
378 Operand *offset = mem.GetOffset();
379
380 if (base != nullptr && base->IsRegister()) {
381 auto *tmpRegOpnd = static_cast<RegOperand *>(base);
382 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
383 return true;
384 }
385 }
386 if (offset != nullptr && offset->IsRegister()) {
387 auto *tmpRegOpnd = static_cast<RegOperand *>(offset);
388 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
389 return true;
390 }
391 }
392 } else if (opnd.IsList()) {
393 auto &opndList = static_cast<ListOperand&>(opnd).GetOperands();
394 if (find(opndList.begin(), opndList.end(), ®Opnd) != opndList.end()) {
395 return true;
396 }
397 }
398
399 if (!opnd.IsRegister()) {
400 continue;
401 }
402 auto &tmpRegOpnd = static_cast<RegOperand &>(opnd);
403 if (opnd.IsRegister() && tmpRegOpnd.GetRegisterNumber() != regOpnd.GetRegisterNumber()) {
404 continue;
405 }
406 const InsnDesc *md = nextInsn->GetDesc();
407 auto *regProp = (md->opndMD[static_cast<uint64>(i)]);
408 bool isUse = regProp->IsUse();
409 /* if noUse Redefined, no need to check live-out. */
410 return isUse;
411 }
412 }
413 /* Check if it is live-out. */
414 return FindRegLiveOut(regOpnd, *insn.GetBB());
415 }
416
417 /* entrance for find if a regOpnd is live-out. */
FindRegLiveOut(const RegOperand & regOpnd,const BB & bb)418 bool PeepPattern::FindRegLiveOut(const RegOperand ®Opnd, const BB &bb)
419 {
420 /*
421 * Each time use peephole, index is initialized by the constructor,
422 * and the internal_flags3 should be cleared.
423 */
424 if (PeepOptimizer::index == 0) {
425 FOR_ALL_BB(currbb, &cgFunc) {
426 currbb->SetInternalFlag3(0);
427 }
428 }
429 /* before each invoke check function, increase index. */
430 ++PeepOptimizer::index;
431 return CheckOpndLiveinSuccs(regOpnd, bb);
432 }
433
434 /* Check regOpnd in succs/ehSuccs. True is live-out, otherwise false. */
CheckOpndLiveinSuccs(const RegOperand & regOpnd,const BB & bb) const435 bool PeepPattern::CheckOpndLiveinSuccs(const RegOperand ®Opnd, const BB &bb) const
436 {
437 for (auto succ : bb.GetSuccs()) {
438 DEBUG_ASSERT(succ->GetInternalFlag3() <= PeepOptimizer::index, "internal error.");
439 if (succ->GetInternalFlag3() == PeepOptimizer::index) {
440 continue;
441 }
442 succ->SetInternalFlag3(PeepOptimizer::index);
443 ReturnType result = IsOpndLiveinBB(regOpnd, *succ);
444 if (result == kResNotFind) {
445 if (CheckOpndLiveinSuccs(regOpnd, *succ)) {
446 return true;
447 }
448 continue;
449 } else if (result == kResUseFirst) {
450 return true;
451 } else if (result == kResDefFirst) {
452 continue;
453 }
454 }
455 for (auto ehSucc : bb.GetEhSuccs()) {
456 DEBUG_ASSERT(ehSucc->GetInternalFlag3() <= PeepOptimizer::index, "internal error.");
457 if (ehSucc->GetInternalFlag3() == PeepOptimizer::index) {
458 continue;
459 }
460 ehSucc->SetInternalFlag3(PeepOptimizer::index);
461 ReturnType result = IsOpndLiveinBB(regOpnd, *ehSucc);
462 if (result == kResNotFind) {
463 if (CheckOpndLiveinSuccs(regOpnd, *ehSucc)) {
464 return true;
465 }
466 continue;
467 } else if (result == kResUseFirst) {
468 return true;
469 } else if (result == kResDefFirst) {
470 continue;
471 }
472 }
473 return CheckRegLiveinReturnBB(regOpnd, bb);
474 }
475
476 /* Check if the reg is used in return BB */
CheckRegLiveinReturnBB(const RegOperand & regOpnd,const BB & bb) const477 bool PeepPattern::CheckRegLiveinReturnBB(const RegOperand ®Opnd, const BB &bb) const
478 {
479 #if TARGAARCH64 || TARGRISCV64
480 if (bb.GetKind() == BB::kBBReturn) {
481 regno_t regNO = regOpnd.GetRegisterNumber();
482 RegType regType = regOpnd.GetRegisterType();
483 if (regType == kRegTyVary) {
484 return false;
485 }
486 PrimType returnType = cgFunc.GetFunction().GetReturnType()->GetPrimType();
487 regno_t returnReg = R0;
488 if (IsPrimitiveFloat(returnType)) {
489 returnReg = V0;
490 } else if (IsPrimitiveInteger(returnType)) {
491 returnReg = R0;
492 }
493 if (regNO == returnReg) {
494 return true;
495 }
496 }
497 #endif
498 return false;
499 }
500
501 /*
502 * Check regNO in current bb:
503 * kResUseFirst:first find use point; kResDefFirst:first find define point;
504 * kResNotFind:cannot find regNO, need to continue searching.
505 */
IsOpndLiveinBB(const RegOperand & regOpnd,const BB & bb) const506 ReturnType PeepPattern::IsOpndLiveinBB(const RegOperand ®Opnd, const BB &bb) const
507 {
508 FOR_BB_INSNS_CONST(insn, &bb) {
509 if (!insn->IsMachineInstruction()) {
510 continue;
511 }
512 const InsnDesc *md = insn->GetDesc();
513 int32 lastOpndId = static_cast<int32>(insn->GetOperandSize() - 1);
514 for (int32 i = lastOpndId; i >= 0; --i) {
515 Operand &opnd = insn->GetOperand(static_cast<uint32>(i));
516 auto *regProp = (md->opndMD[static_cast<uint64>(i)]);
517 if (opnd.IsConditionCode()) {
518 if (regOpnd.GetRegisterNumber() == kRFLAG) {
519 bool isUse = regProp->IsUse();
520 if (isUse) {
521 return kResUseFirst;
522 }
523 DEBUG_ASSERT(regProp->IsDef(), "register should be redefined.");
524 return kResDefFirst;
525 }
526 } else if (opnd.IsList()) {
527 auto &listOpnd = static_cast<ListOperand &>(opnd);
528 if (insn->GetMachineOpcode() == MOP_asm) {
529 if (static_cast<uint32>(i) == kAsmOutputListOpnd || static_cast<uint32>(i) == kAsmClobberListOpnd) {
530 for (auto op : listOpnd.GetOperands()) {
531 if (op->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
532 return kResDefFirst;
533 }
534 }
535 continue;
536 } else if (static_cast<uint32>(i) != kAsmInputListOpnd) {
537 continue;
538 }
539 /* fall thru for kAsmInputListOpnd */
540 }
541 for (auto op : listOpnd.GetOperands()) {
542 if (op->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
543 return kResUseFirst;
544 }
545 }
546 } else if (opnd.IsMemoryAccessOperand()) {
547 auto &mem = static_cast<MemOperand &>(opnd);
548 Operand *base = mem.GetBaseRegister();
549 Operand *offset = mem.GetOffset();
550
551 if (base != nullptr) {
552 DEBUG_ASSERT(base->IsRegister(), "internal error.");
553 auto *tmpRegOpnd = static_cast<RegOperand *>(base);
554 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
555 return kResUseFirst;
556 }
557 }
558 if (offset != nullptr && offset->IsRegister()) {
559 auto *tmpRegOpnd = static_cast<RegOperand *>(offset);
560 if (tmpRegOpnd->GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
561 return kResUseFirst;
562 }
563 }
564 } else if (opnd.IsRegister()) {
565 auto &tmpRegOpnd = static_cast<RegOperand &>(opnd);
566 if (tmpRegOpnd.GetRegisterNumber() == regOpnd.GetRegisterNumber()) {
567 bool isUse = regProp->IsUse();
568 if (isUse) {
569 return kResUseFirst;
570 }
571 DEBUG_ASSERT(regProp->IsDef(), "register should be redefined.");
572 return kResDefFirst;
573 }
574 }
575 }
576 }
577 return kResNotFind;
578 }
579
IsMemOperandOptPattern(const Insn & insn,Insn & nextInsn)580 bool PeepPattern::IsMemOperandOptPattern(const Insn &insn, Insn &nextInsn)
581 {
582 /* Check if base register of nextInsn and the dest operand of insn are identical. */
583 auto *memOpnd = static_cast<MemOperand *>(nextInsn.GetMemOpnd());
584 DEBUG_ASSERT(memOpnd != nullptr, "null ptr check");
585 /* Only for AddrMode_B_OI addressing mode. */
586 if (memOpnd->GetAddrMode() != MemOperand::kAddrModeBOi) {
587 return false;
588 }
589 /* Only for immediate is 0. */
590 if (memOpnd->GetOffsetImmediate()->GetOffsetValue() != 0) {
591 return false;
592 }
593 /* Only for intact memory addressing. */
594 if (!memOpnd->IsIntactIndexed()) {
595 return false;
596 }
597
598 auto &oldBaseOpnd = static_cast<RegOperand &>(insn.GetOperand(kInsnFirstOpnd));
599 /* Check if dest operand of insn is idential with base register of nextInsn. */
600 if (memOpnd->GetBaseRegister() != &oldBaseOpnd) {
601 return false;
602 }
603
604 #ifdef USE_32BIT_REF
605 if (nextInsn.IsAccessRefField() && nextInsn.GetOperand(kInsnFirstOpnd).GetSize() > k32BitSize) {
606 return false;
607 }
608 #endif
609 /* Check if x0 is used after ldr insn, and if it is in live-out. */
610 if (IfOperandIsLiveAfterInsn(oldBaseOpnd, nextInsn)) {
611 return false;
612 }
613 return true;
614 }
615
616 template <typename T>
Run()617 void PeepOptimizer::Run()
618 {
619 auto *patterMatcher = peepOptMemPool->New<T>(cgFunc, peepOptMemPool);
620 patterMatcher->InitOpts();
621 FOR_ALL_BB(bb, &cgFunc) {
622 FOR_BB_INSNS_SAFE(insn, bb, nextInsn) {
623 if (!insn->IsMachineInstruction()) {
624 continue;
625 }
626 patterMatcher->Run(*bb, *insn);
627 }
628 }
629 }
630
631 int32 PeepOptimizer::index = 0;
632
Peephole0()633 void PeepHoleOptimizer::Peephole0()
634 {
635 auto memPool = std::make_unique<ThreadLocalMemPool>(memPoolCtrler, "peepholeOptObj");
636 PeepOptimizer peepOptimizer(*cgFunc, memPool.get());
637 #if TARGAARCH64 || TARGRISCV64
638 peepOptimizer.Run<AArch64PeepHole0>();
639 #endif
640 #if TARGARM32
641 peepOptimizer.Run<Arm32PeepHole0>();
642 #endif
643 }
644
PeepholeOpt()645 void PeepHoleOptimizer::PeepholeOpt()
646 {
647 auto memPool = std::make_unique<ThreadLocalMemPool>(memPoolCtrler, "peepholeOptObj");
648 PeepOptimizer peepOptimizer(*cgFunc, memPool.get());
649 #if TARGAARCH64 || TARGRISCV64
650 peepOptimizer.Run<AArch64PeepHole>();
651 #endif
652 #if TARGARM32
653 peepOptimizer.Run<Arm32PeepHole>();
654 #endif
655 }
656
PrePeepholeOpt()657 void PeepHoleOptimizer::PrePeepholeOpt()
658 {
659 auto memPool = std::make_unique<ThreadLocalMemPool>(memPoolCtrler, "peepholeOptObj");
660 PeepOptimizer peepOptimizer(*cgFunc, memPool.get());
661 #if TARGAARCH64 || TARGRISCV64
662 peepOptimizer.Run<AArch64PrePeepHole>();
663 #endif
664 #if TARGARM32
665 peepOptimizer.Run<Arm32PrePeepHole>();
666 #endif
667 }
668
PrePeepholeOpt1()669 void PeepHoleOptimizer::PrePeepholeOpt1()
670 {
671 auto memPool = std::make_unique<ThreadLocalMemPool>(memPoolCtrler, "peepholeOptObj");
672 PeepOptimizer peepOptimizer(*cgFunc, memPool.get());
673 #if TARGAARCH64 || TARGRISCV64
674 peepOptimizer.Run<AArch64PrePeepHole1>();
675 #endif
676 #if TARGARM32
677 peepOptimizer.Run<Arm32PrePeepHole1>();
678 #endif
679 }
680
681 /* === SSA form === */
PhaseRun(maplebe::CGFunc & f)682 bool CgPeepHole::PhaseRun(maplebe::CGFunc &f)
683 {
684 CGSSAInfo *cgssaInfo = GET_ANALYSIS(CgSSAConstruct, f);
685 CHECK_FATAL((cgssaInfo != nullptr), "Get ssaInfo failed!");
686 MemPool *mp = GetPhaseMemPool();
687 auto *cgpeep = mp->New<AArch64CGPeepHole>(f, mp, cgssaInfo);
688 CHECK_FATAL((cgpeep != nullptr), "Creat AArch64CGPeepHole failed!");
689 cgpeep->Run();
690 return false;
691 }
692
GetAnalysisDependence(AnalysisDep & aDep) const693 void CgPeepHole::GetAnalysisDependence(AnalysisDep &aDep) const
694 {
695 aDep.AddRequired<CgSSAConstruct>();
696 aDep.AddPreserved<CgSSAConstruct>();
697 }
MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPeepHole,cgpeephole)698 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPeepHole, cgpeephole)
699 #endif
700 /* === Physical Pre Form === */
701 bool CgPrePeepHole::PhaseRun(maplebe::CGFunc &f)
702 {
703 MemPool *mp = GetPhaseMemPool();
704 #if defined TARGAARCH64
705 auto *cgpeep = mp->New<AArch64CGPeepHole>(f, mp);
706 #elif defined TARGX86_64
707 auto *cgpeep = mp->New<X64CGPeepHole>(f, mp);
708 #endif
709 CHECK_FATAL(cgpeep != nullptr, "PeepHoleOptimizer instance create failure");
710 cgpeep->Run();
711 return false;
712 }
MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPrePeepHole,cgprepeephole)713 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPrePeepHole, cgprepeephole)
714
715 /* === Physical Post Form === */
716 bool CgPostPeepHole::PhaseRun(maplebe::CGFunc &f)
717 {
718 MemPool *mp = GetPhaseMemPool();
719 #if defined TARGAARCH64
720 auto *cgpeep = mp->New<AArch64CGPeepHole>(f, mp);
721 #elif defined TARGX86_64
722 auto *cgpeep = mp->New<X64CGPeepHole>(f, mp);
723 #endif
724 CHECK_FATAL(cgpeep != nullptr, "PeepHoleOptimizer instance create failure");
725 cgpeep->Run();
726 return false;
727 }
MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPostPeepHole,cgpostpeephole)728 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPostPeepHole, cgpostpeephole)
729
730 #if TARGAARCH64
731 bool CgPrePeepHole0::PhaseRun(maplebe::CGFunc &f)
732 {
733 auto *peep = GetPhaseMemPool()->New<PeepHoleOptimizer>(&f);
734 CHECK_FATAL(peep != nullptr, "PeepHoleOptimizer instance create failure");
735 peep->PrePeepholeOpt();
736 return false;
737 }
MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPrePeepHole0,prepeephole)738 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPrePeepHole0, prepeephole)
739
740 bool CgPrePeepHole1::PhaseRun(maplebe::CGFunc &f)
741 {
742 auto *peep = GetPhaseMemPool()->New<PeepHoleOptimizer>(&f);
743 CHECK_FATAL(peep != nullptr, "PeepHoleOptimizer instance create failure");
744 peep->PrePeepholeOpt1();
745 return false;
746 }
MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPrePeepHole1,prepeephole1)747 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPrePeepHole1, prepeephole1)
748
749 bool CgPeepHole0::PhaseRun(maplebe::CGFunc &f)
750 {
751 auto *peep = GetPhaseMemPool()->New<PeepHoleOptimizer>(&f);
752 CHECK_FATAL(peep != nullptr, "PeepHoleOptimizer instance create failure");
753 peep->Peephole0();
754 return false;
755 }
MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPeepHole0,peephole0)756 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPeepHole0, peephole0)
757
758 bool CgPeepHole1::PhaseRun(maplebe::CGFunc &f)
759 {
760 auto *peep = GetPhaseMemPool()->New<PeepHoleOptimizer>(&f);
761 CHECK_FATAL(peep != nullptr, "PeepHoleOptimizer instance create failure");
762 peep->PeepholeOpt();
763 return false;
764 }
765 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgPeepHole1, peephole)
766 #endif
767
768 } /* namespace maplebe */
769