LLVM 24.0.0git
AArch64InstrInfo.cpp
Go to the documentation of this file.
1//===- AArch64InstrInfo.cpp - AArch64 Instruction Information -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains the AArch64 implementation of the TargetInstrInfo class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "AArch64InstrInfo.h"
14#include "AArch64ExpandImm.h"
16#include "AArch64PointerAuth.h"
17#include "AArch64Subtarget.h"
22#include "llvm/ADT/ArrayRef.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/SmallSet.h"
26#include "llvm/ADT/Statistic.h"
45#include "llvm/IR/DebugLoc.h"
46#include "llvm/IR/GlobalValue.h"
47#include "llvm/IR/Module.h"
48#include "llvm/MC/MCAsmInfo.h"
49#include "llvm/MC/MCInst.h"
51#include "llvm/MC/MCInstrDesc.h"
55#include "llvm/Support/LEB128.h"
59#include <cassert>
60#include <cstdint>
61#include <iterator>
62#include <utility>
63
64using namespace llvm;
65
66#define GET_INSTRINFO_CTOR_DTOR
67#include "AArch64GenInstrInfo.inc"
68
69#define DEBUG_TYPE "AArch64InstrInfo"
70
71STATISTIC(NumCopyInstrs, "Number of COPY instructions expanded");
72STATISTIC(NumZCRegMoveInstrsGPR, "Number of zero-cycle GPR register move "
73 "instructions expanded from canonical COPY");
74STATISTIC(NumZCRegMoveInstrsFPR, "Number of zero-cycle FPR register move "
75 "instructions expanded from canonical COPY");
76STATISTIC(NumZCZeroingInstrsGPR, "Number of zero-cycle GPR zeroing "
77 "instructions expanded from canonical COPY");
78// NumZCZeroingInstrsFPR is counted at AArch64AsmPrinter
79
81 : AArch64GenInstrInfo(STI, RI, AArch64::ADJCALLSTACKDOWN,
82 AArch64::ADJCALLSTACKUP, AArch64::CATCHRET),
83 RI(STI.getTargetTriple(), STI.getHwMode()), Subtarget(STI) {}
84
85/// Return the maximum number of bytes of code the specified instruction may be
86/// after LFI rewriting. If the instruction is not rewritten, std::nullopt is
87/// returned (use default sizing).
88///
89/// NOTE: the size estimates here must be kept in sync with the rewrites in
90/// AArch64MCLFIRewriter.cpp. Sizes may be overestimates of the rewritten
91/// instruction sequences.
92static std::optional<unsigned> getLFIInstSizeInBytes(const MachineInstr &MI) {
93 switch (MI.getOpcode()) {
94 case AArch64::SVC:
95 // SVC expands to 4 instructions.
96 return 16;
97 case AArch64::BR:
98 case AArch64::BLR:
99 // Indirect branches/calls expand to 2 instructions (guard + br/blr).
100 return 8;
101 case AArch64::RET:
102 // RET through another register expands to 2 instructions (guard + ret).
103 // RET through LR may also expand to 2 instructions if a deferred LR guard
104 // is flushed before the return.
105 return 8;
106 case AArch64::RETAA:
107 case AArch64::RETAB:
108 // Authenticated returns expand to 3 instructions (authenticate + guard +
109 // ret).
110 return 12;
111 case AArch64::BRAA:
112 case AArch64::BRAAZ:
113 case AArch64::BRAB:
114 case AArch64::BRABZ:
115 case AArch64::BLRAA:
116 case AArch64::BLRAAZ:
117 case AArch64::BLRAB:
118 case AArch64::BLRABZ:
119 // Authenticated branches/calls expand to 3 instructions (authenticate +
120 // guard + branch).
121 return 12;
122 case AArch64::AUTIASP:
123 case AArch64::AUTIBSP:
124 case AArch64::AUTIAZ:
125 case AArch64::AUTIBZ:
126 case AArch64::XPACLRI:
127 // Authenticating LR expands to the instruction plus a deferred LR guard.
128 return 8;
129 case AArch64::SYSxt:
130 // VA-based DC/IC ops (op1=3, Cn=7, op2=1) expand to 2 instructions.
131 if (MI.getOperand(0).getImm() == 3 && MI.getOperand(1).getImm() == 7 &&
132 MI.getOperand(3).getImm() == 1)
133 return 8;
134 return std::nullopt;
135 default:
136 break;
137 }
138
139 // Detect instructions that explicitly define SP or LR.
140 bool ModifiesLR = false;
141 bool ModifiesSP = false;
142 for (const MachineOperand &MO : MI.defs()) {
143 if (!MO.isReg())
144 continue;
145 if (MO.getReg() == AArch64::LR)
146 ModifiesLR = true;
147 else if (MO.getReg() == AArch64::SP)
148 ModifiesSP = true;
149 }
150
151 // Memory accesses expand to a base-register guard plus the rewritten access
152 // (8 bytes), with an extra base-register update for pre/post-index forms (12
153 // bytes total). If the access also defines LR, an LR mask is appended (+4
154 // bytes). Depending on additional optimizations that the rewriter performs,
155 // this may be an overestimate.
156 if (MI.mayLoadOrStore()) {
157 unsigned Size = isLFIPrePostMemAccess(MI.getOpcode()) ? 12 : 8;
158 if (ModifiesLR)
159 Size += 4;
160 return Size;
161 }
162
163 // Non memory operations that modify LR or SP expand to 2 instructions.
164 if (ModifiesSP || ModifiesLR)
165 return 8;
166
167 // Default case: instructions that don't cause expansion.
168 // - TP accesses in LFI are a single load/store, so no expansion.
169 // - All remaining instructions are not rewritten.
170 return std::nullopt;
171}
172
173/// GetInstSize - Return the number of bytes of code the specified
174/// instruction may be. This returns the maximum number of bytes.
176 const MCInstrDesc &Desc = MI.getDesc();
177 if (!Desc.isPseudo() && !Subtarget.isLFI()) {
178 assert(Desc.getSize() == 4 && "Unexpected instruction size");
179 return 4;
180 }
181
182 const MachineBasicBlock &MBB = *MI.getParent();
183 const MachineFunction *MF = MBB.getParent();
184 const Function &F = MF->getFunction();
185 const MCAsmInfo &MAI = MF->getTarget().getMCAsmInfo();
186
187 {
188 auto Op = MI.getOpcode();
189 if (Op == AArch64::INLINEASM || Op == AArch64::INLINEASM_BR)
190 return getInlineAsmLength(MI.getOperand(0).getSymbolName(), MAI);
191 }
192
193 // Meta-instructions emit no code.
194 if (MI.isMetaInstruction())
195 return 0;
196
197 // FIXME: We currently only handle pseudoinstructions that don't get expanded
198 // before the assembly printer.
199 unsigned NumBytes = 0;
200
201 // LFI rewriter expansions that supersede normal sizing.
202 const auto &STI = MF->getSubtarget<AArch64Subtarget>();
203 if (STI.isLFI())
204 if (auto Size = getLFIInstSizeInBytes(MI))
205 return *Size;
206
207 if (!MI.isBundle() && isTailCallReturnInst(MI)) {
208 NumBytes = Desc.getSize() ? Desc.getSize() : 4;
209
210 const auto *MFI = MF->getInfo<AArch64FunctionInfo>();
211 if (!MFI->shouldSignReturnAddress(*MF))
212 return NumBytes;
213
214 auto Method = STI.getAuthenticatedLRCheckMethod(*MF);
215 NumBytes += AArch64PAuth::getCheckerSizeInBytes(Method);
216 return NumBytes;
217 }
218
219 // Size should be preferably set in
220 // llvm/lib/Target/AArch64/AArch64InstrInfo.td (default case).
221 // Specific cases handle instructions of variable sizes
222 switch (Desc.getOpcode()) {
223 default:
224 if (Desc.getSize())
225 return Desc.getSize();
226
227 // Anything not explicitly designated otherwise (i.e. pseudo-instructions
228 // with fixed constant size but not specified in .td file) is a normal
229 // 4-byte insn.
230 NumBytes = 4;
231 break;
232 case TargetOpcode::STACKMAP:
233 // The upper bound for a stackmap intrinsic is the full length of its shadow
234 NumBytes = StackMapOpers(&MI).getNumPatchBytes();
235 assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
236 break;
237 case TargetOpcode::PATCHPOINT:
238 // The size of the patchpoint intrinsic is the number of bytes requested
239 NumBytes = PatchPointOpers(&MI).getNumPatchBytes();
240 assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
241 break;
242 case TargetOpcode::STATEPOINT:
243 NumBytes = StatepointOpers(&MI).getNumPatchBytes();
244 assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
245 // No patch bytes means a normal call inst is emitted
246 if (NumBytes == 0)
247 NumBytes = 4;
248 break;
249 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
250 // If `patchable-function-entry` is set, PATCHABLE_FUNCTION_ENTER
251 // instructions are expanded to the specified number of NOPs. Otherwise,
252 // they are expanded to 36-byte XRay sleds.
253 NumBytes =
254 F.getFnAttributeAsParsedInteger("patchable-function-entry", 9) * 4;
255 break;
256 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
257 case TargetOpcode::PATCHABLE_TAIL_CALL:
258 case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
259 // An XRay sled can be 4 bytes of alignment plus a 32-byte block.
260 NumBytes = 36;
261 break;
262 case TargetOpcode::PATCHABLE_EVENT_CALL:
263 // EVENT_CALL XRay sleds are exactly 6 instructions long (no alignment).
264 NumBytes = 24;
265 break;
266
267 case AArch64::SPACE:
268 NumBytes = MI.getOperand(1).getImm();
269 break;
270 case AArch64::MOVaddr:
271 case AArch64::MOVaddrJT:
272 case AArch64::MOVaddrCP:
273 case AArch64::MOVaddrBA:
274 case AArch64::MOVaddrTLS:
275 case AArch64::MOVaddrEXT: {
276 // Use the same logic as the pseudo expansion to count instructions.
279 MI.getOperand(1).getTargetFlags(),
280 Subtarget.isTargetMachO(), Insn);
281 NumBytes = Insn.size() * 4;
282 break;
283 }
284
285 case AArch64::MOVi32imm:
286 case AArch64::MOVi64imm: {
287 // Use the same logic as the pseudo expansion to count instructions.
288 unsigned BitSize = Desc.getOpcode() == AArch64::MOVi32imm ? 32 : 64;
290 AArch64_IMM::expandMOVImm(MI.getOperand(1).getImm(), BitSize, Insn);
291 NumBytes = Insn.size() * 4;
292 break;
293 }
294
295 case TargetOpcode::BUNDLE:
296 NumBytes = getInstBundleSize(MI);
297 break;
298 }
299
300 return NumBytes;
301}
302
305 // Block ends with fall-through condbranch.
306 switch (LastInst->getOpcode()) {
307 default:
308 llvm_unreachable("Unknown branch instruction?");
309 case AArch64::Bcc:
310 Target = LastInst->getOperand(1).getMBB();
311 Cond.push_back(LastInst->getOperand(0));
312 break;
313 case AArch64::CBZW:
314 case AArch64::CBZX:
315 case AArch64::CBNZW:
316 case AArch64::CBNZX:
317 Target = LastInst->getOperand(1).getMBB();
318 Cond.push_back(MachineOperand::CreateImm(-1));
319 Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
320 Cond.push_back(LastInst->getOperand(0));
321 break;
322 case AArch64::TBZW:
323 case AArch64::TBZX:
324 case AArch64::TBNZW:
325 case AArch64::TBNZX:
326 Target = LastInst->getOperand(2).getMBB();
327 Cond.push_back(MachineOperand::CreateImm(-1));
328 Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
329 Cond.push_back(LastInst->getOperand(0));
330 Cond.push_back(LastInst->getOperand(1));
331 break;
332 case AArch64::CBWPri:
333 case AArch64::CBXPri:
334 case AArch64::CBWPrr:
335 case AArch64::CBXPrr:
336 Target = LastInst->getOperand(3).getMBB();
337 Cond.push_back(MachineOperand::CreateImm(-1));
338 Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
339 Cond.push_back(LastInst->getOperand(0));
340 Cond.push_back(LastInst->getOperand(1));
341 Cond.push_back(LastInst->getOperand(2));
342 break;
343 case AArch64::CBBAssertExt:
344 case AArch64::CBHAssertExt:
345 Target = LastInst->getOperand(3).getMBB();
346 Cond.push_back(MachineOperand::CreateImm(-1)); // -1
347 Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode())); // Opc
348 Cond.push_back(LastInst->getOperand(0)); // Cond
349 Cond.push_back(LastInst->getOperand(1)); // Op0
350 Cond.push_back(LastInst->getOperand(2)); // Op1
351 Cond.push_back(LastInst->getOperand(4)); // Ext0
352 Cond.push_back(LastInst->getOperand(5)); // Ext1
353 break;
354 }
355}
356
357static unsigned getBranchDisplacementBits(const AArch64Options &CLOpts,
358 unsigned Opc) {
359 switch (Opc) {
360 default:
361 llvm_unreachable("unexpected opcode!");
362 case AArch64::B:
363 return CLOpts.b_offset_bits;
364 case AArch64::TBNZW:
365 case AArch64::TBZW:
366 case AArch64::TBNZX:
367 case AArch64::TBZX:
368 return CLOpts.tbz_offset_bits;
369 case AArch64::CBNZW:
370 case AArch64::CBZW:
371 case AArch64::CBNZX:
372 case AArch64::CBZX:
373 return CLOpts.cbz_offset_bits;
374 case AArch64::Bcc:
375 return CLOpts.bcc_offset_bits;
376 case AArch64::CBWPri:
377 case AArch64::CBXPri:
378 case AArch64::CBBAssertExt:
379 case AArch64::CBHAssertExt:
380 case AArch64::CBWPrr:
381 case AArch64::CBXPrr:
382 return CLOpts.cb_offset_bits;
383 }
384}
385
387 int64_t BrOffset) const {
388 unsigned Bits = getBranchDisplacementBits(Subtarget.getCLOpts(), BranchOp);
389 assert(Bits >= 3 && "max branch displacement must be enough to jump"
390 "over conditional branch expansion");
391 return isIntN(Bits, BrOffset / 4);
392}
393
396 switch (MI.getOpcode()) {
397 default:
398 llvm_unreachable("unexpected opcode!");
399 case AArch64::B:
400 return MI.getOperand(0).getMBB();
401 case AArch64::TBZW:
402 case AArch64::TBNZW:
403 case AArch64::TBZX:
404 case AArch64::TBNZX:
405 return MI.getOperand(2).getMBB();
406 case AArch64::CBZW:
407 case AArch64::CBNZW:
408 case AArch64::CBZX:
409 case AArch64::CBNZX:
410 case AArch64::Bcc:
411 return MI.getOperand(1).getMBB();
412 case AArch64::CBWPri:
413 case AArch64::CBXPri:
414 case AArch64::CBBAssertExt:
415 case AArch64::CBHAssertExt:
416 case AArch64::CBWPrr:
417 case AArch64::CBXPrr:
418 return MI.getOperand(3).getMBB();
419 }
420}
421
423 MachineBasicBlock &NewDestBB,
424 MachineBasicBlock &RestoreBB,
425 const DebugLoc &DL,
426 int64_t BrOffset,
427 RegScavenger *RS) const {
428 assert(RS && "RegScavenger required for long branching");
429 assert(MBB.empty() &&
430 "new block should be inserted for expanding unconditional branch");
431 assert(MBB.pred_size() == 1);
432 assert(RestoreBB.empty() &&
433 "restore block should be inserted for restoring clobbered registers");
434
435 auto buildIndirectBranch = [&](Register Reg, MachineBasicBlock &DestBB) {
436 // Offsets outside of the signed 33-bit range are not supported for ADRP +
437 // ADD.
438 if (!isInt<33>(BrOffset))
440 "Branch offsets outside of the signed 33-bit range not supported");
441
442 BuildMI(MBB, MBB.end(), DL, get(AArch64::ADRP), Reg)
443 .addSym(DestBB.getSymbol(), AArch64II::MO_PAGE);
444 BuildMI(MBB, MBB.end(), DL, get(AArch64::ADDXri), Reg)
445 .addReg(Reg)
446 .addSym(DestBB.getSymbol(), AArch64II::MO_PAGEOFF | AArch64II::MO_NC)
447 .addImm(0);
448 BuildMI(MBB, MBB.end(), DL, get(AArch64::BR)).addReg(Reg);
449 };
450
451 RS->enterBasicBlockEnd(MBB);
452 // If X16 is unused, we can rely on the linker to insert a range extension
453 // thunk if NewDestBB is out of range of a single B instruction.
454 constexpr Register Reg = AArch64::X16;
455 if (!RS->isRegUsed(Reg)) {
456 insertUnconditionalBranch(MBB, &NewDestBB, DL);
457 RS->setRegUsed(Reg);
458 return;
459 }
460
461 // In a cold block without BTI, insert the indirect branch if a register is
462 // free. Skip this if BTI is enabled to avoid inserting a BTI at the target,
463 // prioritizing a dynamic cost in cold code over a static cost in hot code.
464 AArch64FunctionInfo *AFI = MBB.getParent()->getInfo<AArch64FunctionInfo>();
465 bool HasBTI = AFI && AFI->branchTargetEnforcement();
466 if (MBB.getSectionID() == MBBSectionID::ColdSectionID && !HasBTI) {
467 Register Scavenged = RS->FindUnusedReg(&AArch64::GPR64RegClass);
468 if (Scavenged.isValid()) {
469 buildIndirectBranch(Scavenged, NewDestBB);
470 RS->setRegUsed(Scavenged);
471 return;
472 }
473 }
474
475 // Note: Spilling X16 briefly moves the stack pointer, making it incompatible
476 // with red zones.
477 if (!AFI || AFI->hasRedZone().value_or(true))
479 "Unable to insert indirect branch inside function that has red zone");
480
481 // Otherwise, spill X16 and defer range extension to the linker.
482 BuildMI(MBB, MBB.end(), DL, get(AArch64::STRXpre))
483 .addReg(AArch64::SP, RegState::Define)
484 .addReg(Reg)
485 .addReg(AArch64::SP)
486 .addImm(-16);
487
488 BuildMI(MBB, MBB.end(), DL, get(AArch64::B)).addMBB(&RestoreBB);
489
490 BuildMI(RestoreBB, RestoreBB.end(), DL, get(AArch64::LDRXpost))
491 .addReg(AArch64::SP, RegState::Define)
493 .addReg(AArch64::SP)
494 .addImm(16);
495}
496
497// Branch analysis.
500 MachineBasicBlock *&FBB,
502 bool AllowModify) const {
503 // If the block has no terminators, it just falls into the block after it.
504 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
505 if (I == MBB.end())
506 return false;
507
508 // Skip over SpeculationBarrierEndBB terminators
509 if (I->getOpcode() == AArch64::SpeculationBarrierISBDSBEndBB ||
510 I->getOpcode() == AArch64::SpeculationBarrierSBEndBB) {
511 --I;
512 }
513
514 if (!isUnpredicatedTerminator(*I))
515 return false;
516
517 // Get the last instruction in the block.
518 MachineInstr *LastInst = &*I;
519
520 // If there is only one terminator instruction, process it.
521 unsigned LastOpc = LastInst->getOpcode();
522 if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
523 if (isUncondBranchOpcode(LastOpc)) {
524 TBB = LastInst->getOperand(0).getMBB();
525 return false;
526 }
527 if (isCondBranchOpcode(LastOpc)) {
528 // Block ends with fall-through condbranch.
529 parseCondBranch(LastInst, TBB, Cond);
530 return false;
531 }
532 return true; // Can't handle indirect branch.
533 }
534
535 // Get the instruction before it if it is a terminator.
536 MachineInstr *SecondLastInst = &*I;
537 unsigned SecondLastOpc = SecondLastInst->getOpcode();
538
539 // If AllowModify is true and the block ends with two or more unconditional
540 // branches, delete all but the first unconditional branch.
541 if (AllowModify && isUncondBranchOpcode(LastOpc)) {
542 while (isUncondBranchOpcode(SecondLastOpc)) {
543 LastInst->eraseFromParent();
544 LastInst = SecondLastInst;
545 LastOpc = LastInst->getOpcode();
546 if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
547 // Return now the only terminator is an unconditional branch.
548 TBB = LastInst->getOperand(0).getMBB();
549 return false;
550 }
551 SecondLastInst = &*I;
552 SecondLastOpc = SecondLastInst->getOpcode();
553 }
554 }
555
556 // If we're allowed to modify and the block ends in a unconditional branch
557 // which could simply fallthrough, remove the branch. (Note: This case only
558 // matters when we can't understand the whole sequence, otherwise it's also
559 // handled by BranchFolding.cpp.)
560 if (AllowModify && isUncondBranchOpcode(LastOpc) &&
561 MBB.isLayoutSuccessor(getBranchDestBlock(*LastInst))) {
562 LastInst->eraseFromParent();
563 LastInst = SecondLastInst;
564 LastOpc = LastInst->getOpcode();
565 if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
566 assert(!isUncondBranchOpcode(LastOpc) &&
567 "unreachable unconditional branches removed above");
568
569 if (isCondBranchOpcode(LastOpc)) {
570 // Block ends with fall-through condbranch.
571 parseCondBranch(LastInst, TBB, Cond);
572 return false;
573 }
574 return true; // Can't handle indirect branch.
575 }
576 SecondLastInst = &*I;
577 SecondLastOpc = SecondLastInst->getOpcode();
578 }
579
580 // If there are three terminators, we don't know what sort of block this is.
581 if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I))
582 return true;
583
584 // If the block ends with a B and a Bcc, handle it.
585 if (isCondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
586 parseCondBranch(SecondLastInst, TBB, Cond);
587 FBB = LastInst->getOperand(0).getMBB();
588 return false;
589 }
590
591 // If the block ends with two unconditional branches, handle it. The second
592 // one is not executed, so remove it.
593 if (isUncondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
594 TBB = SecondLastInst->getOperand(0).getMBB();
595 I = LastInst;
596 if (AllowModify)
597 I->eraseFromParent();
598 return false;
599 }
600
601 // ...likewise if it ends with an indirect branch followed by an unconditional
602 // branch.
603 if (isIndirectBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
604 I = LastInst;
605 if (AllowModify)
606 I->eraseFromParent();
607 return true;
608 }
609
610 // Otherwise, can't handle this.
611 return true;
612}
613
615 MachineBranchPredicate &MBP,
616 bool AllowModify) const {
617 // Use analyzeBranch to validate the branch pattern.
618 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
620 if (analyzeBranch(MBB, TBB, FBB, Cond, AllowModify))
621 return true;
622
623 // analyzeBranch returns success with empty Cond for unconditional branches.
624 if (Cond.empty())
625 return true;
626
627 MBP.TrueDest = TBB;
628 assert(MBP.TrueDest && "expected!");
629 MBP.FalseDest = FBB ? FBB : MBB.getNextNode();
630
631 MBP.ConditionDef = nullptr;
632 MBP.SingleUseCondition = false;
633
634 // Find the conditional branch. After analyzeBranch succeeds with non-empty
635 // Cond, there's exactly one conditional branch - either last (fallthrough)
636 // or second-to-last (followed by unconditional B).
637 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
638 if (I == MBB.end())
639 return true;
640
641 if (isUncondBranchOpcode(I->getOpcode())) {
642 if (I == MBB.begin())
643 return true;
644 --I;
645 }
646
647 MachineInstr *CondBranch = &*I;
648 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
649
650 switch (CondBranch->getOpcode()) {
651 default:
652 return true;
653
654 case AArch64::Bcc:
655 // Bcc takes the NZCV flag as the operand to branch on, walk up the
656 // instruction stream to find the last instruction to define NZCV.
658 if (MI.modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
659 MBP.ConditionDef = &MI;
660 break;
661 }
662 }
663 return false;
664
665 case AArch64::CBZW:
666 case AArch64::CBZX:
667 case AArch64::CBNZW:
668 case AArch64::CBNZX: {
669 MBP.LHS = CondBranch->getOperand(0);
670 MBP.RHS = MachineOperand::CreateImm(0);
671 unsigned Opc = CondBranch->getOpcode();
672 MBP.Predicate = (Opc == AArch64::CBNZX || Opc == AArch64::CBNZW)
673 ? MachineBranchPredicate::PRED_NE
674 : MachineBranchPredicate::PRED_EQ;
675 Register CondReg = MBP.LHS.getReg();
676 if (CondReg.isVirtual())
677 MBP.ConditionDef = MRI.getVRegDef(CondReg);
678 return false;
679 }
680
681 case AArch64::TBZW:
682 case AArch64::TBZX:
683 case AArch64::TBNZW:
684 case AArch64::TBNZX: {
685 Register CondReg = CondBranch->getOperand(0).getReg();
686 if (CondReg.isVirtual())
687 MBP.ConditionDef = MRI.getVRegDef(CondReg);
688 return false;
689 }
690 }
691}
692
695 if (Cond[0].getImm() != -1) {
696 // Regular Bcc
699 } else {
700 // Folded compare-and-branch
701 switch (Cond[1].getImm()) {
702 default:
703 llvm_unreachable("Unknown conditional branch!");
704 case AArch64::CBZW:
705 Cond[1].setImm(AArch64::CBNZW);
706 break;
707 case AArch64::CBNZW:
708 Cond[1].setImm(AArch64::CBZW);
709 break;
710 case AArch64::CBZX:
711 Cond[1].setImm(AArch64::CBNZX);
712 break;
713 case AArch64::CBNZX:
714 Cond[1].setImm(AArch64::CBZX);
715 break;
716 case AArch64::TBZW:
717 Cond[1].setImm(AArch64::TBNZW);
718 break;
719 case AArch64::TBNZW:
720 Cond[1].setImm(AArch64::TBZW);
721 break;
722 case AArch64::TBZX:
723 Cond[1].setImm(AArch64::TBNZX);
724 break;
725 case AArch64::TBNZX:
726 Cond[1].setImm(AArch64::TBZX);
727 break;
728
729 // Cond is { -1, Opcode, CC, Op0, Op1, ... }
730 case AArch64::CBWPri:
731 case AArch64::CBXPri:
732 case AArch64::CBBAssertExt:
733 case AArch64::CBHAssertExt:
734 case AArch64::CBWPrr:
735 case AArch64::CBXPrr: {
736 // Pseudos using standard 4bit Arm condition codes
738 static_cast<AArch64CC::CondCode>(Cond[2].getImm());
740 }
741 }
742 }
743
744 return false;
745}
746
748 int *BytesRemoved) const {
749 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
750 if (I == MBB.end())
751 return 0;
752
753 if (!isUncondBranchOpcode(I->getOpcode()) &&
754 !isCondBranchOpcode(I->getOpcode()))
755 return 0;
756
757 // Remove the branch.
758 I->eraseFromParent();
759
760 I = MBB.end();
761
762 if (I == MBB.begin()) {
763 if (BytesRemoved)
764 *BytesRemoved = 4;
765 return 1;
766 }
767 --I;
768 if (!isCondBranchOpcode(I->getOpcode())) {
769 if (BytesRemoved)
770 *BytesRemoved = 4;
771 return 1;
772 }
773
774 // Remove the branch.
775 I->eraseFromParent();
776 if (BytesRemoved)
777 *BytesRemoved = 8;
778
779 return 2;
780}
781
782void AArch64InstrInfo::instantiateCondBranch(
785 if (Cond[0].getImm() != -1) {
786 // Regular Bcc
787 BuildMI(&MBB, DL, get(AArch64::Bcc)).addImm(Cond[0].getImm()).addMBB(TBB);
788 } else {
789 // Folded compare-and-branch
790 // Note that we use addOperand instead of addReg to keep the flags.
791
792 // cbz, cbnz
793 const MachineInstrBuilder MIB =
794 BuildMI(&MBB, DL, get(Cond[1].getImm())).add(Cond[2]);
795
796 // tbz/tbnz
797 if (Cond.size() > 3)
798 MIB.add(Cond[3]);
799
800 // cb
801 if (Cond.size() > 4)
802 MIB.add(Cond[4]);
803
804 MIB.addMBB(TBB);
805
806 // cb[b,h]
807 if (Cond.size() > 5) {
808 MIB.addImm(Cond[5].getImm());
809 MIB.addImm(Cond[6].getImm());
810 }
811 }
812}
813
816 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
817 // Shouldn't be a fall through.
818 assert(TBB && "insertBranch must not be told to insert a fallthrough");
819
820 if (!FBB) {
821 if (Cond.empty()) // Unconditional branch?
822 BuildMI(&MBB, DL, get(AArch64::B)).addMBB(TBB);
823 else
824 instantiateCondBranch(MBB, DL, TBB, Cond);
825
826 if (BytesAdded)
827 *BytesAdded = 4;
828
829 return 1;
830 }
831
832 // Two-way conditional branch.
833 instantiateCondBranch(MBB, DL, TBB, Cond);
834 BuildMI(&MBB, DL, get(AArch64::B)).addMBB(FBB);
835
836 if (BytesAdded)
837 *BytesAdded = 8;
838
839 return 2;
840}
841
842#ifndef NDEBUG
844 switch (Ext) {
845 default:
846 return false;
847 case AArch64_AM::UXTB:
848 case AArch64_AM::SXTB:
849 return Opc == AArch64::CBBAssertExt;
850 case AArch64_AM::UXTH:
851 case AArch64_AM::SXTH:
852 return Opc == AArch64::CBHAssertExt;
853 }
854}
855#endif
856
860 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
861
862 // Parse the condition code, see parseCondBranch() above.
864 switch (Cond.size()) {
865 default:
866 llvm_unreachable("Unknown condition opcode in Cond");
867 case 1: // b.cc
869 break;
870 case 3: { // cbz/cbnz
871 // We must insert a compare against 0.
872 bool Is64Bit;
873 switch (Cond[1].getImm()) {
874 default:
875 llvm_unreachable("Unknown branch opcode in Cond");
876 case AArch64::CBZW:
877 Is64Bit = false;
879 break;
880 case AArch64::CBZX:
881 Is64Bit = true;
883 break;
884 case AArch64::CBNZW:
885 Is64Bit = false;
887 break;
888 case AArch64::CBNZX:
889 Is64Bit = true;
891 break;
892 }
893 Register SrcReg = Cond[2].getReg();
894 if (Is64Bit) {
895 // cmp reg, #0 is actually subs xzr, reg, #0.
896 MRI.constrainRegClass(SrcReg, &AArch64::GPR64spRegClass);
897 BuildMI(MBB, MI, DL, get(AArch64::SUBSXri), AArch64::XZR)
898 .addReg(SrcReg)
899 .addImm(0)
900 .addImm(0);
901 } else {
902 MRI.constrainRegClass(SrcReg, &AArch64::GPR32spRegClass);
903 BuildMI(MBB, MI, DL, get(AArch64::SUBSWri), AArch64::WZR)
904 .addReg(SrcReg)
905 .addImm(0)
906 .addImm(0);
907 }
908 } break;
909 case 4: { // tbz/tbnz
910 // We must insert a tst instruction.
911 switch (Cond[1].getImm()) {
912 default:
913 llvm_unreachable("Unknown branch opcode in Cond");
914 case AArch64::TBZW:
915 case AArch64::TBZX:
917 break;
918 case AArch64::TBNZW:
919 case AArch64::TBNZX:
921 break;
922 }
923 // cmp reg, #foo is actually ands xzr, reg, #1<<foo.
924 if (Cond[1].getImm() == AArch64::TBZW || Cond[1].getImm() == AArch64::TBNZW)
925 BuildMI(MBB, MI, DL, get(AArch64::ANDSWri), AArch64::WZR)
926 .addReg(Cond[2].getReg())
927 .addImm(
929 else
930 BuildMI(MBB, MI, DL, get(AArch64::ANDSXri), AArch64::XZR)
931 .addReg(Cond[2].getReg())
932 .addImm(
934 } break;
935 case 5: { // cb
936 // We must insert a cmp, that is a subs
937 // 0 1 2 3 4
938 // Cond is { -1, Opcode, CC, Op0, Op1 }
939 unsigned SubsOpc, SubsDestReg;
940 bool IsImm = false;
941 CC = static_cast<AArch64CC::CondCode>(Cond[2].getImm());
942 switch (Cond[1].getImm()) {
943 default:
944 llvm_unreachable("Unknown branch opcode in Cond");
945 case AArch64::CBWPri:
946 SubsOpc = AArch64::SUBSWri;
947 SubsDestReg = AArch64::WZR;
948 IsImm = true;
949 break;
950 case AArch64::CBXPri:
951 SubsOpc = AArch64::SUBSXri;
952 SubsDestReg = AArch64::XZR;
953 IsImm = true;
954 break;
955 case AArch64::CBWPrr:
956 SubsOpc = AArch64::SUBSWrr;
957 SubsDestReg = AArch64::WZR;
958 IsImm = false;
959 break;
960 case AArch64::CBXPrr:
961 SubsOpc = AArch64::SUBSXrr;
962 SubsDestReg = AArch64::XZR;
963 IsImm = false;
964 break;
965 }
966
967 if (IsImm) {
968 MRI.constrainRegClass(Cond[3].getReg(), getRegClass(get(SubsOpc), 1));
969 BuildMI(MBB, MI, DL, get(SubsOpc), SubsDestReg)
970 .addReg(Cond[3].getReg())
971 .addImm(Cond[4].getImm())
972 .addImm(0);
973 } else {
974 MRI.constrainRegClass(Cond[3].getReg(), getRegClass(get(SubsOpc), 1));
975 MRI.constrainRegClass(Cond[4].getReg(), getRegClass(get(SubsOpc), 2));
976 BuildMI(MBB, MI, DL, get(SubsOpc), SubsDestReg)
977 .addReg(Cond[3].getReg())
978 .addReg(Cond[4].getReg());
979 }
980 } break;
981 case 7: { // cb[b,h]
982 // We must insert a cmp, that is a subs, but also zero- or sign-extensions
983 // that have been folded. For the first operand we codegen an explicit
984 // extension, for the second operand we fold the extension into cmp.
985 // 0 1 2 3 4 5 6
986 // Cond is { -1, Opcode, CC, Op0, Op1, Ext0, Ext1 }
987
988 // We need a new register for the now explicitly extended register
989 Register Reg = Cond[3].getReg();
991 unsigned ExtOpc;
992 unsigned ExtBits;
993 AArch64_AM::ShiftExtendType ExtendType =
995 assert(isValidCBExtend(Cond[1].getImm(), ExtendType) &&
996 "Unexpected compare-and-branch instruction for extend type");
997 switch (ExtendType) {
998 default:
999 llvm_unreachable("Unknown shift-extend for CB instruction");
1000 case AArch64_AM::SXTB:
1001 ExtOpc = AArch64::SBFMWri;
1002 ExtBits = AArch64_AM::encodeLogicalImmediate(0xff, 32);
1003 break;
1004 case AArch64_AM::SXTH:
1005 ExtOpc = AArch64::SBFMWri;
1006 ExtBits = AArch64_AM::encodeLogicalImmediate(0xffff, 32);
1007 break;
1008 case AArch64_AM::UXTB:
1009 ExtOpc = AArch64::ANDWri;
1010 ExtBits = AArch64_AM::encodeLogicalImmediate(0xff, 32);
1011 break;
1012 case AArch64_AM::UXTH:
1013 ExtOpc = AArch64::ANDWri;
1014 ExtBits = AArch64_AM::encodeLogicalImmediate(0xffff, 32);
1015 break;
1016 }
1017
1018 // Build the explicit extension of the first operand
1019 Reg = MRI.createVirtualRegister(&AArch64::GPR32commonRegClass);
1021 BuildMI(MBB, MI, DL, get(ExtOpc), Reg).addReg(Cond[3].getReg());
1022 if (ExtOpc != AArch64::ANDWri)
1023 MBBI.addImm(0);
1024 MBBI.addImm(ExtBits);
1025 }
1026
1027 // Now, subs with an extended second operand
1029 MRI.constrainRegClass(Reg, &AArch64::GPR32commonRegClass);
1030 AArch64_AM::ShiftExtendType ExtendType =
1032 assert(isValidCBExtend(Cond[1].getImm(), ExtendType) &&
1033 "Unexpected compare-and-branch instruction for extend type");
1034 BuildMI(MBB, MI, DL, get(AArch64::SUBSWrx), AArch64::WZR)
1035 .addReg(Reg)
1036 .addReg(Cond[4].getReg())
1037 .addImm(AArch64_AM::getArithExtendImm(ExtendType, 0));
1038 } // If no extension is needed, just a regular subs
1039 else {
1040 BuildMI(MBB, MI, DL, get(AArch64::SUBSWrr), AArch64::WZR)
1041 .addReg(Reg)
1042 .addReg(Cond[4].getReg());
1043 }
1044
1045 CC = static_cast<AArch64CC::CondCode>(Cond[2].getImm());
1046 } break;
1047 }
1048 return CC;
1049}
1050
1052 const TargetInstrInfo &TII) {
1053 for (MachineInstr &MI : MBB->terminators()) {
1054 unsigned Opc = MI.getOpcode();
1055 switch (Opc) {
1056 case AArch64::CBZW:
1057 case AArch64::CBZX:
1058 case AArch64::TBZW:
1059 case AArch64::TBZX:
1060 // CBZ/TBZ with WZR/XZR -> unconditional B
1061 if (MI.getOperand(0).getReg() == AArch64::WZR ||
1062 MI.getOperand(0).getReg() == AArch64::XZR) {
1063 DEBUG_WITH_TYPE("optimizeTerminators",
1064 dbgs() << "Removing always taken branch: " << MI);
1065 MachineBasicBlock *Target = TII.getBranchDestBlock(MI);
1066 SmallVector<MachineBasicBlock *> Succs(MBB->successors());
1067 for (auto *S : Succs)
1068 if (S != Target)
1069 MBB->removeSuccessor(S);
1070 DebugLoc DL = MI.getDebugLoc();
1071 while (MBB->rbegin() != &MI)
1072 MBB->rbegin()->eraseFromParent();
1073 MI.eraseFromParent();
1074 BuildMI(MBB, DL, TII.get(AArch64::B)).addMBB(Target);
1075 return true;
1076 }
1077 break;
1078 case AArch64::CBNZW:
1079 case AArch64::CBNZX:
1080 case AArch64::TBNZW:
1081 case AArch64::TBNZX:
1082 // CBNZ/TBNZ with WZR/XZR -> never taken, remove branch and successor
1083 if (MI.getOperand(0).getReg() == AArch64::WZR ||
1084 MI.getOperand(0).getReg() == AArch64::XZR) {
1085 DEBUG_WITH_TYPE("optimizeTerminators",
1086 dbgs() << "Removing never taken branch: " << MI);
1087 MachineBasicBlock *Target = TII.getBranchDestBlock(MI);
1088 MI.getParent()->removeSuccessor(Target);
1089 MI.eraseFromParent();
1090 return true;
1091 }
1092 break;
1093 }
1094 }
1095 return false;
1096}
1097
1098// Find the original register that VReg is copied from.
1099static unsigned removeCopies(const MachineRegisterInfo &MRI, unsigned VReg) {
1100 while (Register::isVirtualRegister(VReg)) {
1101 const MachineInstr *DefMI = MRI.getVRegDef(VReg);
1102 if (!DefMI || !DefMI->isFullCopy())
1103 return VReg;
1104 VReg = DefMI->getOperand(1).getReg();
1105 }
1106 return VReg;
1107}
1108
1109// Determine if VReg is defined by an instruction that can be folded into a
1110// csel instruction. If so, return the folded opcode, and the replacement
1111// register.
1112static unsigned canFoldIntoCSel(const MachineRegisterInfo &MRI, unsigned VReg,
1113 unsigned *NewReg = nullptr) {
1114 VReg = removeCopies(MRI, VReg);
1115 if (!Register::isVirtualRegister(VReg))
1116 return 0;
1117
1118 bool Is64Bit = AArch64::GPR64allRegClass.hasSubClassEq(MRI.getRegClass(VReg));
1119 const MachineInstr *DefMI = MRI.getVRegDef(VReg);
1120 if (!DefMI)
1121 return 0;
1122 unsigned Opc = 0;
1123 unsigned SrcReg = 0;
1124 switch (DefMI->getOpcode()) {
1125 case AArch64::SUBREG_TO_REG:
1126 // Check for the following way to define an 64-bit immediate:
1127 // %0:gpr32 = MOVi32imm 1
1128 // %1:gpr64 = SUBREG_TO_REG %0:gpr32, %subreg.sub_32
1129 if (!DefMI->getOperand(1).isReg())
1130 return 0;
1131 if (!DefMI->getOperand(2).isImm() ||
1132 DefMI->getOperand(2).getImm() != AArch64::sub_32)
1133 return 0;
1134 DefMI = MRI.getVRegDef(DefMI->getOperand(1).getReg());
1135 if (DefMI->getOpcode() != AArch64::MOVi32imm)
1136 return 0;
1137 if (!DefMI->getOperand(1).isImm() || DefMI->getOperand(1).getImm() != 1)
1138 return 0;
1139 assert(Is64Bit);
1140 SrcReg = AArch64::XZR;
1141 Opc = AArch64::CSINCXr;
1142 break;
1143
1144 case AArch64::MOVi32imm:
1145 case AArch64::MOVi64imm:
1146 if (!DefMI->getOperand(1).isImm() || DefMI->getOperand(1).getImm() != 1)
1147 return 0;
1148 SrcReg = Is64Bit ? AArch64::XZR : AArch64::WZR;
1149 Opc = Is64Bit ? AArch64::CSINCXr : AArch64::CSINCWr;
1150 break;
1151
1152 case AArch64::ADDSXri:
1153 case AArch64::ADDSWri:
1154 // if NZCV is used, do not fold.
1155 if (DefMI->findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr,
1156 true) == -1)
1157 return 0;
1158 // fall-through to ADDXri and ADDWri.
1159 [[fallthrough]];
1160 case AArch64::ADDXri:
1161 case AArch64::ADDWri:
1162 // add x, 1 -> csinc.
1163 if (!DefMI->getOperand(2).isImm() || DefMI->getOperand(2).getImm() != 1 ||
1164 DefMI->getOperand(3).getImm() != 0)
1165 return 0;
1166 SrcReg = DefMI->getOperand(1).getReg();
1167 Opc = Is64Bit ? AArch64::CSINCXr : AArch64::CSINCWr;
1168 break;
1169
1170 case AArch64::ORNXrr:
1171 case AArch64::ORNWrr: {
1172 // not x -> csinv, represented as orn dst, xzr, src.
1173 unsigned ZReg = removeCopies(MRI, DefMI->getOperand(1).getReg());
1174 if (ZReg != AArch64::XZR && ZReg != AArch64::WZR)
1175 return 0;
1176 SrcReg = DefMI->getOperand(2).getReg();
1177 Opc = Is64Bit ? AArch64::CSINVXr : AArch64::CSINVWr;
1178 break;
1179 }
1180
1181 case AArch64::SUBSXrr:
1182 case AArch64::SUBSWrr:
1183 // if NZCV is used, do not fold.
1184 if (DefMI->findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr,
1185 true) == -1)
1186 return 0;
1187 // fall-through to SUBXrr and SUBWrr.
1188 [[fallthrough]];
1189 case AArch64::SUBXrr:
1190 case AArch64::SUBWrr: {
1191 // neg x -> csneg, represented as sub dst, xzr, src.
1192 unsigned ZReg = removeCopies(MRI, DefMI->getOperand(1).getReg());
1193 if (ZReg != AArch64::XZR && ZReg != AArch64::WZR)
1194 return 0;
1195 SrcReg = DefMI->getOperand(2).getReg();
1196 Opc = Is64Bit ? AArch64::CSNEGXr : AArch64::CSNEGWr;
1197 break;
1198 }
1199 default:
1200 return 0;
1201 }
1202 assert(Opc && SrcReg && "Missing parameters");
1203
1204 if (NewReg)
1205 *NewReg = SrcReg;
1206 return Opc;
1207}
1208
1211 Register DstReg, Register TrueReg,
1212 Register FalseReg,
1213 SelectExpansion &Exp) const {
1214 // Check register classes.
1215 const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
1216 const TargetRegisterClass *RC =
1217 RI.getCommonSubClass(MRI.getRegClass(TrueReg), MRI.getRegClass(FalseReg));
1218 if (!RC)
1219 return false;
1220
1221 // Also need to check the dest regclass, in case we're trying to optimize
1222 // something like:
1223 // %1(gpr) = PHI %2(fpr), bb1, %(fpr), bb2
1224 if (!RI.getCommonSubClass(RC, MRI.getRegClass(DstReg)))
1225 return false;
1226
1227 // Expanding cbz/tbz requires a flag setting instruction in addition to the
1228 // select, adding an extra cycle of latency on the condition.
1229 unsigned ExtraCondLat = Cond.size() != 1;
1230 Exp.NumInsts = 1 + ExtraCondLat;
1231 if (ExtraCondLat)
1232 Exp.ClobberedPhysRegs.push_back(AArch64::NZCV);
1233
1234 // GPRs are handled by csel.
1235 // FIXME: Fold in x+1, -x, and ~x when applicable.
1236 if (AArch64::GPR64allRegClass.hasSubClassEq(RC) ||
1237 AArch64::GPR32allRegClass.hasSubClassEq(RC)) {
1238 // Single-cycle csel, csinc, csinv, and csneg.
1239 Exp.CondCycles = 1 + ExtraCondLat;
1240 Exp.TrueCycles = Exp.FalseCycles = 1;
1241 if (canFoldIntoCSel(MRI, TrueReg))
1242 Exp.TrueCycles = 0;
1243 else if (canFoldIntoCSel(MRI, FalseReg))
1244 Exp.FalseCycles = 0;
1245 return true;
1246 }
1247
1248 // Scalar floating point is handled by fcsel.
1249 // FIXME: Form fabs, fmin, and fmax when applicable.
1250 if (AArch64::FPR64RegClass.hasSubClassEq(RC) ||
1251 AArch64::FPR32RegClass.hasSubClassEq(RC)) {
1252 Exp.CondCycles = 5 + ExtraCondLat;
1253 Exp.TrueCycles = Exp.FalseCycles = 2;
1254 return true;
1255 }
1256
1257 // No single conditional move for a 128-bit vector, but we can emit a sequence
1258 // of csetm (~1), dup (~5, cross domain), bsl (~2).
1259 if (AArch64::FPR128RegClass.hasSubClassEq(RC) &&
1260 Subtarget.isNeonAvailable() &&
1261 !MBB.getParent()->getFunction().hasMinSize()) {
1262 Exp.CondCycles = 8 + ExtraCondLat;
1263 Exp.TrueCycles = Exp.FalseCycles = 2;
1264 Exp.NumInsts = 3 + ExtraCondLat;
1265 return true;
1266 }
1267
1268 return false;
1269}
1270
1273 const DebugLoc &DL, Register DstReg,
1275 Register TrueReg, Register FalseReg) const {
1276
1277 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
1279
1280 // A 128-bit vector has no conditional move so blend the operands with a mask
1281 // built from the flags.
1282 if (MRI.constrainRegClass(DstReg, &AArch64::FPR128RegClass)) {
1283 assert(Subtarget.isNeonAvailable() && "Expected NEON for a vector select");
1284 MRI.constrainRegClass(TrueReg, &AArch64::FPR128RegClass);
1285 MRI.constrainRegClass(FalseReg, &AArch64::FPR128RegClass);
1286 Register CondSet = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
1287 BuildMI(MBB, I, DL, get(AArch64::CSINVXr), CondSet)
1288 .addReg(AArch64::XZR)
1289 .addReg(AArch64::XZR)
1291 Register Mask = MRI.createVirtualRegister(&AArch64::FPR128RegClass);
1292 BuildMI(MBB, I, DL, get(AArch64::DUPv2i64gpr), Mask).addReg(CondSet);
1293 BuildMI(MBB, I, DL, get(AArch64::BSPv16i8), DstReg)
1294 .addReg(Mask)
1295 .addReg(TrueReg)
1296 .addReg(FalseReg);
1297 return;
1298 }
1299
1300 unsigned Opc = 0;
1301 const TargetRegisterClass *RC = nullptr;
1302 bool TryFold = false;
1303 if (MRI.constrainRegClass(DstReg, &AArch64::GPR64RegClass)) {
1304 RC = &AArch64::GPR64RegClass;
1305 Opc = AArch64::CSELXr;
1306 TryFold = true;
1307 } else if (MRI.constrainRegClass(DstReg, &AArch64::GPR32RegClass)) {
1308 RC = &AArch64::GPR32RegClass;
1309 Opc = AArch64::CSELWr;
1310 TryFold = true;
1311 } else if (MRI.constrainRegClass(DstReg, &AArch64::FPR64RegClass)) {
1312 RC = &AArch64::FPR64RegClass;
1313 Opc = AArch64::FCSELDrrr;
1314 } else if (MRI.constrainRegClass(DstReg, &AArch64::FPR32RegClass)) {
1315 RC = &AArch64::FPR32RegClass;
1316 Opc = AArch64::FCSELSrrr;
1317 }
1318 assert(RC && "Unsupported regclass");
1319
1320 // Try folding simple instructions into the csel.
1321 if (TryFold) {
1322 unsigned NewReg = 0;
1323 unsigned FoldedOpc = canFoldIntoCSel(MRI, TrueReg, &NewReg);
1324 if (FoldedOpc) {
1325 // The folded opcodes csinc, csinc and csneg apply the operation to
1326 // FalseReg, so we need to invert the condition.
1328 TrueReg = FalseReg;
1329 } else
1330 FoldedOpc = canFoldIntoCSel(MRI, FalseReg, &NewReg);
1331
1332 // Fold the operation. Leave any dead instructions for DCE to clean up.
1333 if (FoldedOpc) {
1334 FalseReg = NewReg;
1335 Opc = FoldedOpc;
1336 // Extend the live range of NewReg.
1337 MRI.clearKillFlags(NewReg);
1338 }
1339 }
1340
1341 // Pull all virtual register into the appropriate class.
1342 MRI.constrainRegClass(TrueReg, RC);
1343 // FalseReg might be WZR or XZR if the folded operand is a literal 1.
1344 assert(
1345 (FalseReg.isVirtual() || FalseReg == AArch64::WZR ||
1346 FalseReg == AArch64::XZR) &&
1347 "FalseReg was folded into a non-virtual register other than WZR or XZR");
1348 if (FalseReg.isVirtual())
1349 MRI.constrainRegClass(FalseReg, RC);
1350
1351 // Insert the csel.
1352 BuildMI(MBB, I, DL, get(Opc), DstReg)
1353 .addReg(TrueReg)
1354 .addReg(FalseReg)
1355 .addImm(CC);
1356}
1357
1358// Return true if Imm can be loaded into a register by a "cheap" sequence of
1359// instructions. For now, "cheap" means at most two instructions.
1360static bool isCheapImmediate(const MachineInstr &MI, unsigned BitSize) {
1361 if (BitSize == 32)
1362 return true;
1363
1364 assert(BitSize == 64 && "Only bit sizes of 32 or 64 allowed");
1365 uint64_t Imm = static_cast<uint64_t>(MI.getOperand(1).getImm());
1367 AArch64_IMM::expandMOVImm(Imm, BitSize, Is);
1368
1369 return Is.size() <= 2;
1370}
1371
1372// Check if a COPY instruction is cheap.
1373static bool isCheapCopy(const MachineInstr &MI, const AArch64RegisterInfo &RI) {
1374 assert(MI.isCopy() && "Expected COPY instruction");
1375 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1376
1377 // Cross-bank copies (e.g., between GPR and FPR) are expensive on AArch64,
1378 // typically requiring an FMOV instruction with a 2-6 cycle latency.
1379 auto GetRegClass = [&](Register Reg) -> const TargetRegisterClass * {
1380 if (Reg.isVirtual())
1381 return MRI.getRegClass(Reg);
1382 if (Reg.isPhysical())
1383 return RI.getMinimalPhysRegClass(Reg);
1384 return nullptr;
1385 };
1386 const TargetRegisterClass *DstRC = GetRegClass(MI.getOperand(0).getReg());
1387 const TargetRegisterClass *SrcRC = GetRegClass(MI.getOperand(1).getReg());
1388 if (DstRC && SrcRC && !RI.getCommonSubClass(DstRC, SrcRC))
1389 return false;
1390
1391 return MI.isAsCheapAsAMove();
1392}
1393
1394// FIXME: this implementation should be micro-architecture dependent, so a
1395// micro-architecture target hook should be introduced here in future.
1397 if (Subtarget.hasExynosCheapAsMoveHandling()) {
1398 if (isExynosCheapAsMove(MI))
1399 return true;
1400 return MI.isAsCheapAsAMove();
1401 }
1402
1403 switch (MI.getOpcode()) {
1404 default:
1405 return MI.isAsCheapAsAMove();
1406
1407 case TargetOpcode::COPY:
1408 return isCheapCopy(MI, RI);
1409
1410 case AArch64::ADDWrs:
1411 case AArch64::ADDXrs:
1412 case AArch64::SUBWrs:
1413 case AArch64::SUBXrs:
1414 return Subtarget.hasALULSLFast() && MI.getOperand(3).getImm() <= 4;
1415
1416 // If MOVi32imm or MOVi64imm can be expanded into ORRWri or
1417 // ORRXri, it is as cheap as MOV.
1418 // Likewise if it can be expanded to MOVZ/MOVN/MOVK.
1419 case AArch64::MOVi32imm:
1420 return isCheapImmediate(MI, 32);
1421 case AArch64::MOVi64imm:
1422 return isCheapImmediate(MI, 64);
1423 }
1424}
1425
1426bool AArch64InstrInfo::isFalkorShiftExtFast(const MachineInstr &MI) {
1427 switch (MI.getOpcode()) {
1428 default:
1429 return false;
1430
1431 case AArch64::ADDWrs:
1432 case AArch64::ADDXrs:
1433 case AArch64::ADDSWrs:
1434 case AArch64::ADDSXrs: {
1435 unsigned Imm = MI.getOperand(3).getImm();
1436 unsigned ShiftVal = AArch64_AM::getShiftValue(Imm);
1437 if (ShiftVal == 0)
1438 return true;
1439 return AArch64_AM::getShiftType(Imm) == AArch64_AM::LSL && ShiftVal <= 5;
1440 }
1441
1442 case AArch64::ADDWrx:
1443 case AArch64::ADDXrx:
1444 case AArch64::ADDXrx64:
1445 case AArch64::ADDSWrx:
1446 case AArch64::ADDSXrx:
1447 case AArch64::ADDSXrx64: {
1448 unsigned Imm = MI.getOperand(3).getImm();
1450 default:
1451 return false;
1452 case AArch64_AM::UXTB:
1453 case AArch64_AM::UXTH:
1454 case AArch64_AM::UXTW:
1455 case AArch64_AM::UXTX:
1457 }
1458 }
1459
1460 case AArch64::SUBWrs:
1461 case AArch64::SUBSWrs: {
1462 unsigned Imm = MI.getOperand(3).getImm();
1463 unsigned ShiftVal = AArch64_AM::getShiftValue(Imm);
1464 return ShiftVal == 0 ||
1465 (AArch64_AM::getShiftType(Imm) == AArch64_AM::ASR && ShiftVal == 31);
1466 }
1467
1468 case AArch64::SUBXrs:
1469 case AArch64::SUBSXrs: {
1470 unsigned Imm = MI.getOperand(3).getImm();
1471 unsigned ShiftVal = AArch64_AM::getShiftValue(Imm);
1472 return ShiftVal == 0 ||
1473 (AArch64_AM::getShiftType(Imm) == AArch64_AM::ASR && ShiftVal == 63);
1474 }
1475
1476 case AArch64::SUBWrx:
1477 case AArch64::SUBXrx:
1478 case AArch64::SUBXrx64:
1479 case AArch64::SUBSWrx:
1480 case AArch64::SUBSXrx:
1481 case AArch64::SUBSXrx64: {
1482 unsigned Imm = MI.getOperand(3).getImm();
1484 default:
1485 return false;
1486 case AArch64_AM::UXTB:
1487 case AArch64_AM::UXTH:
1488 case AArch64_AM::UXTW:
1489 case AArch64_AM::UXTX:
1491 }
1492 }
1493
1494 case AArch64::LDRBBroW:
1495 case AArch64::LDRBBroX:
1496 case AArch64::LDRBroW:
1497 case AArch64::LDRBroX:
1498 case AArch64::LDRDroW:
1499 case AArch64::LDRDroX:
1500 case AArch64::LDRHHroW:
1501 case AArch64::LDRHHroX:
1502 case AArch64::LDRHroW:
1503 case AArch64::LDRHroX:
1504 case AArch64::LDRQroW:
1505 case AArch64::LDRQroX:
1506 case AArch64::LDRSBWroW:
1507 case AArch64::LDRSBWroX:
1508 case AArch64::LDRSBXroW:
1509 case AArch64::LDRSBXroX:
1510 case AArch64::LDRSHWroW:
1511 case AArch64::LDRSHWroX:
1512 case AArch64::LDRSHXroW:
1513 case AArch64::LDRSHXroX:
1514 case AArch64::LDRSWroW:
1515 case AArch64::LDRSWroX:
1516 case AArch64::LDRSroW:
1517 case AArch64::LDRSroX:
1518 case AArch64::LDRWroW:
1519 case AArch64::LDRWroX:
1520 case AArch64::LDRXroW:
1521 case AArch64::LDRXroX:
1522 case AArch64::PRFMroW:
1523 case AArch64::PRFMroX:
1524 case AArch64::STRBBroW:
1525 case AArch64::STRBBroX:
1526 case AArch64::STRBroW:
1527 case AArch64::STRBroX:
1528 case AArch64::STRDroW:
1529 case AArch64::STRDroX:
1530 case AArch64::STRHHroW:
1531 case AArch64::STRHHroX:
1532 case AArch64::STRHroW:
1533 case AArch64::STRHroX:
1534 case AArch64::STRQroW:
1535 case AArch64::STRQroX:
1536 case AArch64::STRSroW:
1537 case AArch64::STRSroX:
1538 case AArch64::STRWroW:
1539 case AArch64::STRWroX:
1540 case AArch64::STRXroW:
1541 case AArch64::STRXroX: {
1542 unsigned IsSigned = MI.getOperand(3).getImm();
1543 return !IsSigned;
1544 }
1545 }
1546}
1547
1548bool AArch64InstrInfo::isSEHInstruction(const MachineInstr &MI) {
1549 unsigned Opc = MI.getOpcode();
1550 switch (Opc) {
1551 default:
1552 return false;
1553 case AArch64::SEH_EndC:
1554 case AArch64::SEH_StackAlloc:
1555 case AArch64::SEH_SaveFPLR:
1556 case AArch64::SEH_SaveFPLR_X:
1557 case AArch64::SEH_SaveReg:
1558 case AArch64::SEH_SaveReg_X:
1559 case AArch64::SEH_SaveRegP:
1560 case AArch64::SEH_SaveRegP_X:
1561 case AArch64::SEH_SaveFReg:
1562 case AArch64::SEH_SaveFReg_X:
1563 case AArch64::SEH_SaveFRegP:
1564 case AArch64::SEH_SaveFRegP_X:
1565 case AArch64::SEH_SetFP:
1566 case AArch64::SEH_AddFP:
1567 case AArch64::SEH_Nop:
1568 case AArch64::SEH_PrologEnd:
1569 case AArch64::SEH_EpilogStart:
1570 case AArch64::SEH_EpilogEnd:
1571 case AArch64::SEH_PACSignLR:
1572 case AArch64::SEH_SaveAnyRegI:
1573 case AArch64::SEH_SaveAnyRegIP:
1574 case AArch64::SEH_SaveAnyRegQ:
1575 case AArch64::SEH_SaveAnyRegQX:
1576 case AArch64::SEH_SaveAnyRegQP:
1577 case AArch64::SEH_SaveAnyRegQPX:
1578 case AArch64::SEH_AllocZ:
1579 case AArch64::SEH_SaveZReg:
1580 case AArch64::SEH_SavePReg:
1581 return true;
1582 }
1583}
1584
1586 Register &SrcReg, Register &DstReg,
1587 unsigned &SubIdx) const {
1588 switch (MI.getOpcode()) {
1589 default:
1590 return false;
1591 case AArch64::SBFMXri: // aka sxtw
1592 case AArch64::UBFMXri: // aka uxtw
1593 // Check for the 32 -> 64 bit extension case, these instructions can do
1594 // much more.
1595 if (MI.getOperand(2).getImm() != 0 || MI.getOperand(3).getImm() != 31)
1596 return false;
1597 // This is a signed or unsigned 32 -> 64 bit extension.
1598 SrcReg = MI.getOperand(1).getReg();
1599 DstReg = MI.getOperand(0).getReg();
1600 SubIdx = AArch64::sub_32;
1601 return true;
1602 }
1603}
1604
1606 const MachineInstr &MIa, const MachineInstr &MIb) const {
1607 const MachineOperand *BaseOpA = nullptr, *BaseOpB = nullptr;
1608 int64_t OffsetA = 0, OffsetB = 0;
1609 TypeSize WidthA(0, false), WidthB(0, false);
1610 bool OffsetAIsScalable = false, OffsetBIsScalable = false;
1611
1612 assert(MIa.mayLoadOrStore() && "MIa must be a load or store.");
1613 assert(MIb.mayLoadOrStore() && "MIb must be a load or store.");
1614
1617 return false;
1618
1619 // Retrieve the base, offset from the base and width. Width
1620 // is the size of memory that is being loaded/stored (e.g. 1, 2, 4, 8). If
1621 // base are identical, and the offset of a lower memory access +
1622 // the width doesn't overlap the offset of a higher memory access,
1623 // then the memory accesses are different.
1624 // If OffsetAIsScalable and OffsetBIsScalable are both true, they
1625 // are assumed to have the same scale (vscale).
1626 if (getMemOperandWithOffsetWidth(MIa, BaseOpA, OffsetA, OffsetAIsScalable,
1627 WidthA) &&
1628 getMemOperandWithOffsetWidth(MIb, BaseOpB, OffsetB, OffsetBIsScalable,
1629 WidthB)) {
1630 if (BaseOpA->isIdenticalTo(*BaseOpB) &&
1631 OffsetAIsScalable == OffsetBIsScalable) {
1632 int LowOffset = OffsetA < OffsetB ? OffsetA : OffsetB;
1633 int HighOffset = OffsetA < OffsetB ? OffsetB : OffsetA;
1634 TypeSize LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB;
1635 if (LowWidth.isScalable() == OffsetAIsScalable &&
1636 LowOffset + (int)LowWidth.getKnownMinValue() <= HighOffset)
1637 return true;
1638 }
1639 }
1640 return false;
1641}
1642
1644 const MachineBasicBlock *MBB,
1645 const MachineFunction &MF) const {
1647 return true;
1648
1649 // Do not move an instruction that can be recognized as a branch target.
1650 if (hasBTISemantics(MI))
1651 return true;
1652
1653 switch (MI.getOpcode()) {
1654 case AArch64::HINT:
1655 // CSDB hints are scheduling barriers.
1656 if (MI.getOperand(0).getImm() == 0x14)
1657 return true;
1658 break;
1659 case AArch64::DSB:
1660 case AArch64::ISB:
1661 // DSB and ISB also are scheduling barriers.
1662 return true;
1663 case AArch64::MSRpstatesvcrImm1:
1664 // SMSTART and SMSTOP are also scheduling barriers.
1665 return true;
1666 default:;
1667 }
1668 if (isSEHInstruction(MI))
1669 return true;
1670 // Skip debug instructions and pseudo probes so they do not change
1671 // scheduling regions.
1672 auto Next = next_nodbg(MI.getIterator(), MBB->instr_end());
1673 return Next != MBB->instr_end() && Next->isCFIInstruction();
1674}
1675
1676/// analyzeCompare - For a comparison instruction, return the source registers
1677/// in SrcReg and SrcReg2, and the value it compares against in CmpValue.
1678/// Return true if the comparison instruction can be analyzed.
1680 Register &SrcReg2, int64_t &CmpMask,
1681 int64_t &CmpValue) const {
1682 // The first operand can be a frame index where we'd normally expect a
1683 // register.
1684 // FIXME: Pass subregisters out of analyzeCompare
1685 assert(MI.getNumOperands() >= 2 && "All AArch64 cmps should have 2 operands");
1686 if (!MI.getOperand(1).isReg() || MI.getOperand(1).getSubReg())
1687 return false;
1688
1689 switch (MI.getOpcode()) {
1690 default:
1691 break;
1692 case AArch64::PTEST_PP:
1693 case AArch64::PTEST_PP_ANY:
1694 case AArch64::PTEST_PP_FIRST:
1695 SrcReg = MI.getOperand(0).getReg();
1696 SrcReg2 = MI.getOperand(1).getReg();
1697 if (MI.getOperand(2).getSubReg())
1698 return false;
1699
1700 // Not sure about the mask and value for now...
1701 CmpMask = ~0;
1702 CmpValue = 0;
1703 return true;
1704 case AArch64::SUBSWrr:
1705 case AArch64::SUBSWrs:
1706 case AArch64::SUBSWrx:
1707 case AArch64::SUBSXrr:
1708 case AArch64::SUBSXrs:
1709 case AArch64::SUBSXrx:
1710 case AArch64::ADDSWrr:
1711 case AArch64::ADDSWrs:
1712 case AArch64::ADDSWrx:
1713 case AArch64::ADDSXrr:
1714 case AArch64::ADDSXrs:
1715 case AArch64::ADDSXrx:
1716 // Replace SUBSWrr with SUBWrr if NZCV is not used.
1717 SrcReg = MI.getOperand(1).getReg();
1718 SrcReg2 = MI.getOperand(2).getReg();
1719
1720 // FIXME: Pass subregisters out of analyzeCompare
1721 if (MI.getOperand(2).getSubReg())
1722 return false;
1723
1724 CmpMask = ~0;
1725 CmpValue = 0;
1726 return true;
1727 case AArch64::SUBSWri:
1728 case AArch64::ADDSWri:
1729 case AArch64::SUBSXri:
1730 case AArch64::ADDSXri:
1731 SrcReg = MI.getOperand(1).getReg();
1732 SrcReg2 = 0;
1733 CmpMask = ~0;
1734 CmpValue = MI.getOperand(2).getImm();
1735 return true;
1736 case AArch64::ANDSWri:
1737 case AArch64::ANDSXri:
1738 // ANDS does not use the same encoding scheme as the others xxxS
1739 // instructions.
1740 SrcReg = MI.getOperand(1).getReg();
1741 SrcReg2 = 0;
1742 CmpMask = ~0;
1744 MI.getOperand(2).getImm(),
1745 MI.getOpcode() == AArch64::ANDSWri ? 32 : 64);
1746 return true;
1747 }
1748
1749 return false;
1750}
1751
1753 MachineBasicBlock *MBB = Instr.getParent();
1754 assert(MBB && "Can't get MachineBasicBlock here");
1755 MachineFunction *MF = MBB->getParent();
1756 assert(MF && "Can't get MachineFunction here");
1760
1761 for (const auto &[OpIdx, MO] : enumerate(Instr.operands())) {
1762 if (!MO.isReg() || !MO.getReg().isVirtual())
1763 continue;
1764
1765 Register Reg = MO.getReg();
1766 const TargetRegisterClass *NewRC = Instr.getRegClassConstraintEffect(
1767 OpIdx, MRI->getRegClass(Reg), TII, TRI);
1768 if (!NewRC || !MRI->constrainRegClass(Reg, NewRC))
1769 llvm_unreachable("Operand register classes are incompatible");
1770 }
1771}
1772
1773/// Return the opcode that does not set flags when possible - otherwise
1774/// return the original opcode. The caller is responsible to do the actual
1775/// substitution and legality checking.
1777 // Don't convert all compare instructions, because for some the zero register
1778 // encoding becomes the sp register.
1779 bool MIDefinesZeroReg = false;
1780 if (MI.definesRegister(AArch64::WZR, /*TRI=*/nullptr) ||
1781 MI.definesRegister(AArch64::XZR, /*TRI=*/nullptr))
1782 MIDefinesZeroReg = true;
1783
1784 switch (MI.getOpcode()) {
1785 default:
1786 return MI.getOpcode();
1787 case AArch64::ADDSWrr:
1788 return AArch64::ADDWrr;
1789 case AArch64::ADDSWri:
1790 return MIDefinesZeroReg ? AArch64::ADDSWri : AArch64::ADDWri;
1791 case AArch64::ADDSWrs:
1792 return MIDefinesZeroReg ? AArch64::ADDSWrs : AArch64::ADDWrs;
1793 case AArch64::ADDSWrx:
1794 return AArch64::ADDWrx;
1795 case AArch64::ADDSXrr:
1796 return AArch64::ADDXrr;
1797 case AArch64::ADDSXri:
1798 return MIDefinesZeroReg ? AArch64::ADDSXri : AArch64::ADDXri;
1799 case AArch64::ADDSXrs:
1800 return MIDefinesZeroReg ? AArch64::ADDSXrs : AArch64::ADDXrs;
1801 case AArch64::ADDSXrx:
1802 return AArch64::ADDXrx;
1803 case AArch64::SUBSWrr:
1804 return AArch64::SUBWrr;
1805 case AArch64::SUBSWri:
1806 return MIDefinesZeroReg ? AArch64::SUBSWri : AArch64::SUBWri;
1807 case AArch64::SUBSWrs:
1808 return MIDefinesZeroReg ? AArch64::SUBSWrs : AArch64::SUBWrs;
1809 case AArch64::SUBSWrx:
1810 return AArch64::SUBWrx;
1811 case AArch64::SUBSXrr:
1812 return AArch64::SUBXrr;
1813 case AArch64::SUBSXri:
1814 return MIDefinesZeroReg ? AArch64::SUBSXri : AArch64::SUBXri;
1815 case AArch64::SUBSXrs:
1816 return MIDefinesZeroReg ? AArch64::SUBSXrs : AArch64::SUBXrs;
1817 case AArch64::SUBSXrx:
1818 return AArch64::SUBXrx;
1819 }
1820}
1821
1822enum AccessKind { AK_Write = 0x01, AK_Read = 0x10, AK_All = 0x11 };
1823
1824/// True when condition flags are accessed (either by writing or reading)
1825/// on the instruction trace starting at From and ending at To.
1826///
1827/// Note: If From and To are from different blocks it's assumed CC are accessed
1828/// on the path.
1831 const TargetRegisterInfo *TRI, const AccessKind AccessToCheck = AK_All) {
1832 // Early exit if To is at the beginning of the BB.
1833 if (To == To->getParent()->begin())
1834 return true;
1835
1836 // Check whether the instructions are in the same basic block
1837 // If not, assume the condition flags might get modified somewhere.
1838 if (To->getParent() != From->getParent())
1839 return true;
1840
1841 // From must be above To.
1842 assert(std::any_of(
1843 ++To.getReverse(), To->getParent()->rend(),
1844 [From](MachineInstr &MI) { return MI.getIterator() == From; }));
1845
1846 // We iterate backward starting at \p To until we hit \p From.
1847 for (const MachineInstr &Instr :
1849 if (((AccessToCheck & AK_Write) &&
1850 Instr.modifiesRegister(AArch64::NZCV, TRI)) ||
1851 ((AccessToCheck & AK_Read) && Instr.readsRegister(AArch64::NZCV, TRI)))
1852 return true;
1853 }
1854 return false;
1855}
1856
1857std::optional<unsigned>
1858AArch64InstrInfo::canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
1859 MachineInstr *Pred,
1860 const MachineRegisterInfo *MRI) const {
1861 unsigned MaskOpcode = Mask->getOpcode();
1862 unsigned PredOpcode = Pred->getOpcode();
1863 bool PredIsPTestLike = isPTestLikeOpcode(PredOpcode);
1864 bool PredIsWhileLike = isWhileOpcode(PredOpcode);
1865
1866 if (PredIsWhileLike) {
1867 // For PTEST(PG, PG), PTEST is redundant when PG is the result of a WHILEcc
1868 // instruction and the condition is "any" since WHILcc does an implicit
1869 // PTEST(ALL, PG) check and PG is always a subset of ALL.
1870 if ((Mask == Pred) && PTest->getOpcode() == AArch64::PTEST_PP_ANY)
1871 return PredOpcode;
1872
1873 // For PTEST(PTRUE_ALL, WHILE), if the element size matches, the PTEST is
1874 // redundant since WHILE performs an implicit PTEST with an all active
1875 // mask.
1876 if (isPTrueOpcode(MaskOpcode) && Mask->getOperand(1).getImm() == 31 &&
1877 getElementSizeForOpcode(MaskOpcode) ==
1878 getElementSizeForOpcode(PredOpcode))
1879 return PredOpcode;
1880
1881 // For PTEST_FIRST(PTRUE_ALL, WHILE), the PTEST_FIRST is redundant since
1882 // WHILEcc performs an implicit PTEST with an all active mask, setting
1883 // the N flag as the PTEST_FIRST would.
1884 if (PTest->getOpcode() == AArch64::PTEST_PP_FIRST &&
1885 isPTrueOpcode(MaskOpcode) && Mask->getOperand(1).getImm() == 31)
1886 return PredOpcode;
1887
1888 return {};
1889 }
1890
1891 if (PredIsPTestLike) {
1892 // For PTEST(PG, PG), PTEST is redundant when PG is the result of an
1893 // instruction that sets the flags as PTEST would and the condition is
1894 // "any" since PG is always a subset of the governing predicate of the
1895 // ptest-like instruction.
1896 if ((Mask == Pred) && PTest->getOpcode() == AArch64::PTEST_PP_ANY)
1897 return PredOpcode;
1898
1899 auto PTestLikeMask = MRI->getUniqueVRegDef(Pred->getOperand(1).getReg());
1900
1901 // If the PTEST like instruction's general predicate is not `Mask`, attempt
1902 // to look through a copy and try again. This is because some instructions
1903 // take a predicate whose register class is a subset of its result class.
1904 if (Mask != PTestLikeMask && PTestLikeMask->isFullCopy() &&
1905 PTestLikeMask->getOperand(1).getReg().isVirtual())
1906 PTestLikeMask =
1907 MRI->getUniqueVRegDef(PTestLikeMask->getOperand(1).getReg());
1908
1909 // For PTEST(PTRUE_ALL, PTEST_LIKE), the PTEST is redundant if the
1910 // the element size matches and either the PTEST_LIKE instruction uses
1911 // the same all active mask or the condition is "any".
1912 if (isPTrueOpcode(MaskOpcode) && Mask->getOperand(1).getImm() == 31 &&
1913 getElementSizeForOpcode(MaskOpcode) ==
1914 getElementSizeForOpcode(PredOpcode)) {
1915 if (Mask == PTestLikeMask || PTest->getOpcode() == AArch64::PTEST_PP_ANY)
1916 return PredOpcode;
1917 }
1918
1919 // For PTEST(PG, PTEST_LIKE(PG, ...)), the PTEST is redundant since the
1920 // flags are set based on the same mask 'PG', but PTEST_LIKE must operate
1921 // on 8-bit predicates like the PTEST. Otherwise, for instructions like
1922 // compare that also support 16/32/64-bit predicates, the implicit PTEST
1923 // performed by the compare could consider fewer lanes for these element
1924 // sizes.
1925 //
1926 // For example, consider
1927 //
1928 // ptrue p0.b ; P0=1111-1111-1111-1111
1929 // index z0.s, #0, #1 ; Z0=<0,1,2,3>
1930 // index z1.s, #1, #1 ; Z1=<1,2,3,4>
1931 // cmphi p1.s, p0/z, z1.s, z0.s ; P1=0001-0001-0001-0001
1932 // ; ^ last active
1933 // ptest p0, p1.b ; P1=0001-0001-0001-0001
1934 // ; ^ last active
1935 //
1936 // where the compare generates a canonical all active 32-bit predicate
1937 // (equivalent to 'ptrue p1.s, all'). The implicit PTEST sets the last
1938 // active flag, whereas the PTEST instruction with the same mask doesn't.
1939 // For PTEST_ANY this doesn't apply as the flags in this case would be
1940 // identical regardless of element size.
1941 uint64_t PredElementSize = getElementSizeForOpcode(PredOpcode);
1942 if (Mask == PTestLikeMask && (PredElementSize == AArch64::ElementSizeB ||
1943 PTest->getOpcode() == AArch64::PTEST_PP_ANY))
1944 return PredOpcode;
1945
1946 return {};
1947 }
1948
1949 // If OP in PTEST(PG, OP(PG, ...)) has a flag-setting variant change the
1950 // opcode so the PTEST becomes redundant.
1951 switch (PredOpcode) {
1952 case AArch64::AND_PPzPP:
1953 case AArch64::BIC_PPzPP:
1954 case AArch64::EOR_PPzPP:
1955 case AArch64::NAND_PPzPP:
1956 case AArch64::NOR_PPzPP:
1957 case AArch64::ORN_PPzPP:
1958 case AArch64::ORR_PPzPP:
1959 case AArch64::BRKA_PPzP:
1960 case AArch64::BRKPA_PPzPP:
1961 case AArch64::BRKB_PPzP:
1962 case AArch64::BRKPB_PPzPP:
1963 case AArch64::RDFFR_PPz: {
1964 // Check to see if our mask is the same. If not the resulting flag bits
1965 // may be different and we can't remove the ptest.
1966 auto *PredMask = MRI->getUniqueVRegDef(Pred->getOperand(1).getReg());
1967 if (Mask != PredMask)
1968 return {};
1969 break;
1970 }
1971 case AArch64::BRKN_PPzP: {
1972 // BRKN uses an all active implicit mask to set flags unlike the other
1973 // flag-setting instructions.
1974 // PTEST(PTRUE_B(31), BRKN(PG, A, B)) -> BRKNS(PG, A, B).
1975 if ((MaskOpcode != AArch64::PTRUE_B) ||
1976 (Mask->getOperand(1).getImm() != 31))
1977 return {};
1978 break;
1979 }
1980 case AArch64::PTRUE_B:
1981 // PTEST(OP=PTRUE_B(A), OP) -> PTRUES_B(A)
1982 break;
1983 default:
1984 // Bail out if we don't recognize the input
1985 return {};
1986 }
1987
1988 return convertToFlagSettingOpc(PredOpcode);
1989}
1990
1991/// optimizePTestInstr - Attempt to remove a ptest of a predicate-generating
1992/// operation which could set the flags in an identical manner
1993bool AArch64InstrInfo::optimizePTestInstr(
1994 MachineInstr *PTest, unsigned MaskReg, unsigned PredReg,
1995 const MachineRegisterInfo *MRI) const {
1996 auto *Mask = MRI->getUniqueVRegDef(MaskReg);
1997 auto *Pred = MRI->getUniqueVRegDef(PredReg);
1998
1999 if (Pred->isCopy() && PTest->getOpcode() == AArch64::PTEST_PP_FIRST) {
2000 // Instructions which return a multi-vector (e.g. WHILECC_x2) require copies
2001 // before the branch to extract each subregister.
2002 auto Op = Pred->getOperand(1);
2003 if (Op.isReg() && Op.getReg().isVirtual() &&
2004 Op.getSubReg() == AArch64::psub0)
2005 Pred = MRI->getUniqueVRegDef(Op.getReg());
2006 }
2007
2008 unsigned PredOpcode = Pred->getOpcode();
2009 auto NewOp = canRemovePTestInstr(PTest, Mask, Pred, MRI);
2010 if (!NewOp)
2011 return false;
2012
2013 const TargetRegisterInfo *TRI = &getRegisterInfo();
2014
2015 // If another instruction between Pred and PTest accesses flags, don't remove
2016 // the ptest or update the earlier instruction to modify them.
2017 if (areCFlagsAccessedBetweenInstrs(Pred, PTest, TRI))
2018 return false;
2019
2020 // If we pass all the checks, it's safe to remove the PTEST and use the flags
2021 // as they are prior to PTEST. Sometimes this requires the tested PTEST
2022 // operand to be replaced with an equivalent instruction that also sets the
2023 // flags.
2024 PTest->eraseFromParent();
2025 if (*NewOp != PredOpcode) {
2026 Pred->setDesc(get(*NewOp));
2027 updateOperandRegClass(*Pred);
2028 Pred->addRegisterDefined(AArch64::NZCV, TRI);
2029 }
2030
2031 // Ensure that the flags def is live.
2032 if (Pred->registerDefIsDead(AArch64::NZCV, TRI)) {
2033 unsigned i = 0, e = Pred->getNumOperands();
2034 for (; i != e; ++i) {
2035 MachineOperand &MO = Pred->getOperand(i);
2036 if (MO.isReg() && MO.isDef() && MO.getReg() == AArch64::NZCV) {
2037 MO.setIsDead(false);
2038 break;
2039 }
2040 }
2041 }
2042 return true;
2043}
2044
2045/// Try to optimize a compare instruction. A compare instruction is an
2046/// instruction which produces AArch64::NZCV. It can be truly compare
2047/// instruction
2048/// when there are no uses of its destination register.
2049///
2050/// The following steps are tried in order:
2051/// 1. Convert CmpInstr into an unconditional version.
2052/// 2. Remove CmpInstr if above there is an instruction producing a needed
2053/// condition code or an instruction which can be converted into such an
2054/// instruction.
2055/// Only comparison with zero is supported.
2057 MachineInstr &CmpInstr, Register SrcReg, Register SrcReg2, int64_t CmpMask,
2058 int64_t CmpValue, const MachineRegisterInfo *MRI) const {
2059 assert(CmpInstr.getParent());
2060 assert(MRI);
2061
2062 // Replace SUBSWrr with SUBWrr if NZCV is not used.
2063 int DeadNZCVIdx =
2064 CmpInstr.findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr, true);
2065 if (DeadNZCVIdx != -1) {
2066 if (CmpInstr.definesRegister(AArch64::WZR, /*TRI=*/nullptr) ||
2067 CmpInstr.definesRegister(AArch64::XZR, /*TRI=*/nullptr)) {
2068 CmpInstr.eraseFromParent();
2069 return true;
2070 }
2071 unsigned Opc = CmpInstr.getOpcode();
2072 unsigned NewOpc = convertToNonFlagSettingOpc(CmpInstr);
2073 if (NewOpc == Opc)
2074 return false;
2075 const MCInstrDesc &MCID = get(NewOpc);
2076 CmpInstr.setDesc(MCID);
2077 CmpInstr.removeOperand(DeadNZCVIdx);
2078 updateOperandRegClass(CmpInstr);
2079 return true;
2080 }
2081
2082 if (CmpInstr.getOpcode() == AArch64::PTEST_PP ||
2083 CmpInstr.getOpcode() == AArch64::PTEST_PP_ANY ||
2084 CmpInstr.getOpcode() == AArch64::PTEST_PP_FIRST)
2085 return optimizePTestInstr(&CmpInstr, SrcReg, SrcReg2, MRI);
2086
2087 if (SrcReg2 != 0)
2088 return false;
2089
2090 // CmpInstr is a Compare instruction if destination register is not used.
2091 if (!MRI->use_nodbg_empty(CmpInstr.getOperand(0).getReg()))
2092 return false;
2093
2094 if (CmpValue == 0 && substituteCmpToZero(CmpInstr, SrcReg, *MRI))
2095 return true;
2096 return (CmpValue == 0 || CmpValue == 1) &&
2097 removeCmpToZeroOrOne(CmpInstr, SrcReg, CmpValue, *MRI);
2098}
2099
2100/// Get opcode of S version of Instr.
2101/// If Instr is S version its opcode is returned.
2102/// AArch64::INSTRUCTION_LIST_END is returned if Instr does not have S version
2103/// or we are not interested in it.
2104static unsigned sForm(MachineInstr &Instr) {
2105 switch (Instr.getOpcode()) {
2106 default:
2107 return AArch64::INSTRUCTION_LIST_END;
2108
2109 case AArch64::ADDSWrr:
2110 case AArch64::ADDSWri:
2111 case AArch64::ADDSXrr:
2112 case AArch64::ADDSXri:
2113 case AArch64::ADDSWrx:
2114 case AArch64::ADDSXrx:
2115 case AArch64::ADDSWrs:
2116 case AArch64::ADDSXrs:
2117 case AArch64::SUBSWrr:
2118 case AArch64::SUBSWri:
2119 case AArch64::SUBSWrx:
2120 case AArch64::SUBSWrs:
2121 case AArch64::SUBSXrr:
2122 case AArch64::SUBSXri:
2123 case AArch64::SUBSXrx:
2124 case AArch64::SUBSXrs:
2125 case AArch64::ANDSWri:
2126 case AArch64::ANDSWrr:
2127 case AArch64::ANDSWrs:
2128 case AArch64::ANDSXri:
2129 case AArch64::ANDSXrr:
2130 case AArch64::ANDSXrs:
2131 case AArch64::BICSWrr:
2132 case AArch64::BICSXrr:
2133 case AArch64::BICSWrs:
2134 case AArch64::BICSXrs:
2135 case AArch64::ADCSWr:
2136 case AArch64::ADCSXr:
2137 case AArch64::SBCSWr:
2138 case AArch64::SBCSXr:
2139 return Instr.getOpcode();
2140
2141 case AArch64::ADDWrr:
2142 return AArch64::ADDSWrr;
2143 case AArch64::ADDWri:
2144 return AArch64::ADDSWri;
2145 case AArch64::ADDXrr:
2146 return AArch64::ADDSXrr;
2147 case AArch64::ADDXri:
2148 return AArch64::ADDSXri;
2149 case AArch64::ADDWrx:
2150 return AArch64::ADDSWrx;
2151 case AArch64::ADDXrx:
2152 return AArch64::ADDSXrx;
2153 case AArch64::ADDWrs:
2154 return AArch64::ADDSWrs;
2155 case AArch64::ADDXrs:
2156 return AArch64::ADDSXrs;
2157 case AArch64::ADCWr:
2158 return AArch64::ADCSWr;
2159 case AArch64::ADCXr:
2160 return AArch64::ADCSXr;
2161 case AArch64::SUBWrr:
2162 return AArch64::SUBSWrr;
2163 case AArch64::SUBWri:
2164 return AArch64::SUBSWri;
2165 case AArch64::SUBXrr:
2166 return AArch64::SUBSXrr;
2167 case AArch64::SUBXri:
2168 return AArch64::SUBSXri;
2169 case AArch64::SUBWrx:
2170 return AArch64::SUBSWrx;
2171 case AArch64::SUBXrx:
2172 return AArch64::SUBSXrx;
2173 case AArch64::SUBWrs:
2174 return AArch64::SUBSWrs;
2175 case AArch64::SUBXrs:
2176 return AArch64::SUBSXrs;
2177 case AArch64::SBCWr:
2178 return AArch64::SBCSWr;
2179 case AArch64::SBCXr:
2180 return AArch64::SBCSXr;
2181 case AArch64::ANDWri:
2182 return AArch64::ANDSWri;
2183 case AArch64::ANDXri:
2184 return AArch64::ANDSXri;
2185 case AArch64::ANDWrr:
2186 return AArch64::ANDSWrr;
2187 case AArch64::ANDWrs:
2188 return AArch64::ANDSWrs;
2189 case AArch64::ANDXrr:
2190 return AArch64::ANDSXrr;
2191 case AArch64::ANDXrs:
2192 return AArch64::ANDSXrs;
2193 case AArch64::BICWrr:
2194 return AArch64::BICSWrr;
2195 case AArch64::BICXrr:
2196 return AArch64::BICSXrr;
2197 case AArch64::BICWrs:
2198 return AArch64::BICSWrs;
2199 case AArch64::BICXrs:
2200 return AArch64::BICSXrs;
2201 }
2202}
2203
2204/// Check if AArch64::NZCV should be alive in successors of MBB.
2206 for (auto *BB : MBB->successors())
2207 if (BB->isLiveIn(AArch64::NZCV))
2208 return true;
2209 return false;
2210}
2211
2212/// \returns The condition code operand index for \p Instr if it is a branch
2213/// or select and -1 otherwise.
2214int AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(
2215 const MachineInstr &Instr) {
2216 switch (Instr.getOpcode()) {
2217 default:
2218 return -1;
2219
2220 case AArch64::Bcc: {
2221 int Idx = Instr.findRegisterUseOperandIdx(AArch64::NZCV, /*TRI=*/nullptr);
2222 assert(Idx >= 2);
2223 return Idx - 2;
2224 }
2225
2226 case AArch64::CSINVWr:
2227 case AArch64::CSINVXr:
2228 case AArch64::CSINCWr:
2229 case AArch64::CSINCXr:
2230 case AArch64::CSELWr:
2231 case AArch64::CSELXr:
2232 case AArch64::CSNEGWr:
2233 case AArch64::CSNEGXr:
2234 case AArch64::FCSELSrrr:
2235 case AArch64::FCSELDrrr: {
2236 int Idx = Instr.findRegisterUseOperandIdx(AArch64::NZCV, /*TRI=*/nullptr);
2237 assert(Idx >= 1);
2238 return Idx - 1;
2239 }
2240 }
2241}
2242
2243/// Find a condition code used by the instruction.
2244/// Returns AArch64CC::Invalid if either the instruction does not use condition
2245/// codes or we don't optimize CmpInstr in the presence of such instructions.
2247 int CCIdx =
2248 AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(Instr);
2249 return CCIdx >= 0 ? static_cast<AArch64CC::CondCode>(
2250 Instr.getOperand(CCIdx).getImm())
2252}
2253
2256 UsedNZCV UsedFlags;
2257 switch (CC) {
2258 default:
2259 break;
2260
2261 case AArch64CC::EQ: // Z set
2262 case AArch64CC::NE: // Z clear
2263 UsedFlags.Z = true;
2264 break;
2265
2266 case AArch64CC::HI: // Z clear and C set
2267 case AArch64CC::LS: // Z set or C clear
2268 UsedFlags.Z = true;
2269 [[fallthrough]];
2270 case AArch64CC::HS: // C set
2271 case AArch64CC::LO: // C clear
2272 UsedFlags.C = true;
2273 break;
2274
2275 case AArch64CC::MI: // N set
2276 case AArch64CC::PL: // N clear
2277 UsedFlags.N = true;
2278 break;
2279
2280 case AArch64CC::VS: // V set
2281 case AArch64CC::VC: // V clear
2282 UsedFlags.V = true;
2283 break;
2284
2285 case AArch64CC::GT: // Z clear, N and V the same
2286 case AArch64CC::LE: // Z set, N and V differ
2287 UsedFlags.Z = true;
2288 [[fallthrough]];
2289 case AArch64CC::GE: // N and V the same
2290 case AArch64CC::LT: // N and V differ
2291 UsedFlags.N = true;
2292 UsedFlags.V = true;
2293 break;
2294 }
2295 return UsedFlags;
2296}
2297
2298/// \returns Conditions flags used after \p CmpInstr in its MachineBB if NZCV
2299/// flags are not alive in successors of the same \p CmpInstr and \p MI parent.
2300/// \returns std::nullopt otherwise.
2301///
2302/// Collect instructions using that flags in \p CCUseInstrs if provided.
2303std::optional<UsedNZCV>
2305 const TargetRegisterInfo &TRI,
2306 SmallVectorImpl<MachineInstr *> *CCUseInstrs) {
2307 MachineBasicBlock *CmpParent = CmpInstr.getParent();
2308 if (MI.getParent() != CmpParent)
2309 return std::nullopt;
2310
2311 if (areCFlagsAliveInSuccessors(CmpParent))
2312 return std::nullopt;
2313
2314 UsedNZCV NZCVUsedAfterCmp;
2316 std::next(CmpInstr.getIterator()), CmpParent->instr_end())) {
2317 if (Instr.readsRegister(AArch64::NZCV, &TRI)) {
2319 if (CC == AArch64CC::Invalid) // Unsupported conditional instruction
2320 return std::nullopt;
2321 NZCVUsedAfterCmp |= getUsedNZCV(CC);
2322 if (CCUseInstrs)
2323 CCUseInstrs->push_back(&Instr);
2324 }
2325 if (Instr.modifiesRegister(AArch64::NZCV, &TRI))
2326 break;
2327 }
2328 return NZCVUsedAfterCmp;
2329}
2330
2331static bool isADDSRegImm(unsigned Opcode) {
2332 return Opcode == AArch64::ADDSWri || Opcode == AArch64::ADDSXri;
2333}
2334
2335static bool isSUBSRegImm(unsigned Opcode) {
2336 return Opcode == AArch64::SUBSWri || Opcode == AArch64::SUBSXri;
2337}
2338
2340 unsigned Opc = sForm(MI);
2341 switch (Opc) {
2342 case AArch64::ANDSWri:
2343 case AArch64::ANDSWrr:
2344 case AArch64::ANDSWrs:
2345 case AArch64::ANDSXri:
2346 case AArch64::ANDSXrr:
2347 case AArch64::ANDSXrs:
2348 case AArch64::BICSWrr:
2349 case AArch64::BICSXrr:
2350 case AArch64::BICSWrs:
2351 case AArch64::BICSXrs:
2352 return true;
2353 default:
2354 return false;
2355 }
2356}
2357
2358/// Check if CmpInstr can be substituted by MI.
2359///
2360/// CmpInstr can be substituted:
2361/// - CmpInstr is either 'ADDS %vreg, 0' or 'SUBS %vreg, 0'
2362/// - and, MI and CmpInstr are from the same MachineBB
2363/// - and, condition flags are not alive in successors of the CmpInstr parent
2364/// - and, if MI opcode is the S form there must be no defs of flags between
2365/// MI and CmpInstr
2366/// or if MI opcode is not the S form there must be neither defs of flags
2367/// nor uses of flags between MI and CmpInstr.
2368/// - and, C is not used after CmpInstr; CmpInstr's C is from adds/subs #0 on
2369/// SrcReg and can differ from MI (e.g. carry out of ADCS/SBCS).
2370/// - and, V is not used after CmpInstr unless MI is AND/BIC (V cleared) or MI
2371/// has NoSWrap (overflow is poison and the fold is still safe).
2373 const TargetRegisterInfo &TRI) {
2374 // MI is an opcode sForm maps (add/sub/adc/sbc/and/bic and their S forms).
2375 assert(sForm(MI) != AArch64::INSTRUCTION_LIST_END);
2376
2377 const unsigned CmpOpcode = CmpInstr.getOpcode();
2378 if (!isADDSRegImm(CmpOpcode) && !isSUBSRegImm(CmpOpcode))
2379 return false;
2380
2381 assert((CmpInstr.getOperand(2).isImm() &&
2382 CmpInstr.getOperand(2).getImm() == 0) &&
2383 "Caller guarantees that CmpInstr compares with constant 0");
2384
2385 std::optional<UsedNZCV> NZVCUsed = examineCFlagsUse(MI, CmpInstr, TRI);
2386 if (!NZVCUsed || NZVCUsed->C)
2387 return false;
2388
2389 // CmpInstr is ADDS/SUBS with immediate 0 on SrcReg (compare SrcReg to zero).
2390 // After the fold, users see NZCV from MI (or its S form), not from CmpInstr.
2391 // N/Z match CmpInstr for the value in SrcReg; C/V need not match in general
2392 // (e.g. ADCS vs adds #0), so we require C unused after CmpInstr and gate V
2393 // as below. NoSWrap makes signed overflow poison; AND/BIC clear V.
2394 if (NZVCUsed->V && !MI.getFlag(MachineInstr::NoSWrap) && !isANDOpcode(MI))
2395 return false;
2396
2397 AccessKind AccessToCheck = AK_Write;
2398 if (sForm(MI) != MI.getOpcode())
2399 AccessToCheck = AK_All;
2400 return !areCFlagsAccessedBetweenInstrs(&MI, &CmpInstr, &TRI, AccessToCheck);
2401}
2402
2403/// Substitute an instruction comparing to zero with another instruction
2404/// which produces needed condition flags.
2405///
2406/// Return true on success.
2407bool AArch64InstrInfo::substituteCmpToZero(
2408 MachineInstr &CmpInstr, unsigned SrcReg,
2409 const MachineRegisterInfo &MRI) const {
2410 // Get the unique definition of SrcReg.
2411 MachineInstr *MI = MRI.getUniqueVRegDef(SrcReg);
2412 if (!MI)
2413 return false;
2414
2415 const TargetRegisterInfo &TRI = getRegisterInfo();
2416
2417 unsigned NewOpc = sForm(*MI);
2418 if (NewOpc == AArch64::INSTRUCTION_LIST_END)
2419 return false;
2420
2421 if (!canInstrSubstituteCmpInstr(*MI, CmpInstr, TRI))
2422 return false;
2423
2424 // Update the instruction to set NZCV.
2425 MI->setDesc(get(NewOpc));
2426 CmpInstr.eraseFromParent();
2428 MI->addRegisterDefined(AArch64::NZCV, &TRI);
2429 return true;
2430}
2431
2432/// \returns True if \p CmpInstr can be removed.
2433///
2434/// \p IsInvertCC is true if, after removing \p CmpInstr, condition
2435/// codes used in \p CCUseInstrs must be inverted.
2437 int CmpValue, const TargetRegisterInfo &TRI,
2439 bool &IsInvertCC) {
2440 assert((CmpValue == 0 || CmpValue == 1) &&
2441 "Only comparisons to 0 or 1 considered for removal!");
2442
2443 // MI is 'CSINCWr %vreg, wzr, wzr, <cc>' or 'CSINCXr %vreg, xzr, xzr, <cc>'
2444 unsigned MIOpc = MI.getOpcode();
2445 if (MIOpc == AArch64::CSINCWr) {
2446 if (MI.getOperand(1).getReg() != AArch64::WZR ||
2447 MI.getOperand(2).getReg() != AArch64::WZR)
2448 return false;
2449 } else if (MIOpc == AArch64::CSINCXr) {
2450 if (MI.getOperand(1).getReg() != AArch64::XZR ||
2451 MI.getOperand(2).getReg() != AArch64::XZR)
2452 return false;
2453 } else {
2454 return false;
2455 }
2457 if (MICC == AArch64CC::Invalid)
2458 return false;
2459
2460 // NZCV needs to be defined
2461 if (MI.findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr, true) != -1)
2462 return false;
2463
2464 // CmpInstr is 'ADDS %vreg, 0' or 'SUBS %vreg, 0' or 'SUBS %vreg, 1'
2465 const unsigned CmpOpcode = CmpInstr.getOpcode();
2466 bool IsSubsRegImm = isSUBSRegImm(CmpOpcode);
2467 if (CmpValue && !IsSubsRegImm)
2468 return false;
2469 if (!CmpValue && !IsSubsRegImm && !isADDSRegImm(CmpOpcode))
2470 return false;
2471
2472 // MI conditions allowed: eq, ne, mi, pl
2473 UsedNZCV MIUsedNZCV = getUsedNZCV(MICC);
2474 if (MIUsedNZCV.C || MIUsedNZCV.V)
2475 return false;
2476
2477 std::optional<UsedNZCV> NZCVUsedAfterCmp =
2478 examineCFlagsUse(MI, CmpInstr, TRI, &CCUseInstrs);
2479 // Condition flags are not used in CmpInstr basic block successors and only
2480 // Z or N flags allowed to be used after CmpInstr within its basic block
2481 if (!NZCVUsedAfterCmp || NZCVUsedAfterCmp->C || NZCVUsedAfterCmp->V)
2482 return false;
2483 // Z or N flag used after CmpInstr must correspond to the flag used in MI
2484 if ((MIUsedNZCV.Z && NZCVUsedAfterCmp->N) ||
2485 (MIUsedNZCV.N && NZCVUsedAfterCmp->Z))
2486 return false;
2487 // If CmpInstr is comparison to zero MI conditions are limited to eq, ne
2488 if (MIUsedNZCV.N && !CmpValue)
2489 return false;
2490
2491 // There must be no defs of flags between MI and CmpInstr
2492 if (areCFlagsAccessedBetweenInstrs(&MI, &CmpInstr, &TRI, AK_Write))
2493 return false;
2494
2495 // Condition code is inverted in the following cases:
2496 // 1. MI condition is ne; CmpInstr is 'ADDS %vreg, 0' or 'SUBS %vreg, 0'
2497 // 2. MI condition is eq, pl; CmpInstr is 'SUBS %vreg, 1'
2498 IsInvertCC = (CmpValue && (MICC == AArch64CC::EQ || MICC == AArch64CC::PL)) ||
2499 (!CmpValue && MICC == AArch64CC::NE);
2500 return true;
2501}
2502
2503/// Remove comparison in csinc-cmp sequence
2504///
2505/// Examples:
2506/// 1. \code
2507/// csinc w9, wzr, wzr, ne
2508/// cmp w9, #0
2509/// b.eq
2510/// \endcode
2511/// to
2512/// \code
2513/// csinc w9, wzr, wzr, ne
2514/// b.ne
2515/// \endcode
2516///
2517/// 2. \code
2518/// csinc x2, xzr, xzr, mi
2519/// cmp x2, #1
2520/// b.pl
2521/// \endcode
2522/// to
2523/// \code
2524/// csinc x2, xzr, xzr, mi
2525/// b.pl
2526/// \endcode
2527///
2528/// \param CmpInstr comparison instruction
2529/// \return True when comparison removed
2530bool AArch64InstrInfo::removeCmpToZeroOrOne(
2531 MachineInstr &CmpInstr, unsigned SrcReg, int CmpValue,
2532 const MachineRegisterInfo &MRI) const {
2533 MachineInstr *MI = MRI.getUniqueVRegDef(SrcReg);
2534 if (!MI)
2535 return false;
2536 const TargetRegisterInfo &TRI = getRegisterInfo();
2537 SmallVector<MachineInstr *, 4> CCUseInstrs;
2538 bool IsInvertCC = false;
2539 if (!canCmpInstrBeRemoved(*MI, CmpInstr, CmpValue, TRI, CCUseInstrs,
2540 IsInvertCC))
2541 return false;
2542 // Make transformation
2543 CmpInstr.eraseFromParent();
2544 if (IsInvertCC) {
2545 // Invert condition codes in CmpInstr CC users
2546 for (MachineInstr *CCUseInstr : CCUseInstrs) {
2547 int Idx = findCondCodeUseOperandIdxForBranchOrSelect(*CCUseInstr);
2548 assert(Idx >= 0 && "Unexpected instruction using CC.");
2549 MachineOperand &CCOperand = CCUseInstr->getOperand(Idx);
2551 static_cast<AArch64CC::CondCode>(CCOperand.getImm()));
2552 CCOperand.setImm(CCUse);
2553 }
2554 }
2555 return true;
2556}
2557
2558bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
2559 if (MI.getOpcode() != TargetOpcode::LOAD_STACK_GUARD &&
2560 MI.getOpcode() != AArch64::CATCHRET &&
2561 MI.getOpcode() != AArch64::STACK_GUARD_UNMIX)
2562 return false;
2563
2564 MachineBasicBlock &MBB = *MI.getParent();
2565 auto &Subtarget = MBB.getParent()->getSubtarget<AArch64Subtarget>();
2566 auto TRI = Subtarget.getRegisterInfo();
2567 DebugLoc DL = MI.getDebugLoc();
2568
2569 if (MI.getOpcode() == AArch64::STACK_GUARD_UNMIX) {
2570 // Expand STACK_GUARD_UNMIX to: sub Rd, fp, Rs
2571 // This computes FP - stored_mixed_value to unmix the cookie
2572 Register DstReg = MI.getOperand(0).getReg();
2573 Register SrcReg = MI.getOperand(1).getReg();
2574
2575 BuildMI(MBB, MI, DL, get(AArch64::SUBXrr), DstReg)
2576 .addReg(AArch64::FP)
2577 .addReg(SrcReg);
2578
2579 MBB.erase(MI);
2580 return true;
2581 }
2582
2583 if (MI.getOpcode() == AArch64::CATCHRET) {
2584 // Skip to the first instruction before the epilog.
2585 const TargetInstrInfo *TII =
2587 MachineBasicBlock *TargetMBB = MI.getOperand(0).getMBB();
2589 MachineBasicBlock::iterator FirstEpilogSEH = std::prev(MBBI);
2590 while (FirstEpilogSEH->getFlag(MachineInstr::FrameDestroy) &&
2591 FirstEpilogSEH != MBB.begin())
2592 FirstEpilogSEH = std::prev(FirstEpilogSEH);
2593 if (FirstEpilogSEH != MBB.begin())
2594 FirstEpilogSEH = std::next(FirstEpilogSEH);
2595 BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADRP))
2596 .addReg(AArch64::X0, RegState::Define)
2597 .addMBB(TargetMBB, AArch64II::MO_PAGE);
2598 BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADDXri))
2599 .addReg(AArch64::X0, RegState::Define)
2600 .addReg(AArch64::X0)
2602 .addImm(0);
2603 TargetMBB->setMachineBlockAddressTaken();
2604 return true;
2605 }
2606
2607 Register Reg = MI.getOperand(0).getReg();
2609 if (M.getStackProtectorGuard() == "sysreg") {
2610 const AArch64SysReg::SysReg *SrcReg =
2611 AArch64SysReg::lookupSysRegByName(M.getStackProtectorGuardReg());
2612 if (!SrcReg)
2613 report_fatal_error("Unknown SysReg for Stack Protector Guard Register");
2614
2615 // mrs xN, sysreg
2616 BuildMI(MBB, MI, DL, get(AArch64::MRS))
2618 .addImm(SrcReg->Encoding);
2619 int Offset = M.getStackProtectorGuardOffset();
2620 if (Offset >= 0 && Offset <= 32760 && Offset % 8 == 0) {
2621 // ldr xN, [xN, #offset]
2622 BuildMI(MBB, MI, DL, get(AArch64::LDRXui))
2623 .addDef(Reg)
2625 .addImm(Offset / 8);
2626 } else if (Offset >= -256 && Offset <= 255) {
2627 // ldur xN, [xN, #offset]
2628 BuildMI(MBB, MI, DL, get(AArch64::LDURXi))
2629 .addDef(Reg)
2631 .addImm(Offset);
2632 } else if (Offset >= -4095 && Offset <= 4095) {
2633 if (Offset > 0) {
2634 // add xN, xN, #offset
2635 BuildMI(MBB, MI, DL, get(AArch64::ADDXri))
2636 .addDef(Reg)
2638 .addImm(Offset)
2639 .addImm(0);
2640 } else {
2641 // sub xN, xN, #offset
2642 BuildMI(MBB, MI, DL, get(AArch64::SUBXri))
2643 .addDef(Reg)
2645 .addImm(-Offset)
2646 .addImm(0);
2647 }
2648 // ldr xN, [xN]
2649 BuildMI(MBB, MI, DL, get(AArch64::LDRXui))
2650 .addDef(Reg)
2652 .addImm(0);
2653 } else {
2654 // Cases that are larger than +/- 4095 and not a multiple of 8, or larger
2655 // than 23760.
2656 // It might be nice to use AArch64::MOVi32imm here, which would get
2657 // expanded in PreSched2 after PostRA, but our lone scratch Reg already
2658 // contains the MRS result. findScratchNonCalleeSaveRegister() in
2659 // AArch64FrameLowering might help us find such a scratch register
2660 // though. If we failed to find a scratch register, we could emit a
2661 // stream of add instructions to build up the immediate. Or, we could try
2662 // to insert a AArch64::MOVi32imm before register allocation so that we
2663 // didn't need to scavenge for a scratch register.
2664 report_fatal_error("Unable to encode Stack Protector Guard Offset");
2665 }
2666 MBB.erase(MI);
2667 return true;
2668 }
2669
2670 const GlobalValue *GV =
2671 cast<GlobalValue>((*MI.memoperands_begin())->getValue());
2672 const TargetMachine &TM = MBB.getParent()->getTarget();
2673 unsigned OpFlags = Subtarget.ClassifyGlobalReference(GV, TM);
2674 const unsigned char MO_NC = AArch64II::MO_NC;
2675
2676 unsigned GuardWidth = M.getStackProtectorGuardValueWidth().value_or(
2677 Subtarget.isTargetILP32() ? 4 : 8);
2678 if (GuardWidth != 4 && GuardWidth != 8)
2679 report_fatal_error("Unsupported stack protector value width");
2680 if ((OpFlags & AArch64II::MO_GOT) != 0) {
2681 BuildMI(MBB, MI, DL, get(AArch64::LOADgot), Reg)
2682 .addGlobalAddress(GV, 0, OpFlags);
2683 if (GuardWidth == 4) {
2684 unsigned Reg32 = TRI->getSubReg(Reg, AArch64::sub_32);
2685 BuildMI(MBB, MI, DL, get(AArch64::LDRWui))
2686 .addDef(Reg32)
2688 .addImm(0)
2689 .addMemOperand(*MI.memoperands_begin())
2691 } else {
2692 BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg)
2694 .addImm(0)
2695 .addMemOperand(*MI.memoperands_begin());
2696 }
2697 } else if (TM.getCodeModel() == CodeModel::Large) {
2698 BuildMI(MBB, MI, DL, get(AArch64::MOVZXi), Reg)
2699 .addGlobalAddress(GV, 0, AArch64II::MO_G0 | MO_NC)
2700 .addImm(0);
2701 BuildMI(MBB, MI, DL, get(AArch64::MOVKXi), Reg)
2703 .addGlobalAddress(GV, 0, AArch64II::MO_G1 | MO_NC)
2704 .addImm(16);
2705 BuildMI(MBB, MI, DL, get(AArch64::MOVKXi), Reg)
2707 .addGlobalAddress(GV, 0, AArch64II::MO_G2 | MO_NC)
2708 .addImm(32);
2709 BuildMI(MBB, MI, DL, get(AArch64::MOVKXi), Reg)
2712 .addImm(48);
2713 if (GuardWidth == 4) {
2714 unsigned Reg32 = TRI->getSubReg(Reg, AArch64::sub_32);
2715 BuildMI(MBB, MI, DL, get(AArch64::LDRWui))
2716 .addDef(Reg32)
2718 .addImm(0)
2719 .addMemOperand(*MI.memoperands_begin())
2721 } else {
2722 BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg)
2724 .addImm(0)
2725 .addMemOperand(*MI.memoperands_begin());
2726 }
2727 } else {
2728 BuildMI(MBB, MI, DL, get(AArch64::ADRP), Reg)
2729 .addGlobalAddress(GV, 0, OpFlags | AArch64II::MO_PAGE);
2730 unsigned char LoFlags = OpFlags | AArch64II::MO_PAGEOFF | MO_NC;
2731 if (GuardWidth == 4) {
2732 unsigned Reg32 = TRI->getSubReg(Reg, AArch64::sub_32);
2733 BuildMI(MBB, MI, DL, get(AArch64::LDRWui))
2734 .addDef(Reg32)
2736 .addGlobalAddress(GV, 0, LoFlags)
2737 .addMemOperand(*MI.memoperands_begin())
2739 } else {
2740 BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg)
2742 .addGlobalAddress(GV, 0, LoFlags)
2743 .addMemOperand(*MI.memoperands_begin());
2744 }
2745 }
2746 // To match MSVC. Unlike x86_64 which uses xor instruction to mix the cookie,
2747 // we use sub instruction to mix the cookie on aarch64.
2748 // The mixing happens here in expandPostRAPseudo (after RA) to ensure we use
2749 // the final frame pointer value.
2750 if (Subtarget.getTargetTriple().isOSMSVCRT())
2751 BuildMI(MBB, MI, DL, get(AArch64::SUBXrr), Reg)
2752 .addReg(AArch64::FP)
2754
2755 MBB.erase(MI);
2756
2757 return true;
2758}
2759
2760// Return true if this instruction simply sets its single destination register
2761// to zero. This is equivalent to a register rename of the zero-register.
2763 switch (MI.getOpcode()) {
2764 default:
2765 break;
2766 case AArch64::MOVZWi:
2767 case AArch64::MOVZXi: // movz Rd, #0 (LSL #0)
2768 if (MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == 0) {
2769 assert(MI.getDesc().getNumOperands() == 3 &&
2770 MI.getOperand(2).getImm() == 0 && "invalid MOVZi operands");
2771 return true;
2772 }
2773 break;
2774 case AArch64::ANDWri: // and Rd, Rzr, #imm
2775 return MI.getOperand(1).getReg() == AArch64::WZR;
2776 case AArch64::ANDXri:
2777 return MI.getOperand(1).getReg() == AArch64::XZR;
2778 case TargetOpcode::COPY:
2779 return MI.getOperand(1).getReg() == AArch64::WZR;
2780 }
2781 return false;
2782}
2783
2784// Return true if this instruction simply renames a general register without
2785// modifying bits.
2787 switch (MI.getOpcode()) {
2788 default:
2789 break;
2790 case TargetOpcode::COPY: {
2791 // GPR32 copies will by lowered to ORRXrs
2792 Register DstReg = MI.getOperand(0).getReg();
2793 return (AArch64::GPR32RegClass.contains(DstReg) ||
2794 AArch64::GPR64RegClass.contains(DstReg));
2795 }
2796 case AArch64::ORRXrs: // orr Xd, Xzr, Xm (LSL #0)
2797 if (MI.getOperand(1).getReg() == AArch64::XZR) {
2798 assert(MI.getDesc().getNumOperands() == 4 &&
2799 MI.getOperand(3).getImm() == 0 && "invalid ORRrs operands");
2800 return true;
2801 }
2802 break;
2803 case AArch64::ADDXri: // add Xd, Xn, #0 (LSL #0)
2804 if (MI.getOperand(2).getImm() == 0) {
2805 assert(MI.getDesc().getNumOperands() == 4 &&
2806 MI.getOperand(3).getImm() == 0 && "invalid ADDXri operands");
2807 return true;
2808 }
2809 break;
2810 }
2811 return false;
2812}
2813
2814// Return true if this instruction simply renames a general register without
2815// modifying bits.
2817 switch (MI.getOpcode()) {
2818 default:
2819 break;
2820 case TargetOpcode::COPY: {
2821 Register DstReg = MI.getOperand(0).getReg();
2822 return AArch64::FPR128RegClass.contains(DstReg);
2823 }
2824 case AArch64::ORRv16i8:
2825 if (MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) {
2826 assert(MI.getDesc().getNumOperands() == 3 && MI.getOperand(0).isReg() &&
2827 "invalid ORRv16i8 operands");
2828 return true;
2829 }
2830 break;
2831 }
2832 return false;
2833}
2834
2835static bool isFrameLoadOpcode(int Opcode) {
2836 switch (Opcode) {
2837 default:
2838 return false;
2839 case AArch64::LDRWui:
2840 case AArch64::LDRXui:
2841 case AArch64::LDRBui:
2842 case AArch64::LDRHui:
2843 case AArch64::LDRSui:
2844 case AArch64::LDRDui:
2845 case AArch64::LDRQui:
2846 case AArch64::LDR_PXI:
2847 return true;
2848 }
2849}
2850
2852 int &FrameIndex) const {
2853 if (!isFrameLoadOpcode(MI.getOpcode()))
2854 return Register();
2855
2856 if (MI.getOperand(0).getSubReg() == 0 && MI.getOperand(1).isFI() &&
2857 MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) {
2858 FrameIndex = MI.getOperand(1).getIndex();
2859 return MI.getOperand(0).getReg();
2860 }
2861 return Register();
2862}
2863
2864static bool isFrameStoreOpcode(int Opcode) {
2865 switch (Opcode) {
2866 default:
2867 return false;
2868 case AArch64::STRWui:
2869 case AArch64::STRXui:
2870 case AArch64::STRBui:
2871 case AArch64::STRHui:
2872 case AArch64::STRSui:
2873 case AArch64::STRDui:
2874 case AArch64::STRQui:
2875 case AArch64::STR_PXI:
2876 return true;
2877 }
2878}
2879
2881 int &FrameIndex) const {
2882 if (!isFrameStoreOpcode(MI.getOpcode()))
2883 return Register();
2884
2885 if (MI.getOperand(0).getSubReg() == 0 && MI.getOperand(1).isFI() &&
2886 MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) {
2887 FrameIndex = MI.getOperand(1).getIndex();
2888 return MI.getOperand(0).getReg();
2889 }
2890 return Register();
2891}
2892
2894 int &FrameIndex) const {
2895 if (!isFrameStoreOpcode(MI.getOpcode()))
2896 return Register();
2897
2898 if (Register Reg = isStoreToStackSlot(MI, FrameIndex))
2899 return Reg;
2900
2902 if (hasStoreToStackSlot(MI, Accesses)) {
2903 if (Accesses.size() > 1)
2904 return Register();
2905
2906 FrameIndex =
2907 cast<FixedStackPseudoSourceValue>(Accesses.front()->getPseudoValue())
2908 ->getFrameIndex();
2909 return MI.getOperand(0).getReg();
2910 }
2911 return Register();
2912}
2913
2915 int &FrameIndex) const {
2916 if (!isFrameLoadOpcode(MI.getOpcode()))
2917 return Register();
2918
2919 if (Register Reg = isLoadFromStackSlot(MI, FrameIndex))
2920 return Reg;
2921
2923 if (hasLoadFromStackSlot(MI, Accesses)) {
2924 if (Accesses.size() > 1)
2925 return Register();
2926
2927 FrameIndex =
2928 cast<FixedStackPseudoSourceValue>(Accesses.front()->getPseudoValue())
2929 ->getFrameIndex();
2930 return MI.getOperand(0).getReg();
2931 }
2932 return Register();
2933}
2934
2935/// Check all MachineMemOperands for a hint to suppress pairing.
2937 return llvm::any_of(MI.memoperands(), [](MachineMemOperand *MMO) {
2938 return MMO->getFlags() & MOSuppressPair;
2939 });
2940}
2941
2942/// Set a flag on the first MachineMemOperand to suppress pairing.
2944 if (MI.memoperands_empty())
2945 return;
2946 (*MI.memoperands_begin())->setFlags(MOSuppressPair);
2947}
2948
2949/// Check all MachineMemOperands for a hint that the load/store is strided.
2951 return llvm::any_of(MI.memoperands(), [](MachineMemOperand *MMO) {
2952 return MMO->getFlags() & MOStridedAccess;
2953 });
2954}
2955
2957 switch (Opc) {
2958 default:
2959 return false;
2960 case AArch64::STURSi:
2961 case AArch64::STRSpre:
2962 case AArch64::STURDi:
2963 case AArch64::STRDpre:
2964 case AArch64::STURQi:
2965 case AArch64::STRQpre:
2966 case AArch64::STURBBi:
2967 case AArch64::STURHHi:
2968 case AArch64::STURWi:
2969 case AArch64::STRWpre:
2970 case AArch64::STURXi:
2971 case AArch64::STRXpre:
2972 case AArch64::LDURSi:
2973 case AArch64::LDRSpre:
2974 case AArch64::LDURDi:
2975 case AArch64::LDRDpre:
2976 case AArch64::LDURQi:
2977 case AArch64::LDRQpre:
2978 case AArch64::LDURWi:
2979 case AArch64::LDRWpre:
2980 case AArch64::LDURXi:
2981 case AArch64::LDRXpre:
2982 case AArch64::LDRSWpre:
2983 case AArch64::LDURSWi:
2984 case AArch64::LDURHHi:
2985 case AArch64::LDURBBi:
2986 case AArch64::LDURSBWi:
2987 case AArch64::LDURSHWi:
2988 return true;
2989 }
2990}
2991
2992std::optional<unsigned> AArch64InstrInfo::getUnscaledLdSt(unsigned Opc) {
2993 switch (Opc) {
2994 default: return {};
2995 case AArch64::PRFMui: return AArch64::PRFUMi;
2996 case AArch64::LDRXui: return AArch64::LDURXi;
2997 case AArch64::LDRWui: return AArch64::LDURWi;
2998 case AArch64::LDRBui: return AArch64::LDURBi;
2999 case AArch64::LDRHui: return AArch64::LDURHi;
3000 case AArch64::LDRSui: return AArch64::LDURSi;
3001 case AArch64::LDRDui: return AArch64::LDURDi;
3002 case AArch64::LDRQui: return AArch64::LDURQi;
3003 case AArch64::LDRBBui: return AArch64::LDURBBi;
3004 case AArch64::LDRHHui: return AArch64::LDURHHi;
3005 case AArch64::LDRSBXui: return AArch64::LDURSBXi;
3006 case AArch64::LDRSBWui: return AArch64::LDURSBWi;
3007 case AArch64::LDRSHXui: return AArch64::LDURSHXi;
3008 case AArch64::LDRSHWui: return AArch64::LDURSHWi;
3009 case AArch64::LDRSWui: return AArch64::LDURSWi;
3010 case AArch64::STRXui: return AArch64::STURXi;
3011 case AArch64::STRWui: return AArch64::STURWi;
3012 case AArch64::STRBui: return AArch64::STURBi;
3013 case AArch64::STRHui: return AArch64::STURHi;
3014 case AArch64::STRSui: return AArch64::STURSi;
3015 case AArch64::STRDui: return AArch64::STURDi;
3016 case AArch64::STRQui: return AArch64::STURQi;
3017 case AArch64::STRBBui: return AArch64::STURBBi;
3018 case AArch64::STRHHui: return AArch64::STURHHi;
3019 }
3020}
3021
3023 switch (Opc) {
3024 default:
3025 llvm_unreachable("Unhandled Opcode in getLoadStoreImmIdx");
3026 case AArch64::ADDG:
3027 case AArch64::LDAPURBi:
3028 case AArch64::LDAPURHi:
3029 case AArch64::LDAPURi:
3030 case AArch64::LDAPURSBWi:
3031 case AArch64::LDAPURSBXi:
3032 case AArch64::LDAPURSHWi:
3033 case AArch64::LDAPURSHXi:
3034 case AArch64::LDAPURSWi:
3035 case AArch64::LDAPURXi:
3036 case AArch64::LDR_PPXI:
3037 case AArch64::LDR_PXI:
3038 case AArch64::LDR_ZXI:
3039 case AArch64::LDR_ZZXI:
3040 case AArch64::LDR_ZZXI_STRIDED_CONTIGUOUS:
3041 case AArch64::LDR_ZZZXI:
3042 case AArch64::LDR_ZZZZXI:
3043 case AArch64::LDR_ZZZZXI_STRIDED_CONTIGUOUS:
3044 case AArch64::LDRBBui:
3045 case AArch64::LDRBui:
3046 case AArch64::LDRDui:
3047 case AArch64::LDRHHui:
3048 case AArch64::LDRHui:
3049 case AArch64::LDRQui:
3050 case AArch64::LDRSBWui:
3051 case AArch64::LDRSBXui:
3052 case AArch64::LDRSHWui:
3053 case AArch64::LDRSHXui:
3054 case AArch64::LDRSui:
3055 case AArch64::LDRSWui:
3056 case AArch64::LDRWui:
3057 case AArch64::LDRXui:
3058 case AArch64::LDURBBi:
3059 case AArch64::LDURBi:
3060 case AArch64::LDURDi:
3061 case AArch64::LDURHHi:
3062 case AArch64::LDURHi:
3063 case AArch64::LDURQi:
3064 case AArch64::LDURSBWi:
3065 case AArch64::LDURSBXi:
3066 case AArch64::LDURSHWi:
3067 case AArch64::LDURSHXi:
3068 case AArch64::LDURSi:
3069 case AArch64::LDURSWi:
3070 case AArch64::LDURWi:
3071 case AArch64::LDURXi:
3072 case AArch64::PRFMui:
3073 case AArch64::PRFUMi:
3074 case AArch64::ST2Gi:
3075 case AArch64::STGi:
3076 case AArch64::STLURBi:
3077 case AArch64::STLURHi:
3078 case AArch64::STLURWi:
3079 case AArch64::STLURXi:
3080 case AArch64::StoreSwiftAsyncContext:
3081 case AArch64::STR_PPXI:
3082 case AArch64::STR_PXI:
3083 case AArch64::STR_ZXI:
3084 case AArch64::STR_ZZXI:
3085 case AArch64::STR_ZZXI_STRIDED_CONTIGUOUS:
3086 case AArch64::STR_ZZZXI:
3087 case AArch64::STR_ZZZZXI:
3088 case AArch64::STR_ZZZZXI_STRIDED_CONTIGUOUS:
3089 case AArch64::STRBBui:
3090 case AArch64::STRBui:
3091 case AArch64::STRDui:
3092 case AArch64::STRHHui:
3093 case AArch64::STRHui:
3094 case AArch64::STRQui:
3095 case AArch64::STRSui:
3096 case AArch64::STRWui:
3097 case AArch64::STRXui:
3098 case AArch64::STURBBi:
3099 case AArch64::STURBi:
3100 case AArch64::STURDi:
3101 case AArch64::STURHHi:
3102 case AArch64::STURHi:
3103 case AArch64::STURQi:
3104 case AArch64::STURSi:
3105 case AArch64::STURWi:
3106 case AArch64::STURXi:
3107 case AArch64::STZ2Gi:
3108 case AArch64::STZGi:
3109 case AArch64::TAGPstack:
3110 case AArch64::ATOMIC_STORE_HINT_Bi:
3111 case AArch64::ATOMIC_STORE_HINT_Hi:
3112 case AArch64::ATOMIC_STORE_HINT_Wi:
3113 case AArch64::ATOMIC_STORE_HINT_Si:
3114 case AArch64::ATOMIC_STORE_HINT_Xi:
3115 case AArch64::ATOMIC_STORE_HINT_Di:
3116 case AArch64::ATOMIC_STORE_HINT_Bui:
3117 case AArch64::ATOMIC_STORE_HINT_Hui:
3118 case AArch64::ATOMIC_STORE_HINT_Wui:
3119 case AArch64::ATOMIC_STORE_HINT_Sui:
3120 case AArch64::ATOMIC_STORE_HINT_Xui:
3121 case AArch64::ATOMIC_STORE_HINT_Dui:
3122 return 2;
3123 case AArch64::LD1B_D_IMM:
3124 case AArch64::LD1B_H_IMM:
3125 case AArch64::LD1B_IMM:
3126 case AArch64::LD1B_S_IMM:
3127 case AArch64::LD1D_IMM:
3128 case AArch64::LD1H_D_IMM:
3129 case AArch64::LD1H_IMM:
3130 case AArch64::LD1H_S_IMM:
3131 case AArch64::LD1RB_D_IMM:
3132 case AArch64::LD1RB_H_IMM:
3133 case AArch64::LD1RB_IMM:
3134 case AArch64::LD1RB_S_IMM:
3135 case AArch64::LD1RD_IMM:
3136 case AArch64::LD1RH_D_IMM:
3137 case AArch64::LD1RH_IMM:
3138 case AArch64::LD1RH_S_IMM:
3139 case AArch64::LD1RSB_D_IMM:
3140 case AArch64::LD1RSB_H_IMM:
3141 case AArch64::LD1RSB_S_IMM:
3142 case AArch64::LD1RSH_D_IMM:
3143 case AArch64::LD1RSH_S_IMM:
3144 case AArch64::LD1RSW_IMM:
3145 case AArch64::LD1RW_D_IMM:
3146 case AArch64::LD1RW_IMM:
3147 case AArch64::LD1SB_D_IMM:
3148 case AArch64::LD1SB_H_IMM:
3149 case AArch64::LD1SB_S_IMM:
3150 case AArch64::LD1SH_D_IMM:
3151 case AArch64::LD1SH_S_IMM:
3152 case AArch64::LD1SW_D_IMM:
3153 case AArch64::LD1W_D_IMM:
3154 case AArch64::LD1W_IMM:
3155 case AArch64::LD2B_IMM:
3156 case AArch64::LD2D_IMM:
3157 case AArch64::LD2H_IMM:
3158 case AArch64::LD2W_IMM:
3159 case AArch64::LD3B_IMM:
3160 case AArch64::LD3D_IMM:
3161 case AArch64::LD3H_IMM:
3162 case AArch64::LD3W_IMM:
3163 case AArch64::LD4B_IMM:
3164 case AArch64::LD4D_IMM:
3165 case AArch64::LD4H_IMM:
3166 case AArch64::LD4W_IMM:
3167 case AArch64::LDG:
3168 case AArch64::LDNF1B_D_IMM:
3169 case AArch64::LDNF1B_H_IMM:
3170 case AArch64::LDNF1B_IMM:
3171 case AArch64::LDNF1B_S_IMM:
3172 case AArch64::LDNF1D_IMM:
3173 case AArch64::LDNF1H_D_IMM:
3174 case AArch64::LDNF1H_IMM:
3175 case AArch64::LDNF1H_S_IMM:
3176 case AArch64::LDNF1SB_D_IMM:
3177 case AArch64::LDNF1SB_H_IMM:
3178 case AArch64::LDNF1SB_S_IMM:
3179 case AArch64::LDNF1SH_D_IMM:
3180 case AArch64::LDNF1SH_S_IMM:
3181 case AArch64::LDNF1SW_D_IMM:
3182 case AArch64::LDNF1W_D_IMM:
3183 case AArch64::LDNF1W_IMM:
3184 case AArch64::LDNPDi:
3185 case AArch64::LDNPQi:
3186 case AArch64::LDNPSi:
3187 case AArch64::LDNPWi:
3188 case AArch64::LDNPXi:
3189 case AArch64::LDNT1B_ZRI:
3190 case AArch64::LDNT1D_ZRI:
3191 case AArch64::LDNT1H_ZRI:
3192 case AArch64::LDNT1W_ZRI:
3193 case AArch64::LDPDi:
3194 case AArch64::LDPQi:
3195 case AArch64::LDPSi:
3196 case AArch64::LDPWi:
3197 case AArch64::LDPXi:
3198 case AArch64::LDRBBpost:
3199 case AArch64::LDRBBpre:
3200 case AArch64::LDRBpost:
3201 case AArch64::LDRBpre:
3202 case AArch64::LDRDpost:
3203 case AArch64::LDRDpre:
3204 case AArch64::LDRHHpost:
3205 case AArch64::LDRHHpre:
3206 case AArch64::LDRHpost:
3207 case AArch64::LDRHpre:
3208 case AArch64::LDRQpost:
3209 case AArch64::LDRQpre:
3210 case AArch64::LDRSpost:
3211 case AArch64::LDRSpre:
3212 case AArch64::LDRWpost:
3213 case AArch64::LDRWpre:
3214 case AArch64::LDRXpost:
3215 case AArch64::LDRXpre:
3216 case AArch64::ST1B_D_IMM:
3217 case AArch64::ST1B_H_IMM:
3218 case AArch64::ST1B_IMM:
3219 case AArch64::ST1B_S_IMM:
3220 case AArch64::ST1D_IMM:
3221 case AArch64::ST1H_D_IMM:
3222 case AArch64::ST1H_IMM:
3223 case AArch64::ST1H_S_IMM:
3224 case AArch64::ST1W_D_IMM:
3225 case AArch64::ST1W_IMM:
3226 case AArch64::ST2B_IMM:
3227 case AArch64::ST2D_IMM:
3228 case AArch64::ST2H_IMM:
3229 case AArch64::ST2W_IMM:
3230 case AArch64::ST3B_IMM:
3231 case AArch64::ST3D_IMM:
3232 case AArch64::ST3H_IMM:
3233 case AArch64::ST3W_IMM:
3234 case AArch64::ST4B_IMM:
3235 case AArch64::ST4D_IMM:
3236 case AArch64::ST4H_IMM:
3237 case AArch64::ST4W_IMM:
3238 case AArch64::STGPi:
3239 case AArch64::STGPreIndex:
3240 case AArch64::STZGPreIndex:
3241 case AArch64::ST2GPreIndex:
3242 case AArch64::STZ2GPreIndex:
3243 case AArch64::STGPostIndex:
3244 case AArch64::STZGPostIndex:
3245 case AArch64::ST2GPostIndex:
3246 case AArch64::STZ2GPostIndex:
3247 case AArch64::STNPDi:
3248 case AArch64::STNPQi:
3249 case AArch64::STNPSi:
3250 case AArch64::STNPWi:
3251 case AArch64::STNPXi:
3252 case AArch64::STNT1B_ZRI:
3253 case AArch64::STNT1D_ZRI:
3254 case AArch64::STNT1H_ZRI:
3255 case AArch64::STNT1W_ZRI:
3256 case AArch64::STPDi:
3257 case AArch64::STPQi:
3258 case AArch64::STPSi:
3259 case AArch64::STPWi:
3260 case AArch64::STPXi:
3261 case AArch64::STRBBpost:
3262 case AArch64::STRBBpre:
3263 case AArch64::STRBpost:
3264 case AArch64::STRBpre:
3265 case AArch64::STRDpost:
3266 case AArch64::STRDpre:
3267 case AArch64::STRHHpost:
3268 case AArch64::STRHHpre:
3269 case AArch64::STRHpost:
3270 case AArch64::STRHpre:
3271 case AArch64::STRQpost:
3272 case AArch64::STRQpre:
3273 case AArch64::STRSpost:
3274 case AArch64::STRSpre:
3275 case AArch64::STRWpost:
3276 case AArch64::STRWpre:
3277 case AArch64::STRXpost:
3278 case AArch64::STRXpre:
3279 case AArch64::LD1B_2Z_IMM:
3280 case AArch64::LD1B_2Z_STRIDED_IMM:
3281 case AArch64::LD1H_2Z_IMM:
3282 case AArch64::LD1H_2Z_STRIDED_IMM:
3283 case AArch64::LD1W_2Z_IMM:
3284 case AArch64::LD1W_2Z_STRIDED_IMM:
3285 case AArch64::LD1D_2Z_IMM:
3286 case AArch64::LD1D_2Z_STRIDED_IMM:
3287 case AArch64::LD1B_4Z_IMM:
3288 case AArch64::LD1B_4Z_STRIDED_IMM:
3289 case AArch64::LD1H_4Z_IMM:
3290 case AArch64::LD1H_4Z_STRIDED_IMM:
3291 case AArch64::LD1W_4Z_IMM:
3292 case AArch64::LD1W_4Z_STRIDED_IMM:
3293 case AArch64::LD1D_4Z_IMM:
3294 case AArch64::LD1D_4Z_STRIDED_IMM:
3295 case AArch64::LD1B_2Z_IMM_PSEUDO:
3296 case AArch64::LD1H_2Z_IMM_PSEUDO:
3297 case AArch64::LD1W_2Z_IMM_PSEUDO:
3298 case AArch64::LD1D_2Z_IMM_PSEUDO:
3299 case AArch64::LD1B_4Z_IMM_PSEUDO:
3300 case AArch64::LD1H_4Z_IMM_PSEUDO:
3301 case AArch64::LD1W_4Z_IMM_PSEUDO:
3302 case AArch64::LD1D_4Z_IMM_PSEUDO:
3303 case AArch64::ST1B_2Z_IMM:
3304 case AArch64::ST1B_2Z_STRIDED_IMM:
3305 case AArch64::ST1H_2Z_IMM:
3306 case AArch64::ST1H_2Z_STRIDED_IMM:
3307 case AArch64::ST1W_2Z_IMM:
3308 case AArch64::ST1W_2Z_STRIDED_IMM:
3309 case AArch64::ST1D_2Z_IMM:
3310 case AArch64::ST1D_2Z_STRIDED_IMM:
3311 case AArch64::LDNT1B_2Z_IMM_PSEUDO:
3312 case AArch64::LDNT1B_2Z_IMM:
3313 case AArch64::LDNT1B_2Z_STRIDED_IMM:
3314 case AArch64::LDNT1H_2Z_IMM_PSEUDO:
3315 case AArch64::LDNT1H_2Z_IMM:
3316 case AArch64::LDNT1H_2Z_STRIDED_IMM:
3317 case AArch64::LDNT1W_2Z_IMM_PSEUDO:
3318 case AArch64::LDNT1W_2Z_IMM:
3319 case AArch64::LDNT1W_2Z_STRIDED_IMM:
3320 case AArch64::LDNT1D_2Z_IMM_PSEUDO:
3321 case AArch64::LDNT1D_2Z_IMM:
3322 case AArch64::LDNT1D_2Z_STRIDED_IMM:
3323 case AArch64::STNT1B_2Z_IMM:
3324 case AArch64::STNT1B_2Z_STRIDED_IMM:
3325 case AArch64::STNT1H_2Z_IMM:
3326 case AArch64::STNT1H_2Z_STRIDED_IMM:
3327 case AArch64::STNT1W_2Z_IMM:
3328 case AArch64::STNT1W_2Z_STRIDED_IMM:
3329 case AArch64::STNT1D_2Z_IMM:
3330 case AArch64::STNT1D_2Z_STRIDED_IMM:
3331 case AArch64::ST1B_2Z_IMM_PSEUDO:
3332 case AArch64::ST1H_2Z_IMM_PSEUDO:
3333 case AArch64::ST1W_2Z_IMM_PSEUDO:
3334 case AArch64::ST1D_2Z_IMM_PSEUDO:
3335 case AArch64::STNT1B_2Z_IMM_PSEUDO:
3336 case AArch64::STNT1H_2Z_IMM_PSEUDO:
3337 case AArch64::STNT1W_2Z_IMM_PSEUDO:
3338 case AArch64::STNT1D_2Z_IMM_PSEUDO:
3339 case AArch64::ST1B_4Z_IMM:
3340 case AArch64::ST1B_4Z_STRIDED_IMM:
3341 case AArch64::ST1H_4Z_IMM:
3342 case AArch64::ST1H_4Z_STRIDED_IMM:
3343 case AArch64::ST1W_4Z_IMM:
3344 case AArch64::ST1W_4Z_STRIDED_IMM:
3345 case AArch64::ST1D_4Z_IMM:
3346 case AArch64::ST1D_4Z_STRIDED_IMM:
3347 case AArch64::LDNT1B_4Z_IMM_PSEUDO:
3348 case AArch64::LDNT1B_4Z_IMM:
3349 case AArch64::LDNT1B_4Z_STRIDED_IMM:
3350 case AArch64::LDNT1H_4Z_IMM_PSEUDO:
3351 case AArch64::LDNT1H_4Z_IMM:
3352 case AArch64::LDNT1H_4Z_STRIDED_IMM:
3353 case AArch64::LDNT1W_4Z_IMM_PSEUDO:
3354 case AArch64::LDNT1W_4Z_IMM:
3355 case AArch64::LDNT1W_4Z_STRIDED_IMM:
3356 case AArch64::LDNT1D_4Z_IMM_PSEUDO:
3357 case AArch64::LDNT1D_4Z_IMM:
3358 case AArch64::LDNT1D_4Z_STRIDED_IMM:
3359 case AArch64::STNT1B_4Z_IMM:
3360 case AArch64::STNT1B_4Z_STRIDED_IMM:
3361 case AArch64::STNT1H_4Z_IMM:
3362 case AArch64::STNT1H_4Z_STRIDED_IMM:
3363 case AArch64::STNT1W_4Z_IMM:
3364 case AArch64::STNT1W_4Z_STRIDED_IMM:
3365 case AArch64::STNT1D_4Z_IMM:
3366 case AArch64::STNT1D_4Z_STRIDED_IMM:
3367 case AArch64::ST1B_4Z_IMM_PSEUDO:
3368 case AArch64::ST1H_4Z_IMM_PSEUDO:
3369 case AArch64::ST1W_4Z_IMM_PSEUDO:
3370 case AArch64::ST1D_4Z_IMM_PSEUDO:
3371 case AArch64::STNT1B_4Z_IMM_PSEUDO:
3372 case AArch64::STNT1H_4Z_IMM_PSEUDO:
3373 case AArch64::STNT1W_4Z_IMM_PSEUDO:
3374 case AArch64::STNT1D_4Z_IMM_PSEUDO:
3375 return 3;
3376 case AArch64::LDPDpost:
3377 case AArch64::LDPDpre:
3378 case AArch64::LDPQpost:
3379 case AArch64::LDPQpre:
3380 case AArch64::LDPSpost:
3381 case AArch64::LDPSpre:
3382 case AArch64::LDPWpost:
3383 case AArch64::LDPWpre:
3384 case AArch64::LDPXpost:
3385 case AArch64::LDPXpre:
3386 case AArch64::STGPpre:
3387 case AArch64::STGPpost:
3388 case AArch64::STPDpost:
3389 case AArch64::STPDpre:
3390 case AArch64::STPQpost:
3391 case AArch64::STPQpre:
3392 case AArch64::STPSpost:
3393 case AArch64::STPSpre:
3394 case AArch64::STPWpost:
3395 case AArch64::STPWpre:
3396 case AArch64::STPXpost:
3397 case AArch64::STPXpre:
3398 return 4;
3399 }
3400}
3401
3403 switch (MI.getOpcode()) {
3404 default:
3405 return false;
3406 // Scaled instructions.
3407 case AArch64::STRSui:
3408 case AArch64::STRDui:
3409 case AArch64::STRQui:
3410 case AArch64::STRXui:
3411 case AArch64::STRWui:
3412 case AArch64::LDRSui:
3413 case AArch64::LDRDui:
3414 case AArch64::LDRQui:
3415 case AArch64::LDRXui:
3416 case AArch64::LDRWui:
3417 case AArch64::LDRSWui:
3418 // Unscaled instructions.
3419 case AArch64::STURSi:
3420 case AArch64::STRSpre:
3421 case AArch64::STURDi:
3422 case AArch64::STRDpre:
3423 case AArch64::STURQi:
3424 case AArch64::STRQpre:
3425 case AArch64::STURWi:
3426 case AArch64::STRWpre:
3427 case AArch64::STURXi:
3428 case AArch64::STRXpre:
3429 case AArch64::LDURSi:
3430 case AArch64::LDRSpre:
3431 case AArch64::LDURDi:
3432 case AArch64::LDRDpre:
3433 case AArch64::LDURQi:
3434 case AArch64::LDRQpre:
3435 case AArch64::LDURWi:
3436 case AArch64::LDRWpre:
3437 case AArch64::LDURXi:
3438 case AArch64::LDRXpre:
3439 case AArch64::LDURSWi:
3440 case AArch64::LDRSWpre:
3441 // SVE instructions.
3442 case AArch64::LDR_ZXI:
3443 case AArch64::STR_ZXI:
3444 return true;
3445 }
3446}
3447
3449 switch (MI.getOpcode()) {
3450 default:
3451 assert((!MI.isCall() || !MI.isReturn()) &&
3452 "Unexpected instruction - was a new tail call opcode introduced?");
3453 return false;
3454 case AArch64::TCRETURNdi:
3455 case AArch64::TCRETURNri:
3456 case AArch64::TCRETURNrix16x17:
3457 case AArch64::TCRETURNrix17:
3458 case AArch64::TCRETURNrinotx16:
3459 case AArch64::TCRETURNriALL:
3460 case AArch64::AUTH_TCRETURN:
3461 case AArch64::AUTH_TCRETURN_BTI:
3462 return true;
3463 }
3464}
3465
3467 switch (Opc) {
3468 default:
3469 llvm_unreachable("Opcode has no flag setting equivalent!");
3470 // 32-bit cases:
3471 case AArch64::ADDWri:
3472 return AArch64::ADDSWri;
3473 case AArch64::ADDWrr:
3474 return AArch64::ADDSWrr;
3475 case AArch64::ADDWrs:
3476 return AArch64::ADDSWrs;
3477 case AArch64::ADDWrx:
3478 return AArch64::ADDSWrx;
3479 case AArch64::ANDWri:
3480 return AArch64::ANDSWri;
3481 case AArch64::ANDWrr:
3482 return AArch64::ANDSWrr;
3483 case AArch64::ANDWrs:
3484 return AArch64::ANDSWrs;
3485 case AArch64::BICWrr:
3486 return AArch64::BICSWrr;
3487 case AArch64::BICWrs:
3488 return AArch64::BICSWrs;
3489 case AArch64::SUBWri:
3490 return AArch64::SUBSWri;
3491 case AArch64::SUBWrr:
3492 return AArch64::SUBSWrr;
3493 case AArch64::SUBWrs:
3494 return AArch64::SUBSWrs;
3495 case AArch64::SUBWrx:
3496 return AArch64::SUBSWrx;
3497 // 64-bit cases:
3498 case AArch64::ADDXri:
3499 return AArch64::ADDSXri;
3500 case AArch64::ADDXrr:
3501 return AArch64::ADDSXrr;
3502 case AArch64::ADDXrs:
3503 return AArch64::ADDSXrs;
3504 case AArch64::ADDXrx:
3505 return AArch64::ADDSXrx;
3506 case AArch64::ANDXri:
3507 return AArch64::ANDSXri;
3508 case AArch64::ANDXrr:
3509 return AArch64::ANDSXrr;
3510 case AArch64::ANDXrs:
3511 return AArch64::ANDSXrs;
3512 case AArch64::BICXrr:
3513 return AArch64::BICSXrr;
3514 case AArch64::BICXrs:
3515 return AArch64::BICSXrs;
3516 case AArch64::SUBXri:
3517 return AArch64::SUBSXri;
3518 case AArch64::SUBXrr:
3519 return AArch64::SUBSXrr;
3520 case AArch64::SUBXrs:
3521 return AArch64::SUBSXrs;
3522 case AArch64::SUBXrx:
3523 return AArch64::SUBSXrx;
3524 // SVE instructions:
3525 case AArch64::AND_PPzPP:
3526 return AArch64::ANDS_PPzPP;
3527 case AArch64::BIC_PPzPP:
3528 return AArch64::BICS_PPzPP;
3529 case AArch64::EOR_PPzPP:
3530 return AArch64::EORS_PPzPP;
3531 case AArch64::NAND_PPzPP:
3532 return AArch64::NANDS_PPzPP;
3533 case AArch64::NOR_PPzPP:
3534 return AArch64::NORS_PPzPP;
3535 case AArch64::ORN_PPzPP:
3536 return AArch64::ORNS_PPzPP;
3537 case AArch64::ORR_PPzPP:
3538 return AArch64::ORRS_PPzPP;
3539 case AArch64::BRKA_PPzP:
3540 return AArch64::BRKAS_PPzP;
3541 case AArch64::BRKPA_PPzPP:
3542 return AArch64::BRKPAS_PPzPP;
3543 case AArch64::BRKB_PPzP:
3544 return AArch64::BRKBS_PPzP;
3545 case AArch64::BRKPB_PPzPP:
3546 return AArch64::BRKPBS_PPzPP;
3547 case AArch64::BRKN_PPzP:
3548 return AArch64::BRKNS_PPzP;
3549 case AArch64::RDFFR_PPz:
3550 return AArch64::RDFFRS_PPz;
3551 case AArch64::PTRUE_B:
3552 return AArch64::PTRUES_B;
3553 }
3554}
3555
3556// Is this a candidate for ld/st merging or pairing? For example, we don't
3557// touch volatiles or load/stores that have a hint to avoid pair formation.
3559
3560 bool IsPreLdSt = isPreLdSt(MI);
3561
3562 // If this is a volatile load/store, don't mess with it.
3563 if (MI.hasOrderedMemoryRef())
3564 return false;
3565
3566 // Make sure this is a reg/fi+imm (as opposed to an address reloc).
3567 // For Pre-inc LD/ST, the operand is shifted by one.
3568 assert((MI.getOperand(IsPreLdSt ? 2 : 1).isReg() ||
3569 MI.getOperand(IsPreLdSt ? 2 : 1).isFI()) &&
3570 "Expected a reg or frame index operand.");
3571
3572 // For Pre-indexed addressing quadword instructions, the third operand is the
3573 // immediate value.
3574 bool IsImmPreLdSt = IsPreLdSt && MI.getOperand(3).isImm();
3575
3576 if (!MI.getOperand(2).isImm() && !IsImmPreLdSt)
3577 return false;
3578
3579 // Can't merge/pair if the instruction modifies the base register.
3580 // e.g., ldr x0, [x0]
3581 // This case will never occur with an FI base.
3582 // However, if the instruction is an LDR<S,D,Q,W,X,SW>pre or
3583 // STR<S,D,Q,W,X>pre, it can be merged.
3584 // For example:
3585 // ldr q0, [x11, #32]!
3586 // ldr q1, [x11, #16]
3587 // to
3588 // ldp q0, q1, [x11, #32]!
3589 if (MI.getOperand(1).isReg() && !IsPreLdSt) {
3590 Register BaseReg = MI.getOperand(1).getReg();
3592 if (MI.modifiesRegister(BaseReg, TRI))
3593 return false;
3594 }
3595
3596 // Pairing SVE fills/spills is only valid for little-endian targets that
3597 // implement VLS 128.
3598 switch (MI.getOpcode()) {
3599 default:
3600 break;
3601 case AArch64::LDR_ZXI:
3602 case AArch64::STR_ZXI:
3603 if (!Subtarget.isLittleEndian() ||
3604 Subtarget.getSVEVectorSizeInBits() != 128)
3605 return false;
3606 }
3607
3608 // Check if this load/store has a hint to avoid pair formation.
3609 // MachineMemOperands hints are set by the AArch64StorePairSuppress pass.
3611 return false;
3612
3613 // Do not pair any callee-save store/reload instructions in the
3614 // prologue/epilogue if the CFI information encoded the operations as separate
3615 // instructions, as that will cause the size of the actual prologue to mismatch
3616 // with the prologue size recorded in the Windows CFI.
3617 if ((MI.getFlag(MachineInstr::FrameSetup) ||
3618 MI.getFlag(MachineInstr::FrameDestroy)) &&
3619 MI.getMF()->needsWinCFI())
3620 return false;
3621
3622 // On some CPUs quad load/store pairs are slower than two single load/stores.
3623 if (Subtarget.isPaired128Slow()) {
3624 switch (MI.getOpcode()) {
3625 default:
3626 break;
3627 case AArch64::LDURQi:
3628 case AArch64::STURQi:
3629 case AArch64::LDRQui:
3630 case AArch64::STRQui:
3631 return false;
3632 }
3633 }
3634
3635 return true;
3636}
3637
3640 int64_t &Offset, bool &OffsetIsScalable, LocationSize &Width) const {
3641 if (!LdSt.mayLoadOrStore())
3642 return false;
3643
3644 const MachineOperand *BaseOp;
3645 TypeSize WidthN(0, false);
3646 if (!getMemOperandWithOffsetWidth(LdSt, BaseOp, Offset, OffsetIsScalable,
3647 WidthN))
3648 return false;
3649 // The maximum vscale is 16 under AArch64, return the maximal extent for the
3650 // vector.
3651 Width = LocationSize::precise(WidthN);
3652 BaseOps.push_back(BaseOp);
3653 return true;
3654}
3655
3656std::optional<ExtAddrMode>
3658 const MachineOperand *Base; // Filled with the base operand of MI.
3659 int64_t Offset; // Filled with the offset of MI.
3660 bool OffsetIsScalable;
3661 if (!getMemOperandWithOffset(MemI, Base, Offset, OffsetIsScalable))
3662 return std::nullopt;
3663
3664 if (!Base->isReg())
3665 return std::nullopt;
3666 ExtAddrMode AM;
3667 AM.BaseReg = Base->getReg();
3668 AM.Displacement = Offset;
3669 AM.ScaledReg = 0;
3670 AM.Scale = 0;
3671 return AM;
3672}
3673
3675 Register Reg,
3676 const MachineInstr &AddrI,
3677 ExtAddrMode &AM) const {
3678 // Filter out instructions into which we cannot fold.
3679 unsigned NumBytes;
3680 int64_t OffsetScale = 1;
3681 switch (MemI.getOpcode()) {
3682 default:
3683 return false;
3684
3685 case AArch64::LDURQi:
3686 case AArch64::STURQi:
3687 NumBytes = 16;
3688 break;
3689
3690 case AArch64::LDURDi:
3691 case AArch64::STURDi:
3692 case AArch64::LDURXi:
3693 case AArch64::STURXi:
3694 NumBytes = 8;
3695 break;
3696
3697 case AArch64::LDURWi:
3698 case AArch64::LDURSWi:
3699 case AArch64::STURWi:
3700 NumBytes = 4;
3701 break;
3702
3703 case AArch64::LDURHi:
3704 case AArch64::STURHi:
3705 case AArch64::LDURHHi:
3706 case AArch64::STURHHi:
3707 case AArch64::LDURSHXi:
3708 case AArch64::LDURSHWi:
3709 NumBytes = 2;
3710 break;
3711
3712 case AArch64::LDRBroX:
3713 case AArch64::LDRBBroX:
3714 case AArch64::LDRSBXroX:
3715 case AArch64::LDRSBWroX:
3716 case AArch64::STRBroX:
3717 case AArch64::STRBBroX:
3718 case AArch64::LDURBi:
3719 case AArch64::LDURBBi:
3720 case AArch64::LDURSBXi:
3721 case AArch64::LDURSBWi:
3722 case AArch64::STURBi:
3723 case AArch64::STURBBi:
3724 case AArch64::LDRBui:
3725 case AArch64::LDRBBui:
3726 case AArch64::LDRSBXui:
3727 case AArch64::LDRSBWui:
3728 case AArch64::STRBui:
3729 case AArch64::STRBBui:
3730 NumBytes = 1;
3731 break;
3732
3733 case AArch64::LDRQroX:
3734 case AArch64::STRQroX:
3735 case AArch64::LDRQui:
3736 case AArch64::STRQui:
3737 NumBytes = 16;
3738 OffsetScale = 16;
3739 break;
3740
3741 case AArch64::LDRDroX:
3742 case AArch64::STRDroX:
3743 case AArch64::LDRXroX:
3744 case AArch64::STRXroX:
3745 case AArch64::LDRDui:
3746 case AArch64::STRDui:
3747 case AArch64::LDRXui:
3748 case AArch64::STRXui:
3749 NumBytes = 8;
3750 OffsetScale = 8;
3751 break;
3752
3753 case AArch64::LDRWroX:
3754 case AArch64::LDRSWroX:
3755 case AArch64::STRWroX:
3756 case AArch64::LDRWui:
3757 case AArch64::LDRSWui:
3758 case AArch64::STRWui:
3759 NumBytes = 4;
3760 OffsetScale = 4;
3761 break;
3762
3763 case AArch64::LDRHroX:
3764 case AArch64::STRHroX:
3765 case AArch64::LDRHHroX:
3766 case AArch64::STRHHroX:
3767 case AArch64::LDRSHXroX:
3768 case AArch64::LDRSHWroX:
3769 case AArch64::LDRHui:
3770 case AArch64::STRHui:
3771 case AArch64::LDRHHui:
3772 case AArch64::STRHHui:
3773 case AArch64::LDRSHXui:
3774 case AArch64::LDRSHWui:
3775 NumBytes = 2;
3776 OffsetScale = 2;
3777 break;
3778 }
3779
3780 // Check the fold operand is not the loaded/stored value.
3781 const MachineOperand &BaseRegOp = MemI.getOperand(0);
3782 if (BaseRegOp.isReg() && BaseRegOp.getReg() == Reg)
3783 return false;
3784
3785 // Handle memory instructions with a [Reg, Reg] addressing mode.
3786 if (MemI.getOperand(2).isReg()) {
3787 // Bail if the addressing mode already includes extension of the offset
3788 // register.
3789 if (MemI.getOperand(3).getImm())
3790 return false;
3791
3792 // Check if we actually have a scaled offset.
3793 if (MemI.getOperand(4).getImm() == 0)
3794 OffsetScale = 1;
3795
3796 // If the address instructions is folded into the base register, then the
3797 // addressing mode must not have a scale. Then we can swap the base and the
3798 // scaled registers.
3799 if (MemI.getOperand(1).getReg() == Reg && OffsetScale != 1)
3800 return false;
3801
3802 switch (AddrI.getOpcode()) {
3803 default:
3804 return false;
3805
3806 case AArch64::SBFMXri:
3807 // sxtw Xa, Wm
3808 // ldr Xd, [Xn, Xa, lsl #N]
3809 // ->
3810 // ldr Xd, [Xn, Wm, sxtw #N]
3811 if (AddrI.getOperand(2).getImm() != 0 ||
3812 AddrI.getOperand(3).getImm() != 31)
3813 return false;
3814
3815 AM.BaseReg = MemI.getOperand(1).getReg();
3816 if (AM.BaseReg == Reg)
3817 AM.BaseReg = MemI.getOperand(2).getReg();
3818 AM.ScaledReg = AddrI.getOperand(1).getReg();
3819 AM.Scale = OffsetScale;
3820 AM.Displacement = 0;
3822 return true;
3823
3824 case TargetOpcode::SUBREG_TO_REG: {
3825 // mov Wa, Wm
3826 // ldr Xd, [Xn, Xa, lsl #N]
3827 // ->
3828 // ldr Xd, [Xn, Wm, uxtw #N]
3829
3830 // Zero-extension looks like an ORRWrs followed by a SUBREG_TO_REG.
3831 if (AddrI.getOperand(2).getImm() != AArch64::sub_32)
3832 return false;
3833
3834 const MachineRegisterInfo &MRI = AddrI.getMF()->getRegInfo();
3835 Register OffsetReg = AddrI.getOperand(1).getReg();
3836 if (!OffsetReg.isVirtual() || !MRI.hasOneNonDBGUse(OffsetReg))
3837 return false;
3838
3839 const MachineInstr &DefMI = *MRI.getVRegDef(OffsetReg);
3840 if (DefMI.getOpcode() != AArch64::ORRWrs ||
3841 DefMI.getOperand(1).getReg() != AArch64::WZR ||
3842 DefMI.getOperand(3).getImm() != 0)
3843 return false;
3844
3845 AM.BaseReg = MemI.getOperand(1).getReg();
3846 if (AM.BaseReg == Reg)
3847 AM.BaseReg = MemI.getOperand(2).getReg();
3848 AM.ScaledReg = DefMI.getOperand(2).getReg();
3849 AM.Scale = OffsetScale;
3850 AM.Displacement = 0;
3852 return true;
3853 }
3854 }
3855 }
3856
3857 // Handle memory instructions with a [Reg, #Imm] addressing mode.
3858
3859 // Check we are not breaking a potential conversion to an LDP.
3860 auto validateOffsetForLDP = [](unsigned NumBytes, int64_t OldOffset,
3861 int64_t NewOffset) -> bool {
3862 int64_t MinOffset, MaxOffset;
3863 switch (NumBytes) {
3864 default:
3865 return true;
3866 case 4:
3867 MinOffset = -256;
3868 MaxOffset = 252;
3869 break;
3870 case 8:
3871 MinOffset = -512;
3872 MaxOffset = 504;
3873 break;
3874 case 16:
3875 MinOffset = -1024;
3876 MaxOffset = 1008;
3877 break;
3878 }
3879 return OldOffset < MinOffset || OldOffset > MaxOffset ||
3880 (NewOffset >= MinOffset && NewOffset <= MaxOffset);
3881 };
3882 auto canFoldAddSubImmIntoAddrMode = [&](int64_t Disp) -> bool {
3883 int64_t OldOffset = MemI.getOperand(2).getImm() * OffsetScale;
3884 int64_t NewOffset = OldOffset + Disp;
3885 if (!isLegalAddressingMode(NumBytes, NewOffset, /* Scale */ 0))
3886 return false;
3887 // If the old offset would fit into an LDP, but the new offset wouldn't,
3888 // bail out.
3889 if (!validateOffsetForLDP(NumBytes, OldOffset, NewOffset))
3890 return false;
3891 AM.BaseReg = AddrI.getOperand(1).getReg();
3892 AM.ScaledReg = 0;
3893 AM.Scale = 0;
3894 AM.Displacement = NewOffset;
3896 return true;
3897 };
3898
3899 auto canFoldAddRegIntoAddrMode =
3900 [&](int64_t Scale,
3902 if (MemI.getOperand(2).getImm() != 0)
3903 return false;
3904 if ((unsigned)Scale != Scale)
3905 return false;
3906 if (!isLegalAddressingMode(NumBytes, /* Offset */ 0, Scale))
3907 return false;
3908 AM.BaseReg = AddrI.getOperand(1).getReg();
3909 AM.ScaledReg = AddrI.getOperand(2).getReg();
3910 AM.Scale = Scale;
3911 AM.Displacement = 0;
3912 AM.Form = Form;
3913 return true;
3914 };
3915
3916 auto avoidSlowSTRQ = [&](const MachineInstr &MemI) {
3917 unsigned Opcode = MemI.getOpcode();
3918 return (Opcode == AArch64::STURQi || Opcode == AArch64::STRQui) &&
3919 Subtarget.isSTRQroSlow();
3920 };
3921
3922 int64_t Disp = 0;
3923 const bool OptSize = MemI.getMF()->getFunction().hasOptSize();
3924 switch (AddrI.getOpcode()) {
3925 default:
3926 return false;
3927
3928 case AArch64::ADDXri:
3929 // add Xa, Xn, #N
3930 // ldr Xd, [Xa, #M]
3931 // ->
3932 // ldr Xd, [Xn, #N'+M]
3933 Disp = AddrI.getOperand(2).getImm() << AddrI.getOperand(3).getImm();
3934 return canFoldAddSubImmIntoAddrMode(Disp);
3935
3936 case AArch64::SUBXri:
3937 // sub Xa, Xn, #N
3938 // ldr Xd, [Xa, #M]
3939 // ->
3940 // ldr Xd, [Xn, #N'+M]
3941 Disp = AddrI.getOperand(2).getImm() << AddrI.getOperand(3).getImm();
3942 return canFoldAddSubImmIntoAddrMode(-Disp);
3943
3944 case AArch64::ADDXrs: {
3945 // add Xa, Xn, Xm, lsl #N
3946 // ldr Xd, [Xa]
3947 // ->
3948 // ldr Xd, [Xn, Xm, lsl #N]
3949
3950 // Don't fold the add if the result would be slower, unless optimising for
3951 // size.
3952 unsigned Shift = static_cast<unsigned>(AddrI.getOperand(3).getImm());
3954 return false;
3955 Shift = AArch64_AM::getShiftValue(Shift);
3956 if (!OptSize) {
3957 if (Shift != 2 && Shift != 3 && Subtarget.hasAddrLSLSlow14())
3958 return false;
3959 if (avoidSlowSTRQ(MemI))
3960 return false;
3961 }
3962 return canFoldAddRegIntoAddrMode(1ULL << Shift);
3963 }
3964
3965 case AArch64::ADDXrr:
3966 // add Xa, Xn, Xm
3967 // ldr Xd, [Xa]
3968 // ->
3969 // ldr Xd, [Xn, Xm, lsl #0]
3970
3971 // Don't fold the add if the result would be slower, unless optimising for
3972 // size.
3973 if (!OptSize && avoidSlowSTRQ(MemI))
3974 return false;
3975 return canFoldAddRegIntoAddrMode(1);
3976
3977 case AArch64::ADDXrx:
3978 // add Xa, Xn, Wm, {s,u}xtw #N
3979 // ldr Xd, [Xa]
3980 // ->
3981 // ldr Xd, [Xn, Wm, {s,u}xtw #N]
3982
3983 // Don't fold the add if the result would be slower, unless optimising for
3984 // size.
3985 if (!OptSize && avoidSlowSTRQ(MemI))
3986 return false;
3987
3988 // Can fold only sign-/zero-extend of a word.
3989 unsigned Imm = static_cast<unsigned>(AddrI.getOperand(3).getImm());
3991 if (Extend != AArch64_AM::UXTW && Extend != AArch64_AM::SXTW)
3992 return false;
3993
3994 return canFoldAddRegIntoAddrMode(
3998 }
3999}
4000
4001// Given an opcode for an instruction with a [Reg, #Imm] addressing mode,
4002// return the opcode of an instruction performing the same operation, but using
4003// the [Reg, Reg] addressing mode.
4004static unsigned regOffsetOpcode(unsigned Opcode) {
4005 switch (Opcode) {
4006 default:
4007 llvm_unreachable("Address folding not implemented for instruction");
4008
4009 case AArch64::LDURQi:
4010 case AArch64::LDRQui:
4011 return AArch64::LDRQroX;
4012 case AArch64::STURQi:
4013 case AArch64::STRQui:
4014 return AArch64::STRQroX;
4015 case AArch64::LDURDi:
4016 case AArch64::LDRDui:
4017 return AArch64::LDRDroX;
4018 case AArch64::STURDi:
4019 case AArch64::STRDui:
4020 return AArch64::STRDroX;
4021 case AArch64::LDURXi:
4022 case AArch64::LDRXui:
4023 return AArch64::LDRXroX;
4024 case AArch64::STURXi:
4025 case AArch64::STRXui:
4026 return AArch64::STRXroX;
4027 case AArch64::LDURWi:
4028 case AArch64::LDRWui:
4029 return AArch64::LDRWroX;
4030 case AArch64::LDURSWi:
4031 case AArch64::LDRSWui:
4032 return AArch64::LDRSWroX;
4033 case AArch64::STURWi:
4034 case AArch64::STRWui:
4035 return AArch64::STRWroX;
4036 case AArch64::LDURHi:
4037 case AArch64::LDRHui:
4038 return AArch64::LDRHroX;
4039 case AArch64::STURHi:
4040 case AArch64::STRHui:
4041 return AArch64::STRHroX;
4042 case AArch64::LDURHHi:
4043 case AArch64::LDRHHui:
4044 return AArch64::LDRHHroX;
4045 case AArch64::STURHHi:
4046 case AArch64::STRHHui:
4047 return AArch64::STRHHroX;
4048 case AArch64::LDURSHXi:
4049 case AArch64::LDRSHXui:
4050 return AArch64::LDRSHXroX;
4051 case AArch64::LDURSHWi:
4052 case AArch64::LDRSHWui:
4053 return AArch64::LDRSHWroX;
4054 case AArch64::LDURBi:
4055 case AArch64::LDRBui:
4056 return AArch64::LDRBroX;
4057 case AArch64::LDURBBi:
4058 case AArch64::LDRBBui:
4059 return AArch64::LDRBBroX;
4060 case AArch64::LDURSBXi:
4061 case AArch64::LDRSBXui:
4062 return AArch64::LDRSBXroX;
4063 case AArch64::LDURSBWi:
4064 case AArch64::LDRSBWui:
4065 return AArch64::LDRSBWroX;
4066 case AArch64::STURBi:
4067 case AArch64::STRBui:
4068 return AArch64::STRBroX;
4069 case AArch64::STURBBi:
4070 case AArch64::STRBBui:
4071 return AArch64::STRBBroX;
4072 }
4073}
4074
4075// Given an opcode for an instruction with a [Reg, #Imm] addressing mode, return
4076// the opcode of an instruction performing the same operation, but using the
4077// [Reg, #Imm] addressing mode with scaled offset.
4078unsigned scaledOffsetOpcode(unsigned Opcode, unsigned &Scale) {
4079 switch (Opcode) {
4080 default:
4081 llvm_unreachable("Address folding not implemented for instruction");
4082
4083 case AArch64::LDURQi:
4084 Scale = 16;
4085 return AArch64::LDRQui;
4086 case AArch64::STURQi:
4087 Scale = 16;
4088 return AArch64::STRQui;
4089 case AArch64::LDURDi:
4090 Scale = 8;
4091 return AArch64::LDRDui;
4092 case AArch64::STURDi:
4093 Scale = 8;
4094 return AArch64::STRDui;
4095 case AArch64::LDURXi:
4096 Scale = 8;
4097 return AArch64::LDRXui;
4098 case AArch64::STURXi:
4099 Scale = 8;
4100 return AArch64::STRXui;
4101 case AArch64::LDURWi:
4102 Scale = 4;
4103 return AArch64::LDRWui;
4104 case AArch64::LDURSWi:
4105 Scale = 4;
4106 return AArch64::LDRSWui;
4107 case AArch64::STURWi:
4108 Scale = 4;
4109 return AArch64::STRWui;
4110 case AArch64::LDURHi:
4111 Scale = 2;
4112 return AArch64::LDRHui;
4113 case AArch64::STURHi:
4114 Scale = 2;
4115 return AArch64::STRHui;
4116 case AArch64::LDURHHi:
4117 Scale = 2;
4118 return AArch64::LDRHHui;
4119 case AArch64::STURHHi:
4120 Scale = 2;
4121 return AArch64::STRHHui;
4122 case AArch64::LDURSHXi:
4123 Scale = 2;
4124 return AArch64::LDRSHXui;
4125 case AArch64::LDURSHWi:
4126 Scale = 2;
4127 return AArch64::LDRSHWui;
4128 case AArch64::LDURBi:
4129 Scale = 1;
4130 return AArch64::LDRBui;
4131 case AArch64::LDURBBi:
4132 Scale = 1;
4133 return AArch64::LDRBBui;
4134 case AArch64::LDURSBXi:
4135 Scale = 1;
4136 return AArch64::LDRSBXui;
4137 case AArch64::LDURSBWi:
4138 Scale = 1;
4139 return AArch64::LDRSBWui;
4140 case AArch64::STURBi:
4141 Scale = 1;
4142 return AArch64::STRBui;
4143 case AArch64::STURBBi:
4144 Scale = 1;
4145 return AArch64::STRBBui;
4146 case AArch64::LDRQui:
4147 case AArch64::STRQui:
4148 Scale = 16;
4149 return Opcode;
4150 case AArch64::LDRDui:
4151 case AArch64::STRDui:
4152 case AArch64::LDRXui:
4153 case AArch64::STRXui:
4154 Scale = 8;
4155 return Opcode;
4156 case AArch64::LDRWui:
4157 case AArch64::LDRSWui:
4158 case AArch64::STRWui:
4159 Scale = 4;
4160 return Opcode;
4161 case AArch64::LDRHui:
4162 case AArch64::STRHui:
4163 case AArch64::LDRHHui:
4164 case AArch64::STRHHui:
4165 case AArch64::LDRSHXui:
4166 case AArch64::LDRSHWui:
4167 Scale = 2;
4168 return Opcode;
4169 case AArch64::LDRBui:
4170 case AArch64::LDRBBui:
4171 case AArch64::LDRSBXui:
4172 case AArch64::LDRSBWui:
4173 case AArch64::STRBui:
4174 case AArch64::STRBBui:
4175 Scale = 1;
4176 return Opcode;
4177 }
4178}
4179
4180// Given an opcode for an instruction with a [Reg, #Imm] addressing mode, return
4181// the opcode of an instruction performing the same operation, but using the
4182// [Reg, #Imm] addressing mode with unscaled offset.
4183unsigned unscaledOffsetOpcode(unsigned Opcode) {
4184 switch (Opcode) {
4185 default:
4186 llvm_unreachable("Address folding not implemented for instruction");
4187
4188 case AArch64::LDURQi:
4189 case AArch64::STURQi:
4190 case AArch64::LDURDi:
4191 case AArch64::STURDi:
4192 case AArch64::LDURXi:
4193 case AArch64::STURXi:
4194 case AArch64::LDURWi:
4195 case AArch64::LDURSWi:
4196 case AArch64::STURWi:
4197 case AArch64::LDURHi:
4198 case AArch64::STURHi:
4199 case AArch64::LDURHHi:
4200 case AArch64::STURHHi:
4201 case AArch64::LDURSHXi:
4202 case AArch64::LDURSHWi:
4203 case AArch64::LDURBi:
4204 case AArch64::STURBi:
4205 case AArch64::LDURBBi:
4206 case AArch64::STURBBi:
4207 case AArch64::LDURSBWi:
4208 case AArch64::LDURSBXi:
4209 return Opcode;
4210 case AArch64::LDRQui:
4211 return AArch64::LDURQi;
4212 case AArch64::STRQui:
4213 return AArch64::STURQi;
4214 case AArch64::LDRDui:
4215 return AArch64::LDURDi;
4216 case AArch64::STRDui:
4217 return AArch64::STURDi;
4218 case AArch64::LDRXui:
4219 return AArch64::LDURXi;
4220 case AArch64::STRXui:
4221 return AArch64::STURXi;
4222 case AArch64::LDRWui:
4223 return AArch64::LDURWi;
4224 case AArch64::LDRSWui:
4225 return AArch64::LDURSWi;
4226 case AArch64::STRWui:
4227 return AArch64::STURWi;
4228 case AArch64::LDRHui:
4229 return AArch64::LDURHi;
4230 case AArch64::STRHui:
4231 return AArch64::STURHi;
4232 case AArch64::LDRHHui:
4233 return AArch64::LDURHHi;
4234 case AArch64::STRHHui:
4235 return AArch64::STURHHi;
4236 case AArch64::LDRSHXui:
4237 return AArch64::LDURSHXi;
4238 case AArch64::LDRSHWui:
4239 return AArch64::LDURSHWi;
4240 case AArch64::LDRBBui:
4241 return AArch64::LDURBBi;
4242 case AArch64::LDRBui:
4243 return AArch64::LDURBi;
4244 case AArch64::STRBBui:
4245 return AArch64::STURBBi;
4246 case AArch64::STRBui:
4247 return AArch64::STURBi;
4248 case AArch64::LDRSBWui:
4249 return AArch64::LDURSBWi;
4250 case AArch64::LDRSBXui:
4251 return AArch64::LDURSBXi;
4252 }
4253}
4254
4255// Given the opcode of a memory load/store instruction, return the opcode of an
4256// instruction performing the same operation, but using
4257// the [Reg, Reg, {s,u}xtw #N] addressing mode with sign-/zero-extend of the
4258// offset register.
4259static unsigned offsetExtendOpcode(unsigned Opcode) {
4260 switch (Opcode) {
4261 default:
4262 llvm_unreachable("Address folding not implemented for instruction");
4263
4264 case AArch64::LDRQroX:
4265 case AArch64::LDURQi:
4266 case AArch64::LDRQui:
4267 return AArch64::LDRQroW;
4268 case AArch64::STRQroX:
4269 case AArch64::STURQi:
4270 case AArch64::STRQui:
4271 return AArch64::STRQroW;
4272 case AArch64::LDRDroX:
4273 case AArch64::LDURDi:
4274 case AArch64::LDRDui:
4275 return AArch64::LDRDroW;
4276 case AArch64::STRDroX:
4277 case AArch64::STURDi:
4278 case AArch64::STRDui:
4279 return AArch64::STRDroW;
4280 case AArch64::LDRXroX:
4281 case AArch64::LDURXi:
4282 case AArch64::LDRXui:
4283 return AArch64::LDRXroW;
4284 case AArch64::STRXroX:
4285 case AArch64::STURXi:
4286 case AArch64::STRXui:
4287 return AArch64::STRXroW;
4288 case AArch64::LDRWroX:
4289 case AArch64::LDURWi:
4290 case AArch64::LDRWui:
4291 return AArch64::LDRWroW;
4292 case AArch64::LDRSWroX:
4293 case AArch64::LDURSWi:
4294 case AArch64::LDRSWui:
4295 return AArch64::LDRSWroW;
4296 case AArch64::STRWroX:
4297 case AArch64::STURWi:
4298 case AArch64::STRWui:
4299 return AArch64::STRWroW;
4300 case AArch64::LDRHroX:
4301 case AArch64::LDURHi:
4302 case AArch64::LDRHui:
4303 return AArch64::LDRHroW;
4304 case AArch64::STRHroX:
4305 case AArch64::STURHi:
4306 case AArch64::STRHui:
4307 return AArch64::STRHroW;
4308 case AArch64::LDRHHroX:
4309 case AArch64::LDURHHi:
4310 case AArch64::LDRHHui:
4311 return AArch64::LDRHHroW;
4312 case AArch64::STRHHroX:
4313 case AArch64::STURHHi:
4314 case AArch64::STRHHui:
4315 return AArch64::STRHHroW;
4316 case AArch64::LDRSHXroX:
4317 case AArch64::LDURSHXi:
4318 case AArch64::LDRSHXui:
4319 return AArch64::LDRSHXroW;
4320 case AArch64::LDRSHWroX:
4321 case AArch64::LDURSHWi:
4322 case AArch64::LDRSHWui:
4323 return AArch64::LDRSHWroW;
4324 case AArch64::LDRBroX:
4325 case AArch64::LDURBi:
4326 case AArch64::LDRBui:
4327 return AArch64::LDRBroW;
4328 case AArch64::LDRBBroX:
4329 case AArch64::LDURBBi:
4330 case AArch64::LDRBBui:
4331 return AArch64::LDRBBroW;
4332 case AArch64::LDRSBXroX:
4333 case AArch64::LDURSBXi:
4334 case AArch64::LDRSBXui:
4335 return AArch64::LDRSBXroW;
4336 case AArch64::LDRSBWroX:
4337 case AArch64::LDURSBWi:
4338 case AArch64::LDRSBWui:
4339 return AArch64::LDRSBWroW;
4340 case AArch64::STRBroX:
4341 case AArch64::STURBi:
4342 case AArch64::STRBui:
4343 return AArch64::STRBroW;
4344 case AArch64::STRBBroX:
4345 case AArch64::STURBBi:
4346 case AArch64::STRBBui:
4347 return AArch64::STRBBroW;
4348 }
4349}
4350
4352 const ExtAddrMode &AM) const {
4353
4354 const DebugLoc &DL = MemI.getDebugLoc();
4355 MachineBasicBlock &MBB = *MemI.getParent();
4357
4359 if (AM.ScaledReg) {
4360 // The new instruction will be in the form `ldr Rt, [Xn, Xm, lsl #imm]`.
4361 unsigned Opcode = regOffsetOpcode(MemI.getOpcode());
4362 MRI.constrainRegClass(AM.BaseReg, &AArch64::GPR64spRegClass);
4363 auto B = BuildMI(MBB, MemI, DL, get(Opcode))
4364 .addReg(MemI.getOperand(0).getReg(),
4365 getDefRegState(MemI.mayLoad()))
4366 .addReg(AM.BaseReg)
4367 .addReg(AM.ScaledReg)
4368 .addImm(0)
4369 .addImm(AM.Scale > 1)
4370 .setMemRefs(MemI.memoperands())
4371 .setMIFlags(MemI.getFlags());
4372 return B.getInstr();
4373 }
4374
4375 assert(AM.ScaledReg == 0 && AM.Scale == 0 &&
4376 "Addressing mode not supported for folding");
4377
4378 // The new instruction will be in the form `ld[u]r Rt, [Xn, #imm]`.
4379 unsigned Scale = 1;
4380 unsigned Opcode = MemI.getOpcode();
4381 if (isInt<9>(AM.Displacement))
4382 Opcode = unscaledOffsetOpcode(Opcode);
4383 else
4384 Opcode = scaledOffsetOpcode(Opcode, Scale);
4385
4386 auto B =
4387 BuildMI(MBB, MemI, DL, get(Opcode))
4388 .addReg(MemI.getOperand(0).getReg(), getDefRegState(MemI.mayLoad()))
4389 .addReg(AM.BaseReg)
4390 .addImm(AM.Displacement / Scale)
4391 .setMemRefs(MemI.memoperands())
4392 .setMIFlags(MemI.getFlags());
4393 return B.getInstr();
4394 }
4395
4398 // The new instruction will be in the form `ldr Rt, [Xn, Wm, {s,u}xtw #N]`.
4399 assert(AM.ScaledReg && !AM.Displacement &&
4400 "Address offset can be a register or an immediate, but not both");
4401 unsigned Opcode = offsetExtendOpcode(MemI.getOpcode());
4402 MRI.constrainRegClass(AM.BaseReg, &AArch64::GPR64spRegClass);
4403 // Make sure the offset register is in the correct register class.
4404 Register OffsetReg = AM.ScaledReg;
4405 const TargetRegisterClass *RC = MRI.getRegClass(OffsetReg);
4406 if (RC->hasSuperClassEq(&AArch64::GPR64RegClass)) {
4407 OffsetReg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
4408 BuildMI(MBB, MemI, DL, get(TargetOpcode::COPY), OffsetReg)
4409 .addReg(AM.ScaledReg, {}, AArch64::sub_32);
4410 }
4411 auto B =
4412 BuildMI(MBB, MemI, DL, get(Opcode))
4413 .addReg(MemI.getOperand(0).getReg(), getDefRegState(MemI.mayLoad()))
4414 .addReg(AM.BaseReg)
4415 .addReg(OffsetReg)
4417 .addImm(AM.Scale != 1)
4418 .setMemRefs(MemI.memoperands())
4419 .setMIFlags(MemI.getFlags());
4420
4421 return B.getInstr();
4422 }
4423
4425 "Function must not be called with an addressing mode it can't handle");
4426}
4427
4428/// Return true if the opcode is a post-index ld/st instruction, which really
4429/// loads from base+0.
4430static bool isPostIndexLdStOpcode(unsigned Opcode) {
4431 switch (Opcode) {
4432 default:
4433 return false;
4434 case AArch64::LD1Fourv16b_POST:
4435 case AArch64::LD1Fourv1d_POST:
4436 case AArch64::LD1Fourv2d_POST:
4437 case AArch64::LD1Fourv2s_POST:
4438 case AArch64::LD1Fourv4h_POST:
4439 case AArch64::LD1Fourv4s_POST:
4440 case AArch64::LD1Fourv8b_POST:
4441 case AArch64::LD1Fourv8h_POST:
4442 case AArch64::LD1Onev16b_POST:
4443 case AArch64::LD1Onev1d_POST:
4444 case AArch64::LD1Onev2d_POST:
4445 case AArch64::LD1Onev2s_POST:
4446 case AArch64::LD1Onev4h_POST:
4447 case AArch64::LD1Onev4s_POST:
4448 case AArch64::LD1Onev8b_POST:
4449 case AArch64::LD1Onev8h_POST:
4450 case AArch64::LD1Rv16b_POST:
4451 case AArch64::LD1Rv1d_POST:
4452 case AArch64::LD1Rv2d_POST:
4453 case AArch64::LD1Rv2s_POST:
4454 case AArch64::LD1Rv4h_POST:
4455 case AArch64::LD1Rv4s_POST:
4456 case AArch64::LD1Rv8b_POST:
4457 case AArch64::LD1Rv8h_POST:
4458 case AArch64::LD1Threev16b_POST:
4459 case AArch64::LD1Threev1d_POST:
4460 case AArch64::LD1Threev2d_POST:
4461 case AArch64::LD1Threev2s_POST:
4462 case AArch64::LD1Threev4h_POST:
4463 case AArch64::LD1Threev4s_POST:
4464 case AArch64::LD1Threev8b_POST:
4465 case AArch64::LD1Threev8h_POST:
4466 case AArch64::LD1Twov16b_POST:
4467 case AArch64::LD1Twov1d_POST:
4468 case AArch64::LD1Twov2d_POST:
4469 case AArch64::LD1Twov2s_POST:
4470 case AArch64::LD1Twov4h_POST:
4471 case AArch64::LD1Twov4s_POST:
4472 case AArch64::LD1Twov8b_POST:
4473 case AArch64::LD1Twov8h_POST:
4474 case AArch64::LD1i16_POST:
4475 case AArch64::LD1i32_POST:
4476 case AArch64::LD1i64_POST:
4477 case AArch64::LD1i8_POST:
4478 case AArch64::LD2Rv16b_POST:
4479 case AArch64::LD2Rv1d_POST:
4480 case AArch64::LD2Rv2d_POST:
4481 case AArch64::LD2Rv2s_POST:
4482 case AArch64::LD2Rv4h_POST:
4483 case AArch64::LD2Rv4s_POST:
4484 case AArch64::LD2Rv8b_POST:
4485 case AArch64::LD2Rv8h_POST:
4486 case AArch64::LD2Twov16b_POST:
4487 case AArch64::LD2Twov2d_POST:
4488 case AArch64::LD2Twov2s_POST:
4489 case AArch64::LD2Twov4h_POST:
4490 case AArch64::LD2Twov4s_POST:
4491 case AArch64::LD2Twov8b_POST:
4492 case AArch64::LD2Twov8h_POST:
4493 case AArch64::LD2i16_POST:
4494 case AArch64::LD2i32_POST:
4495 case AArch64::LD2i64_POST:
4496 case AArch64::LD2i8_POST:
4497 case AArch64::LD3Rv16b_POST:
4498 case AArch64::LD3Rv1d_POST:
4499 case AArch64::LD3Rv2d_POST:
4500 case AArch64::LD3Rv2s_POST:
4501 case AArch64::LD3Rv4h_POST:
4502 case AArch64::LD3Rv4s_POST:
4503 case AArch64::LD3Rv8b_POST:
4504 case AArch64::LD3Rv8h_POST:
4505 case AArch64::LD3Threev16b_POST:
4506 case AArch64::LD3Threev2d_POST:
4507 case AArch64::LD3Threev2s_POST:
4508 case AArch64::LD3Threev4h_POST:
4509 case AArch64::LD3Threev4s_POST:
4510 case AArch64::LD3Threev8b_POST:
4511 case AArch64::LD3Threev8h_POST:
4512 case AArch64::LD3i16_POST:
4513 case AArch64::LD3i32_POST:
4514 case AArch64::LD3i64_POST:
4515 case AArch64::LD3i8_POST:
4516 case AArch64::LD4Fourv16b_POST:
4517 case AArch64::LD4Fourv2d_POST:
4518 case AArch64::LD4Fourv2s_POST:
4519 case AArch64::LD4Fourv4h_POST:
4520 case AArch64::LD4Fourv4s_POST:
4521 case AArch64::LD4Fourv8b_POST:
4522 case AArch64::LD4Fourv8h_POST:
4523 case AArch64::LD4Rv16b_POST:
4524 case AArch64::LD4Rv1d_POST:
4525 case AArch64::LD4Rv2d_POST:
4526 case AArch64::LD4Rv2s_POST:
4527 case AArch64::LD4Rv4h_POST:
4528 case AArch64::LD4Rv4s_POST:
4529 case AArch64::LD4Rv8b_POST:
4530 case AArch64::LD4Rv8h_POST:
4531 case AArch64::LD4i16_POST:
4532 case AArch64::LD4i32_POST:
4533 case AArch64::LD4i64_POST:
4534 case AArch64::LD4i8_POST:
4535 case AArch64::LDAPRWpost:
4536 case AArch64::LDAPRXpost:
4537 case AArch64::LDIAPPWpost:
4538 case AArch64::LDIAPPXpost:
4539 case AArch64::LDPDpost:
4540 case AArch64::LDPQpost:
4541 case AArch64::LDPSWpost:
4542 case AArch64::LDPSpost:
4543 case AArch64::LDPWpost:
4544 case AArch64::LDPXpost:
4545 case AArch64::LDRBBpost:
4546 case AArch64::LDRBpost:
4547 case AArch64::LDRDpost:
4548 case AArch64::LDRHHpost:
4549 case AArch64::LDRHpost:
4550 case AArch64::LDRQpost:
4551 case AArch64::LDRSBWpost:
4552 case AArch64::LDRSBXpost:
4553 case AArch64::LDRSHWpost:
4554 case AArch64::LDRSHXpost:
4555 case AArch64::LDRSWpost:
4556 case AArch64::LDRSpost:
4557 case AArch64::LDRWpost:
4558 case AArch64::LDRXpost:
4559 case AArch64::ST1Fourv16b_POST:
4560 case AArch64::ST1Fourv1d_POST:
4561 case AArch64::ST1Fourv2d_POST:
4562 case AArch64::ST1Fourv2s_POST:
4563 case AArch64::ST1Fourv4h_POST:
4564 case AArch64::ST1Fourv4s_POST:
4565 case AArch64::ST1Fourv8b_POST:
4566 case AArch64::ST1Fourv8h_POST:
4567 case AArch64::ST1Onev16b_POST:
4568 case AArch64::ST1Onev1d_POST:
4569 case AArch64::ST1Onev2d_POST:
4570 case AArch64::ST1Onev2s_POST:
4571 case AArch64::ST1Onev4h_POST:
4572 case AArch64::ST1Onev4s_POST:
4573 case AArch64::ST1Onev8b_POST:
4574 case AArch64::ST1Onev8h_POST:
4575 case AArch64::ST1Threev16b_POST:
4576 case AArch64::ST1Threev1d_POST:
4577 case AArch64::ST1Threev2d_POST:
4578 case AArch64::ST1Threev2s_POST:
4579 case AArch64::ST1Threev4h_POST:
4580 case AArch64::ST1Threev4s_POST:
4581 case AArch64::ST1Threev8b_POST:
4582 case AArch64::ST1Threev8h_POST:
4583 case AArch64::ST1Twov16b_POST:
4584 case AArch64::ST1Twov1d_POST:
4585 case AArch64::ST1Twov2d_POST:
4586 case AArch64::ST1Twov2s_POST:
4587 case AArch64::ST1Twov4h_POST:
4588 case AArch64::ST1Twov4s_POST:
4589 case AArch64::ST1Twov8b_POST:
4590 case AArch64::ST1Twov8h_POST:
4591 case AArch64::ST1i16_POST:
4592 case AArch64::ST1i32_POST:
4593 case AArch64::ST1i64_POST:
4594 case AArch64::ST1i8_POST:
4595 case AArch64::ST2GPostIndex:
4596 case AArch64::ST2Twov16b_POST:
4597 case AArch64::ST2Twov2d_POST:
4598 case AArch64::ST2Twov2s_POST:
4599 case AArch64::ST2Twov4h_POST:
4600 case AArch64::ST2Twov4s_POST:
4601 case AArch64::ST2Twov8b_POST:
4602 case AArch64::ST2Twov8h_POST:
4603 case AArch64::ST2i16_POST:
4604 case AArch64::ST2i32_POST:
4605 case AArch64::ST2i64_POST:
4606 case AArch64::ST2i8_POST:
4607 case AArch64::ST3Threev16b_POST:
4608 case AArch64::ST3Threev2d_POST:
4609 case AArch64::ST3Threev2s_POST:
4610 case AArch64::ST3Threev4h_POST:
4611 case AArch64::ST3Threev4s_POST:
4612 case AArch64::ST3Threev8b_POST:
4613 case AArch64::ST3Threev8h_POST:
4614 case AArch64::ST3i16_POST:
4615 case AArch64::ST3i32_POST:
4616 case AArch64::ST3i64_POST:
4617 case AArch64::ST3i8_POST:
4618 case AArch64::ST4Fourv16b_POST:
4619 case AArch64::ST4Fourv2d_POST:
4620 case AArch64::ST4Fourv2s_POST:
4621 case AArch64::ST4Fourv4h_POST:
4622 case AArch64::ST4Fourv4s_POST:
4623 case AArch64::ST4Fourv8b_POST:
4624 case AArch64::ST4Fourv8h_POST:
4625 case AArch64::ST4i16_POST:
4626 case AArch64::ST4i32_POST:
4627 case AArch64::ST4i64_POST:
4628 case AArch64::ST4i8_POST:
4629 case AArch64::STGPostIndex:
4630 case AArch64::STGPpost:
4631 case AArch64::STPDpost:
4632 case AArch64::STPQpost:
4633 case AArch64::STPSpost:
4634 case AArch64::STPWpost:
4635 case AArch64::STPXpost:
4636 case AArch64::STRBBpost:
4637 case AArch64::STRBpost:
4638 case AArch64::STRDpost:
4639 case AArch64::STRHHpost:
4640 case AArch64::STRHpost:
4641 case AArch64::STRQpost:
4642 case AArch64::STRSpost:
4643 case AArch64::STRWpost:
4644 case AArch64::STRXpost:
4645 case AArch64::STZ2GPostIndex:
4646 case AArch64::STZGPostIndex:
4647 return true;
4648 }
4649}
4650
4652 const MachineInstr &LdSt, const MachineOperand *&BaseOp, int64_t &Offset,
4653 bool &OffsetIsScalable, TypeSize &Width) const {
4654 assert(LdSt.mayLoadOrStore() && "Expected a memory operation.");
4655 // Handle only loads/stores with base register followed by immediate offset.
4656 if (LdSt.getNumExplicitOperands() == 3) {
4657 // Non-paired instruction (e.g., ldr x1, [x0, #8]).
4658 if ((!LdSt.getOperand(1).isReg() && !LdSt.getOperand(1).isFI()) ||
4659 !LdSt.getOperand(2).isImm())
4660 return false;
4661 } else if (LdSt.getNumExplicitOperands() == 4) {
4662 // Paired instruction (e.g., ldp x1, x2, [x0, #8]).
4663 if (!LdSt.getOperand(1).isReg() ||
4664 (!LdSt.getOperand(2).isReg() && !LdSt.getOperand(2).isFI()) ||
4665 !LdSt.getOperand(3).isImm())
4666 return false;
4667 } else
4668 return false;
4669
4670 // Get the scaling factor for the instruction and set the width for the
4671 // instruction.
4672 TypeSize Scale(0U, false);
4673 int64_t Dummy1, Dummy2;
4674
4675 // If this returns false, then it's an instruction we don't want to handle.
4676 if (!getMemOpInfo(LdSt.getOpcode(), Scale, Width, Dummy1, Dummy2))
4677 return false;
4678
4679 // Compute the offset. Offset is calculated as the immediate operand
4680 // multiplied by the scaling factor. Unscaled instructions have scaling factor
4681 // set to 1. Postindex are a special case which have an offset of 0.
4682 if (isPostIndexLdStOpcode(LdSt.getOpcode())) {
4683 BaseOp = &LdSt.getOperand(2);
4684 Offset = 0;
4685 } else if (LdSt.getNumExplicitOperands() == 3) {
4686 BaseOp = &LdSt.getOperand(1);
4687 Offset = LdSt.getOperand(2).getImm() * Scale.getKnownMinValue();
4688 } else {
4689 assert(LdSt.getNumExplicitOperands() == 4 && "invalid number of operands");
4690 BaseOp = &LdSt.getOperand(2);
4691 Offset = LdSt.getOperand(3).getImm() * Scale.getKnownMinValue();
4692 }
4693 OffsetIsScalable = Scale.isScalable();
4694
4695 return BaseOp->isReg() || BaseOp->isFI();
4696}
4697
4700 assert(LdSt.mayLoadOrStore() && "Expected a memory operation.");
4701 MachineOperand &OfsOp = LdSt.getOperand(LdSt.getNumExplicitOperands() - 1);
4702 assert(OfsOp.isImm() && "Offset operand wasn't immediate.");
4703 return OfsOp;
4704}
4705
4706bool AArch64InstrInfo::getMemOpInfo(unsigned Opcode, TypeSize &Scale,
4707 TypeSize &Width, int64_t &MinOffset,
4708 int64_t &MaxOffset) {
4709 switch (Opcode) {
4710 // Not a memory operation or something we want to handle.
4711 default:
4712 Scale = Width = TypeSize::getFixed(0);
4713 MinOffset = MaxOffset = 0;
4714 return false;
4715 // LDR / STR
4716 case AArch64::LDRQui:
4717 case AArch64::STRQui:
4718 Scale = Width = TypeSize::getFixed(16);
4719 MinOffset = 0;
4720 MaxOffset = 4095;
4721 break;
4722 case AArch64::LDRXui:
4723 case AArch64::LDRDui:
4724 case AArch64::STRXui:
4725 case AArch64::STRDui:
4726 case AArch64::PRFMui:
4727 case AArch64::ATOMIC_STORE_HINT_Xui:
4728 case AArch64::ATOMIC_STORE_HINT_Dui:
4729 Scale = Width = TypeSize::getFixed(8);
4730 MinOffset = 0;
4731 MaxOffset = 4095;
4732 break;
4733 case AArch64::LDRWui:
4734 case AArch64::LDRSui:
4735 case AArch64::LDRSWui:
4736 case AArch64::STRWui:
4737 case AArch64::STRSui:
4738 case AArch64::ATOMIC_STORE_HINT_Wui:
4739 case AArch64::ATOMIC_STORE_HINT_Sui:
4740 Scale = Width = TypeSize::getFixed(4);
4741 MinOffset = 0;
4742 MaxOffset = 4095;
4743 break;
4744 case AArch64::LDRHui:
4745 case AArch64::LDRHHui:
4746 case AArch64::LDRSHWui:
4747 case AArch64::LDRSHXui:
4748 case AArch64::STRHui:
4749 case AArch64::STRHHui:
4750 case AArch64::ATOMIC_STORE_HINT_Hui:
4751 Scale = Width = TypeSize::getFixed(2);
4752 MinOffset = 0;
4753 MaxOffset = 4095;
4754 break;
4755 case AArch64::LDRBui:
4756 case AArch64::LDRBBui:
4757 case AArch64::LDRSBWui:
4758 case AArch64::LDRSBXui:
4759 case AArch64::STRBui:
4760 case AArch64::STRBBui:
4761 case AArch64::ATOMIC_STORE_HINT_Bui:
4762 Scale = Width = TypeSize::getFixed(1);
4763 MinOffset = 0;
4764 MaxOffset = 4095;
4765 break;
4766 // post/pre inc
4767 case AArch64::STRQpre:
4768 case AArch64::LDRQpost:
4769 Scale = TypeSize::getFixed(1);
4770 Width = TypeSize::getFixed(16);
4771 MinOffset = -256;
4772 MaxOffset = 255;
4773 break;
4774 case AArch64::LDRDpost:
4775 case AArch64::LDRDpre:
4776 case AArch64::LDRXpost:
4777 case AArch64::LDRXpre:
4778 case AArch64::STRDpost:
4779 case AArch64::STRDpre:
4780 case AArch64::STRXpost:
4781 case AArch64::STRXpre:
4782 Scale = TypeSize::getFixed(1);
4783 Width = TypeSize::getFixed(8);
4784 MinOffset = -256;
4785 MaxOffset = 255;
4786 break;
4787 case AArch64::STRWpost:
4788 case AArch64::STRWpre:
4789 case AArch64::LDRWpost:
4790 case AArch64::LDRWpre:
4791 case AArch64::STRSpost:
4792 case AArch64::STRSpre:
4793 case AArch64::LDRSpost:
4794 case AArch64::LDRSpre:
4795 Scale = TypeSize::getFixed(1);
4796 Width = TypeSize::getFixed(4);
4797 MinOffset = -256;
4798 MaxOffset = 255;
4799 break;
4800 case AArch64::LDRHpost:
4801 case AArch64::LDRHpre:
4802 case AArch64::STRHpost:
4803 case AArch64::STRHpre:
4804 case AArch64::LDRHHpost:
4805 case AArch64::LDRHHpre:
4806 case AArch64::STRHHpost:
4807 case AArch64::STRHHpre:
4808 Scale = TypeSize::getFixed(1);
4809 Width = TypeSize::getFixed(2);
4810 MinOffset = -256;
4811 MaxOffset = 255;
4812 break;
4813 case AArch64::LDRBpost:
4814 case AArch64::LDRBpre:
4815 case AArch64::STRBpost:
4816 case AArch64::STRBpre:
4817 case AArch64::LDRBBpost:
4818 case AArch64::LDRBBpre:
4819 case AArch64::STRBBpost:
4820 case AArch64::STRBBpre:
4821 Scale = Width = TypeSize::getFixed(1);
4822 MinOffset = -256;
4823 MaxOffset = 255;
4824 break;
4825 // Unscaled
4826 case AArch64::LDURQi:
4827 case AArch64::STURQi:
4828 Scale = TypeSize::getFixed(1);
4829 Width = TypeSize::getFixed(16);
4830 MinOffset = -256;
4831 MaxOffset = 255;
4832 break;
4833 case AArch64::LDURXi:
4834 case AArch64::LDURDi:
4835 case AArch64::LDAPURXi:
4836 case AArch64::STURXi:
4837 case AArch64::STURDi:
4838 case AArch64::STLURXi:
4839 case AArch64::PRFUMi:
4840 case AArch64::ATOMIC_STORE_HINT_Xi:
4841 case AArch64::ATOMIC_STORE_HINT_Di:
4842 Scale = TypeSize::getFixed(1);
4843 Width = TypeSize::getFixed(8);
4844 MinOffset = -256;
4845 MaxOffset = 255;
4846 break;
4847 case AArch64::LDURWi:
4848 case AArch64::LDURSi:
4849 case AArch64::LDURSWi:
4850 case AArch64::LDAPURi:
4851 case AArch64::LDAPURSWi:
4852 case AArch64::STURWi:
4853 case AArch64::STURSi:
4854 case AArch64::STLURWi:
4855 case AArch64::ATOMIC_STORE_HINT_Wi:
4856 case AArch64::ATOMIC_STORE_HINT_Si:
4857 Scale = TypeSize::getFixed(1);
4858 Width = TypeSize::getFixed(4);
4859 MinOffset = -256;
4860 MaxOffset = 255;
4861 break;
4862 case AArch64::LDURHi:
4863 case AArch64::LDURHHi:
4864 case AArch64::LDURSHXi:
4865 case AArch64::LDURSHWi:
4866 case AArch64::LDAPURHi:
4867 case AArch64::LDAPURSHWi:
4868 case AArch64::LDAPURSHXi:
4869 case AArch64::STURHi:
4870 case AArch64::STURHHi:
4871 case AArch64::STLURHi:
4872 case AArch64::ATOMIC_STORE_HINT_Hi:
4873 Scale = TypeSize::getFixed(1);
4874 Width = TypeSize::getFixed(2);
4875 MinOffset = -256;
4876 MaxOffset = 255;
4877 break;
4878 case AArch64::LDURBi:
4879 case AArch64::LDURBBi:
4880 case AArch64::LDURSBXi:
4881 case AArch64::LDURSBWi:
4882 case AArch64::LDAPURBi:
4883 case AArch64::LDAPURSBWi:
4884 case AArch64::LDAPURSBXi:
4885 case AArch64::STURBi:
4886 case AArch64::STURBBi:
4887 case AArch64::STLURBi:
4888 case AArch64::ATOMIC_STORE_HINT_Bi:
4889 Scale = Width = TypeSize::getFixed(1);
4890 MinOffset = -256;
4891 MaxOffset = 255;
4892 break;
4893 // LDP / STP (including pre/post inc)
4894 case AArch64::LDPQi:
4895 case AArch64::LDNPQi:
4896 case AArch64::STPQi:
4897 case AArch64::STNPQi:
4898 case AArch64::LDPQpost:
4899 case AArch64::LDPQpre:
4900 case AArch64::STPQpost:
4901 case AArch64::STPQpre:
4902 Scale = TypeSize::getFixed(16);
4903 Width = TypeSize::getFixed(16 * 2);
4904 MinOffset = -64;
4905 MaxOffset = 63;
4906 break;
4907 case AArch64::LDPXi:
4908 case AArch64::LDPDi:
4909 case AArch64::LDNPXi:
4910 case AArch64::LDNPDi:
4911 case AArch64::STPXi:
4912 case AArch64::STPDi:
4913 case AArch64::STNPXi:
4914 case AArch64::STNPDi:
4915 case AArch64::LDPDpost:
4916 case AArch64::LDPDpre:
4917 case AArch64::LDPXpost:
4918 case AArch64::LDPXpre:
4919 case AArch64::STPDpost:
4920 case AArch64::STPDpre:
4921 case AArch64::STPXpost:
4922 case AArch64::STPXpre:
4923 Scale = TypeSize::getFixed(8);
4924 Width = TypeSize::getFixed(8 * 2);
4925 MinOffset = -64;
4926 MaxOffset = 63;
4927 break;
4928 case AArch64::LDPWi:
4929 case AArch64::LDPSi:
4930 case AArch64::LDNPWi:
4931 case AArch64::LDNPSi:
4932 case AArch64::STPWi:
4933 case AArch64::STPSi:
4934 case AArch64::STNPWi:
4935 case AArch64::STNPSi:
4936 case AArch64::LDPSpost:
4937 case AArch64::LDPSpre:
4938 case AArch64::LDPWpost:
4939 case AArch64::LDPWpre:
4940 case AArch64::STPSpost:
4941 case AArch64::STPSpre:
4942 case AArch64::STPWpost:
4943 case AArch64::STPWpre:
4944 Scale = TypeSize::getFixed(4);
4945 Width = TypeSize::getFixed(4 * 2);
4946 MinOffset = -64;
4947 MaxOffset = 63;
4948 break;
4949 case AArch64::StoreSwiftAsyncContext:
4950 // Store is an STRXui, but there might be an ADDXri in the expansion too.
4951 Scale = TypeSize::getFixed(1);
4952 Width = TypeSize::getFixed(8);
4953 MinOffset = 0;
4954 MaxOffset = 4095;
4955 break;
4956 case AArch64::ADDG:
4957 Scale = TypeSize::getFixed(16);
4958 Width = TypeSize::getFixed(0);
4959 MinOffset = 0;
4960 MaxOffset = 63;
4961 break;
4962 case AArch64::TAGPstack:
4963 Scale = TypeSize::getFixed(16);
4964 Width = TypeSize::getFixed(0);
4965 // TAGP with a negative offset turns into SUBP, which has a maximum offset
4966 // of 63 (not 64!).
4967 MinOffset = -63;
4968 MaxOffset = 63;
4969 break;
4970 case AArch64::LDG:
4971 case AArch64::STGi:
4972 case AArch64::STGPreIndex:
4973 case AArch64::STGPostIndex:
4974 case AArch64::STZGi:
4975 case AArch64::STZGPreIndex:
4976 case AArch64::STZGPostIndex:
4977 Scale = Width = TypeSize::getFixed(16);
4978 MinOffset = -256;
4979 MaxOffset = 255;
4980 break;
4981 // SVE
4982 case AArch64::STR_ZZZZXI:
4983 case AArch64::STR_ZZZZXI_STRIDED_CONTIGUOUS:
4984 case AArch64::LDR_ZZZZXI:
4985 case AArch64::LDR_ZZZZXI_STRIDED_CONTIGUOUS:
4986 Scale = TypeSize::getScalable(16);
4987 Width = TypeSize::getScalable(16 * 4);
4988 MinOffset = -256;
4989 MaxOffset = 252;
4990 break;
4991 case AArch64::STR_ZZZXI:
4992 case AArch64::LDR_ZZZXI:
4993 Scale = TypeSize::getScalable(16);
4994 Width = TypeSize::getScalable(16 * 3);
4995 MinOffset = -256;
4996 MaxOffset = 253;
4997 break;
4998 case AArch64::STR_ZZXI:
4999 case AArch64::STR_ZZXI_STRIDED_CONTIGUOUS:
5000 case AArch64::LDR_ZZXI:
5001 case AArch64::LDR_ZZXI_STRIDED_CONTIGUOUS:
5002 Scale = TypeSize::getScalable(16);
5003 Width = TypeSize::getScalable(16 * 2);
5004 MinOffset = -256;
5005 MaxOffset = 254;
5006 break;
5007 case AArch64::LDR_PXI:
5008 case AArch64::STR_PXI:
5009 Scale = Width = TypeSize::getScalable(2);
5010 MinOffset = -256;
5011 MaxOffset = 255;
5012 break;
5013 case AArch64::LDR_PPXI:
5014 case AArch64::STR_PPXI:
5015 Scale = TypeSize::getScalable(2);
5016 Width = TypeSize::getScalable(2 * 2);
5017 MinOffset = -256;
5018 MaxOffset = 254;
5019 break;
5020 case AArch64::LDR_ZXI:
5021 case AArch64::STR_ZXI:
5022 Scale = Width = TypeSize::getScalable(16);
5023 MinOffset = -256;
5024 MaxOffset = 255;
5025 break;
5026 case AArch64::LD1B_IMM:
5027 case AArch64::LD1H_IMM:
5028 case AArch64::LD1W_IMM:
5029 case AArch64::LD1D_IMM:
5030 case AArch64::LDNT1B_ZRI:
5031 case AArch64::LDNT1H_ZRI:
5032 case AArch64::LDNT1W_ZRI:
5033 case AArch64::LDNT1D_ZRI:
5034 case AArch64::ST1B_IMM:
5035 case AArch64::ST1H_IMM:
5036 case AArch64::ST1W_IMM:
5037 case AArch64::ST1D_IMM:
5038 case AArch64::STNT1B_ZRI:
5039 case AArch64::STNT1H_ZRI:
5040 case AArch64::STNT1W_ZRI:
5041 case AArch64::STNT1D_ZRI:
5042 case AArch64::LDNF1B_IMM:
5043 case AArch64::LDNF1H_IMM:
5044 case AArch64::LDNF1W_IMM:
5045 case AArch64::LDNF1D_IMM:
5046 // A full vectors worth of data
5047 // Width = mbytes * elements
5048 Scale = Width = TypeSize::getScalable(16);
5049 MinOffset = -8;
5050 MaxOffset = 7;
5051 break;
5052 case AArch64::LD2B_IMM:
5053 case AArch64::LD2H_IMM:
5054 case AArch64::LD2W_IMM:
5055 case AArch64::LD2D_IMM:
5056 case AArch64::ST2B_IMM:
5057 case AArch64::ST2H_IMM:
5058 case AArch64::ST2W_IMM:
5059 case AArch64::ST2D_IMM:
5060 case AArch64::LD1B_2Z_IMM:
5061 case AArch64::LD1B_2Z_STRIDED_IMM:
5062 case AArch64::LD1H_2Z_IMM:
5063 case AArch64::LD1H_2Z_STRIDED_IMM:
5064 case AArch64::LD1W_2Z_IMM:
5065 case AArch64::LD1W_2Z_STRIDED_IMM:
5066 case AArch64::LD1D_2Z_IMM:
5067 case AArch64::LD1D_2Z_STRIDED_IMM:
5068 case AArch64::LD1B_2Z_IMM_PSEUDO:
5069 case AArch64::LD1H_2Z_IMM_PSEUDO:
5070 case AArch64::LD1W_2Z_IMM_PSEUDO:
5071 case AArch64::LD1D_2Z_IMM_PSEUDO:
5072 case AArch64::ST1B_2Z_IMM:
5073 case AArch64::ST1B_2Z_STRIDED_IMM:
5074 case AArch64::ST1H_2Z_IMM:
5075 case AArch64::ST1H_2Z_STRIDED_IMM:
5076 case AArch64::ST1W_2Z_IMM:
5077 case AArch64::ST1W_2Z_STRIDED_IMM:
5078 case AArch64::ST1D_2Z_IMM:
5079 case AArch64::ST1D_2Z_STRIDED_IMM:
5080 case AArch64::LDNT1B_2Z_IMM_PSEUDO:
5081 case AArch64::LDNT1B_2Z_IMM:
5082 case AArch64::LDNT1B_2Z_STRIDED_IMM:
5083 case AArch64::LDNT1H_2Z_IMM_PSEUDO:
5084 case AArch64::LDNT1H_2Z_IMM:
5085 case AArch64::LDNT1H_2Z_STRIDED_IMM:
5086 case AArch64::LDNT1W_2Z_IMM_PSEUDO:
5087 case AArch64::LDNT1W_2Z_IMM:
5088 case AArch64::LDNT1W_2Z_STRIDED_IMM:
5089 case AArch64::LDNT1D_2Z_IMM_PSEUDO:
5090 case AArch64::LDNT1D_2Z_IMM:
5091 case AArch64::LDNT1D_2Z_STRIDED_IMM:
5092 case AArch64::STNT1B_2Z_IMM:
5093 case AArch64::STNT1B_2Z_STRIDED_IMM:
5094 case AArch64::STNT1H_2Z_IMM:
5095 case AArch64::STNT1H_2Z_STRIDED_IMM:
5096 case AArch64::STNT1W_2Z_IMM:
5097 case AArch64::STNT1W_2Z_STRIDED_IMM:
5098 case AArch64::STNT1D_2Z_IMM:
5099 case AArch64::STNT1D_2Z_STRIDED_IMM:
5100 case AArch64::ST1B_2Z_IMM_PSEUDO:
5101 case AArch64::ST1H_2Z_IMM_PSEUDO:
5102 case AArch64::ST1W_2Z_IMM_PSEUDO:
5103 case AArch64::ST1D_2Z_IMM_PSEUDO:
5104 case AArch64::STNT1B_2Z_IMM_PSEUDO:
5105 case AArch64::STNT1H_2Z_IMM_PSEUDO:
5106 case AArch64::STNT1W_2Z_IMM_PSEUDO:
5107 case AArch64::STNT1D_2Z_IMM_PSEUDO:
5108 Scale = Width = TypeSize::getScalable(16 * 2);
5109 MinOffset = -8;
5110 MaxOffset = 7;
5111 break;
5112 case AArch64::LD3B_IMM:
5113 case AArch64::LD3H_IMM:
5114 case AArch64::LD3W_IMM:
5115 case AArch64::LD3D_IMM:
5116 case AArch64::ST3B_IMM:
5117 case AArch64::ST3H_IMM:
5118 case AArch64::ST3W_IMM:
5119 case AArch64::ST3D_IMM:
5120 Scale = Width = TypeSize::getScalable(16 * 3);
5121 MinOffset = -8;
5122 MaxOffset = 7;
5123 break;
5124 case AArch64::LD4B_IMM:
5125 case AArch64::LD4H_IMM:
5126 case AArch64::LD4W_IMM:
5127 case AArch64::LD4D_IMM:
5128 case AArch64::ST4B_IMM:
5129 case AArch64::ST4H_IMM:
5130 case AArch64::ST4W_IMM:
5131 case AArch64::ST4D_IMM:
5132 case AArch64::LD1B_4Z_IMM:
5133 case AArch64::LD1B_4Z_STRIDED_IMM:
5134 case AArch64::LD1H_4Z_IMM:
5135 case AArch64::LD1H_4Z_STRIDED_IMM:
5136 case AArch64::LD1W_4Z_IMM:
5137 case AArch64::LD1W_4Z_STRIDED_IMM:
5138 case AArch64::LD1D_4Z_IMM:
5139 case AArch64::LD1D_4Z_STRIDED_IMM:
5140 case AArch64::LD1B_4Z_IMM_PSEUDO:
5141 case AArch64::LD1H_4Z_IMM_PSEUDO:
5142 case AArch64::LD1W_4Z_IMM_PSEUDO:
5143 case AArch64::LD1D_4Z_IMM_PSEUDO:
5144 case AArch64::ST1B_4Z_IMM:
5145 case AArch64::ST1B_4Z_STRIDED_IMM:
5146 case AArch64::ST1H_4Z_IMM:
5147 case AArch64::ST1H_4Z_STRIDED_IMM:
5148 case AArch64::ST1W_4Z_IMM:
5149 case AArch64::ST1W_4Z_STRIDED_IMM:
5150 case AArch64::ST1D_4Z_IMM:
5151 case AArch64::ST1D_4Z_STRIDED_IMM:
5152 case AArch64::LDNT1B_4Z_IMM_PSEUDO:
5153 case AArch64::LDNT1B_4Z_IMM:
5154 case AArch64::LDNT1B_4Z_STRIDED_IMM:
5155 case AArch64::LDNT1H_4Z_IMM_PSEUDO:
5156 case AArch64::LDNT1H_4Z_IMM:
5157 case AArch64::LDNT1H_4Z_STRIDED_IMM:
5158 case AArch64::LDNT1W_4Z_IMM_PSEUDO:
5159 case AArch64::LDNT1W_4Z_IMM:
5160 case AArch64::LDNT1W_4Z_STRIDED_IMM:
5161 case AArch64::LDNT1D_4Z_IMM_PSEUDO:
5162 case AArch64::LDNT1D_4Z_IMM:
5163 case AArch64::LDNT1D_4Z_STRIDED_IMM:
5164 case AArch64::STNT1B_4Z_IMM:
5165 case AArch64::STNT1B_4Z_STRIDED_IMM:
5166 case AArch64::STNT1H_4Z_IMM:
5167 case AArch64::STNT1H_4Z_STRIDED_IMM:
5168 case AArch64::STNT1W_4Z_IMM:
5169 case AArch64::STNT1W_4Z_STRIDED_IMM:
5170 case AArch64::STNT1D_4Z_IMM:
5171 case AArch64::STNT1D_4Z_STRIDED_IMM:
5172 case AArch64::ST1B_4Z_IMM_PSEUDO:
5173 case AArch64::ST1H_4Z_IMM_PSEUDO:
5174 case AArch64::ST1W_4Z_IMM_PSEUDO:
5175 case AArch64::ST1D_4Z_IMM_PSEUDO:
5176 case AArch64::STNT1B_4Z_IMM_PSEUDO:
5177 case AArch64::STNT1H_4Z_IMM_PSEUDO:
5178 case AArch64::STNT1W_4Z_IMM_PSEUDO:
5179 case AArch64::STNT1D_4Z_IMM_PSEUDO:
5180 Scale = Width = TypeSize::getScalable(16 * 4);
5181 MinOffset = -8;
5182 MaxOffset = 7;
5183 break;
5184 case AArch64::LD1B_H_IMM:
5185 case AArch64::LD1SB_H_IMM:
5186 case AArch64::LD1H_S_IMM:
5187 case AArch64::LD1SH_S_IMM:
5188 case AArch64::LD1W_D_IMM:
5189 case AArch64::LD1SW_D_IMM:
5190 case AArch64::ST1B_H_IMM:
5191 case AArch64::ST1H_S_IMM:
5192 case AArch64::ST1W_D_IMM:
5193 case AArch64::LDNF1B_H_IMM:
5194 case AArch64::LDNF1SB_H_IMM:
5195 case AArch64::LDNF1H_S_IMM:
5196 case AArch64::LDNF1SH_S_IMM:
5197 case AArch64::LDNF1W_D_IMM:
5198 case AArch64::LDNF1SW_D_IMM:
5199 // A half vector worth of data
5200 // Width = mbytes * elements
5201 Scale = Width = TypeSize::getScalable(8);
5202 MinOffset = -8;
5203 MaxOffset = 7;
5204 break;
5205 case AArch64::LD1B_S_IMM:
5206 case AArch64::LD1SB_S_IMM:
5207 case AArch64::LD1H_D_IMM:
5208 case AArch64::LD1SH_D_IMM:
5209 case AArch64::ST1B_S_IMM:
5210 case AArch64::ST1H_D_IMM:
5211 case AArch64::LDNF1B_S_IMM:
5212 case AArch64::LDNF1SB_S_IMM:
5213 case AArch64::LDNF1H_D_IMM:
5214 case AArch64::LDNF1SH_D_IMM:
5215 // A quarter vector worth of data
5216 // Width = mbytes * elements
5217 Scale = Width = TypeSize::getScalable(4);
5218 MinOffset = -8;
5219 MaxOffset = 7;
5220 break;
5221 case AArch64::LD1B_D_IMM:
5222 case AArch64::LD1SB_D_IMM:
5223 case AArch64::ST1B_D_IMM:
5224 case AArch64::LDNF1B_D_IMM:
5225 case AArch64::LDNF1SB_D_IMM:
5226 // A eighth vector worth of data
5227 // Width = mbytes * elements
5228 Scale = Width = TypeSize::getScalable(2);
5229 MinOffset = -8;
5230 MaxOffset = 7;
5231 break;
5232 case AArch64::ST2Gi:
5233 case AArch64::ST2GPreIndex:
5234 case AArch64::ST2GPostIndex:
5235 case AArch64::STZ2Gi:
5236 case AArch64::STZ2GPreIndex:
5237 case AArch64::STZ2GPostIndex:
5238 Scale = TypeSize::getFixed(16);
5239 Width = TypeSize::getFixed(32);
5240 MinOffset = -256;
5241 MaxOffset = 255;
5242 break;
5243 case AArch64::STGPi:
5244 case AArch64::STGPpost:
5245 case AArch64::STGPpre:
5246 Scale = Width = TypeSize::getFixed(16);
5247 MinOffset = -64;
5248 MaxOffset = 63;
5249 break;
5250 case AArch64::LD1RB_IMM:
5251 case AArch64::LD1RB_H_IMM:
5252 case AArch64::LD1RB_S_IMM:
5253 case AArch64::LD1RB_D_IMM:
5254 case AArch64::LD1RSB_H_IMM:
5255 case AArch64::LD1RSB_S_IMM:
5256 case AArch64::LD1RSB_D_IMM:
5257 Scale = Width = TypeSize::getFixed(1);
5258 MinOffset = 0;
5259 MaxOffset = 63;
5260 break;
5261 case AArch64::LD1RH_IMM:
5262 case AArch64::LD1RH_S_IMM:
5263 case AArch64::LD1RH_D_IMM:
5264 case AArch64::LD1RSH_S_IMM:
5265 case AArch64::LD1RSH_D_IMM:
5266 Scale = Width = TypeSize::getFixed(2);
5267 MinOffset = 0;
5268 MaxOffset = 63;
5269 break;
5270 case AArch64::LD1RW_IMM:
5271 case AArch64::LD1RW_D_IMM:
5272 case AArch64::LD1RSW_IMM:
5273 Scale = Width = TypeSize::getFixed(4);
5274 MinOffset = 0;
5275 MaxOffset = 63;
5276 break;
5277 case AArch64::LD1RD_IMM:
5278 Scale = Width = TypeSize::getFixed(8);
5279 MinOffset = 0;
5280 MaxOffset = 63;
5281 break;
5282 }
5283
5284 return true;
5285}
5286
5287// Scaling factor for unscaled load or store.
5289 switch (Opc) {
5290 default:
5291 llvm_unreachable("Opcode has unknown scale!");
5292 case AArch64::LDRBui:
5293 case AArch64::LDRBBui:
5294 case AArch64::LDURBBi:
5295 case AArch64::LDRSBWui:
5296 case AArch64::LDURSBWi:
5297 case AArch64::STRBui:
5298 case AArch64::STRBBui:
5299 case AArch64::STURBBi:
5300 return 1;
5301 case AArch64::LDRHui:
5302 case AArch64::LDRHHui:
5303 case AArch64::LDURHHi:
5304 case AArch64::LDRSHWui:
5305 case AArch64::LDURSHWi:
5306 case AArch64::STRHui:
5307 case AArch64::STRHHui:
5308 case AArch64::STURHHi:
5309 return 2;
5310 case AArch64::LDRSui:
5311 case AArch64::LDURSi:
5312 case AArch64::LDRSpre:
5313 case AArch64::LDRSWui:
5314 case AArch64::LDURSWi:
5315 case AArch64::LDRSWpre:
5316 case AArch64::LDRWpre:
5317 case AArch64::LDRWui:
5318 case AArch64::LDURWi:
5319 case AArch64::STRSui:
5320 case AArch64::STURSi:
5321 case AArch64::STRSpre:
5322 case AArch64::STRWui:
5323 case AArch64::STURWi:
5324 case AArch64::STRWpre:
5325 case AArch64::LDPSi:
5326 case AArch64::LDPSWi:
5327 case AArch64::LDPWi:
5328 case AArch64::STPSi:
5329 case AArch64::STPWi:
5330 return 4;
5331 case AArch64::LDRDui:
5332 case AArch64::LDURDi:
5333 case AArch64::LDRDpre:
5334 case AArch64::LDRXui:
5335 case AArch64::LDURXi:
5336 case AArch64::LDRXpre:
5337 case AArch64::STRDui:
5338 case AArch64::STURDi:
5339 case AArch64::STRDpre:
5340 case AArch64::STRXui:
5341 case AArch64::STURXi:
5342 case AArch64::STRXpre:
5343 case AArch64::LDPDi:
5344 case AArch64::LDPXi:
5345 case AArch64::STPDi:
5346 case AArch64::STPXi:
5347 return 8;
5348 case AArch64::LDRQui:
5349 case AArch64::LDURQi:
5350 case AArch64::STRQui:
5351 case AArch64::STURQi:
5352 case AArch64::STRQpre:
5353 case AArch64::LDPQi:
5354 case AArch64::LDRQpre:
5355 case AArch64::STPQi:
5356 case AArch64::STGi:
5357 case AArch64::STZGi:
5358 case AArch64::ST2Gi:
5359 case AArch64::STZ2Gi:
5360 case AArch64::STGPi:
5361 return 16;
5362 }
5363}
5364
5366 switch (MI.getOpcode()) {
5367 default:
5368 return false;
5369 case AArch64::LDRWpre:
5370 case AArch64::LDRXpre:
5371 case AArch64::LDRSWpre:
5372 case AArch64::LDRSpre:
5373 case AArch64::LDRDpre:
5374 case AArch64::LDRQpre:
5375 return true;
5376 }
5377}
5378
5380 switch (MI.getOpcode()) {
5381 default:
5382 return false;
5383 case AArch64::STRWpre:
5384 case AArch64::STRXpre:
5385 case AArch64::STRSpre:
5386 case AArch64::STRDpre:
5387 case AArch64::STRQpre:
5388 return true;
5389 }
5390}
5391
5393 return isPreLd(MI) || isPreSt(MI);
5394}
5395
5397 switch (MI.getOpcode()) {
5398 default:
5399 return false;
5400 case AArch64::LDURBBi:
5401 case AArch64::LDURHHi:
5402 case AArch64::LDURWi:
5403 case AArch64::LDRBBui:
5404 case AArch64::LDRHHui:
5405 case AArch64::LDRWui:
5406 case AArch64::LDRBBroX:
5407 case AArch64::LDRHHroX:
5408 case AArch64::LDRWroX:
5409 case AArch64::LDRBBroW:
5410 case AArch64::LDRHHroW:
5411 case AArch64::LDRWroW:
5412 return true;
5413 }
5414}
5415
5417 switch (MI.getOpcode()) {
5418 default:
5419 return false;
5420 case AArch64::LDURSBWi:
5421 case AArch64::LDURSHWi:
5422 case AArch64::LDURSBXi:
5423 case AArch64::LDURSHXi:
5424 case AArch64::LDURSWi:
5425 case AArch64::LDRSBWui:
5426 case AArch64::LDRSHWui:
5427 case AArch64::LDRSBXui:
5428 case AArch64::LDRSHXui:
5429 case AArch64::LDRSWui:
5430 case AArch64::LDRSBWroX:
5431 case AArch64::LDRSHWroX:
5432 case AArch64::LDRSBXroX:
5433 case AArch64::LDRSHXroX:
5434 case AArch64::LDRSWroX:
5435 case AArch64::LDRSBWroW:
5436 case AArch64::LDRSHWroW:
5437 case AArch64::LDRSBXroW:
5438 case AArch64::LDRSHXroW:
5439 case AArch64::LDRSWroW:
5440 return true;
5441 }
5442}
5443
5445 switch (MI.getOpcode()) {
5446 default:
5447 return false;
5448 case AArch64::LDPSi:
5449 case AArch64::LDPSWi:
5450 case AArch64::LDPDi:
5451 case AArch64::LDPQi:
5452 case AArch64::LDPWi:
5453 case AArch64::LDPXi:
5454 case AArch64::STPSi:
5455 case AArch64::STPDi:
5456 case AArch64::STPQi:
5457 case AArch64::STPWi:
5458 case AArch64::STPXi:
5459 case AArch64::STGPi:
5460 return true;
5461 }
5462}
5463
5465 assert(MI.mayLoadOrStore() && "Load or store instruction expected");
5466 unsigned Idx =
5468 : 1;
5469 return MI.getOperand(Idx);
5470}
5471
5472const MachineOperand &
5474 assert(MI.mayLoadOrStore() && "Load or store instruction expected");
5475 unsigned Idx =
5477 : 2;
5478 return MI.getOperand(Idx);
5479}
5480
5481const MachineOperand &
5483 switch (MI.getOpcode()) {
5484 default:
5485 llvm_unreachable("Unexpected opcode");
5486 case AArch64::LDRBroX:
5487 case AArch64::LDRBBroX:
5488 case AArch64::LDRSBXroX:
5489 case AArch64::LDRSBWroX:
5490 case AArch64::LDRHroX:
5491 case AArch64::LDRHHroX:
5492 case AArch64::LDRSHXroX:
5493 case AArch64::LDRSHWroX:
5494 case AArch64::LDRWroX:
5495 case AArch64::LDRSroX:
5496 case AArch64::LDRSWroX:
5497 case AArch64::LDRDroX:
5498 case AArch64::LDRXroX:
5499 case AArch64::LDRQroX:
5500 return MI.getOperand(4);
5501 }
5502}
5503
5505 Register Reg) {
5506 if (MI.getParent() == nullptr)
5507 return nullptr;
5508 const MachineFunction *MF = MI.getParent()->getParent();
5509 return MF ? MF->getRegInfo().getRegClassOrNull(Reg) : nullptr;
5510}
5511
5513 auto IsHFPR = [&](const MachineOperand &Op) {
5514 if (!Op.isReg())
5515 return false;
5516 auto Reg = Op.getReg();
5517 if (Reg.isPhysical())
5518 return AArch64::FPR16RegClass.contains(Reg);
5519 const TargetRegisterClass *TRC = ::getRegClass(MI, Reg);
5520 return TRC == &AArch64::FPR16RegClass ||
5521 TRC == &AArch64::FPR16_loRegClass;
5522 };
5523 return llvm::any_of(MI.operands(), IsHFPR);
5524}
5525
5527 auto IsQFPR = [&](const MachineOperand &Op) {
5528 if (!Op.isReg())
5529 return false;
5530 auto Reg = Op.getReg();
5531 if (Reg.isPhysical())
5532 return AArch64::FPR128RegClass.contains(Reg);
5533 const TargetRegisterClass *TRC = ::getRegClass(MI, Reg);
5534 return TRC == &AArch64::FPR128RegClass ||
5535 TRC == &AArch64::FPR128_loRegClass;
5536 };
5537 return llvm::any_of(MI.operands(), IsQFPR);
5538}
5539
5541 switch (MI.getOpcode()) {
5542 case AArch64::BRK:
5543 case AArch64::HLT:
5544 case AArch64::PACIASP:
5545 case AArch64::PACIBSP:
5546 // Implicit BTI behavior.
5547 return true;
5548 case AArch64::PAUTH_PROLOGUE:
5549 // PAUTH_PROLOGUE expands to PACI(A|B)SP.
5550 return true;
5551 case AArch64::HINT: {
5552 unsigned Imm = MI.getOperand(0).getImm();
5553 // Explicit BTI instruction.
5554 if (Imm == 32 || Imm == 34 || Imm == 36 || Imm == 38)
5555 return true;
5556 // PACI(A|B)SP instructions.
5557 if (Imm == 25 || Imm == 27)
5558 return true;
5559 return false;
5560 }
5561 default:
5562 return false;
5563 }
5564}
5565
5567 if (Reg == 0)
5568 return false;
5569 assert(Reg.isPhysical() && "Expected physical register in isFpOrNEON");
5570 return AArch64::FPR128RegClass.contains(Reg) ||
5571 AArch64::FPR64RegClass.contains(Reg) ||
5572 AArch64::FPR32RegClass.contains(Reg) ||
5573 AArch64::FPR16RegClass.contains(Reg) ||
5574 AArch64::FPR8RegClass.contains(Reg);
5575}
5576
5578 auto IsFPR = [&](const MachineOperand &Op) {
5579 if (!Op.isReg())
5580 return false;
5581 auto Reg = Op.getReg();
5582 if (Reg.isPhysical())
5583 return isFpOrNEON(Reg);
5584
5585 const TargetRegisterClass *TRC = ::getRegClass(MI, Reg);
5586 return TRC == &AArch64::FPR128RegClass ||
5587 TRC == &AArch64::FPR128_loRegClass ||
5588 TRC == &AArch64::FPR64RegClass ||
5589 TRC == &AArch64::FPR64_loRegClass ||
5590 TRC == &AArch64::FPR32RegClass || TRC == &AArch64::FPR16RegClass ||
5591 TRC == &AArch64::FPR8RegClass;
5592 };
5593 return llvm::any_of(MI.operands(), IsFPR);
5594}
5595
5596// Scale the unscaled offsets. Returns false if the unscaled offset can't be
5597// scaled.
5598static bool scaleOffset(unsigned Opc, int64_t &Offset) {
5600
5601 // If the byte-offset isn't a multiple of the stride, we can't scale this
5602 // offset.
5603 if (Offset % Scale != 0)
5604 return false;
5605
5606 // Convert the byte-offset used by unscaled into an "element" offset used
5607 // by the scaled pair load/store instructions.
5608 Offset /= Scale;
5609 return true;
5610}
5611
5612static bool canPairLdStOpc(unsigned FirstOpc, unsigned SecondOpc) {
5613 if (FirstOpc == SecondOpc)
5614 return true;
5615 // We can also pair sign-ext and zero-ext instructions.
5616 switch (FirstOpc) {
5617 default:
5618 return false;
5619 case AArch64::STRSui:
5620 case AArch64::STURSi:
5621 return SecondOpc == AArch64::STRSui || SecondOpc == AArch64::STURSi;
5622 case AArch64::STRDui:
5623 case AArch64::STURDi:
5624 return SecondOpc == AArch64::STRDui || SecondOpc == AArch64::STURDi;
5625 case AArch64::STRQui:
5626 case AArch64::STURQi:
5627 return SecondOpc == AArch64::STRQui || SecondOpc == AArch64::STURQi;
5628 case AArch64::STRWui:
5629 case AArch64::STURWi:
5630 return SecondOpc == AArch64::STRWui || SecondOpc == AArch64::STURWi;
5631 case AArch64::STRXui:
5632 case AArch64::STURXi:
5633 return SecondOpc == AArch64::STRXui || SecondOpc == AArch64::STURXi;
5634 case AArch64::LDRSui:
5635 case AArch64::LDURSi:
5636 return SecondOpc == AArch64::LDRSui || SecondOpc == AArch64::LDURSi;
5637 case AArch64::LDRDui:
5638 case AArch64::LDURDi:
5639 return SecondOpc == AArch64::LDRDui || SecondOpc == AArch64::LDURDi;
5640 case AArch64::LDRQui:
5641 case AArch64::LDURQi:
5642 return SecondOpc == AArch64::LDRQui || SecondOpc == AArch64::LDURQi;
5643 case AArch64::LDRWui:
5644 case AArch64::LDURWi:
5645 return SecondOpc == AArch64::LDRSWui || SecondOpc == AArch64::LDURSWi;
5646 case AArch64::LDRSWui:
5647 case AArch64::LDURSWi:
5648 return SecondOpc == AArch64::LDRWui || SecondOpc == AArch64::LDURWi;
5649 case AArch64::LDRXui:
5650 case AArch64::LDURXi:
5651 return SecondOpc == AArch64::LDRXui || SecondOpc == AArch64::LDURXi;
5652 }
5653 // These instructions can't be paired based on their opcodes.
5654 return false;
5655}
5656
5657static bool shouldClusterFI(const MachineFrameInfo &MFI, int FI1,
5658 int64_t Offset1, unsigned Opcode1, int FI2,
5659 int64_t Offset2, unsigned Opcode2) {
5660 // Accesses through fixed stack object frame indices may access a different
5661 // fixed stack slot. Check that the object offsets + offsets match.
5662 if (MFI.isFixedObjectIndex(FI1) && MFI.isFixedObjectIndex(FI2)) {
5663 int64_t ObjectOffset1 = MFI.getObjectOffset(FI1);
5664 int64_t ObjectOffset2 = MFI.getObjectOffset(FI2);
5665 assert(ObjectOffset1 <= ObjectOffset2 && "Object offsets are not ordered.");
5666 // Convert to scaled object offsets.
5667 int Scale1 = AArch64InstrInfo::getMemScale(Opcode1);
5668 if (ObjectOffset1 % Scale1 != 0)
5669 return false;
5670 ObjectOffset1 /= Scale1;
5671 int Scale2 = AArch64InstrInfo::getMemScale(Opcode2);
5672 if (ObjectOffset2 % Scale2 != 0)
5673 return false;
5674 ObjectOffset2 /= Scale2;
5675 ObjectOffset1 += Offset1;
5676 ObjectOffset2 += Offset2;
5677 return ObjectOffset1 + 1 == ObjectOffset2;
5678 }
5679
5680 return FI1 == FI2;
5681}
5682
5683/// Detect opportunities for ldp/stp formation.
5684///
5685/// Only called for LdSt for which getMemOperandWithOffset returns true.
5687 ArrayRef<const MachineOperand *> BaseOps1, int64_t OpOffset1,
5688 bool OffsetIsScalable1, ArrayRef<const MachineOperand *> BaseOps2,
5689 int64_t OpOffset2, bool OffsetIsScalable2, unsigned ClusterSize,
5690 unsigned NumBytes) const {
5691 assert(BaseOps1.size() == 1 && BaseOps2.size() == 1);
5692 const MachineOperand &BaseOp1 = *BaseOps1.front();
5693 const MachineOperand &BaseOp2 = *BaseOps2.front();
5694 const MachineInstr &FirstLdSt = *BaseOp1.getParent();
5695 const MachineInstr &SecondLdSt = *BaseOp2.getParent();
5696 if (BaseOp1.getType() != BaseOp2.getType())
5697 return false;
5698
5699 assert((BaseOp1.isReg() || BaseOp1.isFI()) &&
5700 "Only base registers and frame indices are supported.");
5701
5702 // Check for both base regs and base FI.
5703 if (BaseOp1.isReg() && BaseOp1.getReg() != BaseOp2.getReg())
5704 return false;
5705
5706 // Only cluster up to a single pair.
5707 if (ClusterSize > 2)
5708 return false;
5709
5710 if (!isPairableLdStInst(FirstLdSt) || !isPairableLdStInst(SecondLdSt))
5711 return false;
5712
5713 // Can we pair these instructions based on their opcodes?
5714 unsigned FirstOpc = FirstLdSt.getOpcode();
5715 unsigned SecondOpc = SecondLdSt.getOpcode();
5716 if (!canPairLdStOpc(FirstOpc, SecondOpc))
5717 return false;
5718
5719 // Can't merge volatiles or load/stores that have a hint to avoid pair
5720 // formation, for example.
5721 if (!isCandidateToMergeOrPair(FirstLdSt) ||
5722 !isCandidateToMergeOrPair(SecondLdSt))
5723 return false;
5724
5725 // isCandidateToMergeOrPair guarantees that operand 2 is an immediate.
5726 int64_t Offset1 = FirstLdSt.getOperand(2).getImm();
5727 if (hasUnscaledLdStOffset(FirstOpc) && !scaleOffset(FirstOpc, Offset1))
5728 return false;
5729
5730 int64_t Offset2 = SecondLdSt.getOperand(2).getImm();
5731 if (hasUnscaledLdStOffset(SecondOpc) && !scaleOffset(SecondOpc, Offset2))
5732 return false;
5733
5734 // Pairwise instructions have a 7-bit signed offset field.
5735 if (Offset1 > 63 || Offset1 < -64)
5736 return false;
5737
5738 // The caller should already have ordered First/SecondLdSt by offset.
5739 // Note: except for non-equal frame index bases
5740 if (BaseOp1.isFI()) {
5741 assert((!BaseOp1.isIdenticalTo(BaseOp2) || Offset1 <= Offset2) &&
5742 "Caller should have ordered offsets.");
5743
5744 const MachineFrameInfo &MFI =
5745 FirstLdSt.getParent()->getParent()->getFrameInfo();
5746 return shouldClusterFI(MFI, BaseOp1.getIndex(), Offset1, FirstOpc,
5747 BaseOp2.getIndex(), Offset2, SecondOpc);
5748 }
5749
5750 assert(Offset1 <= Offset2 && "Caller should have ordered offsets.");
5751
5752 return Offset1 + 1 == Offset2;
5753}
5754
5756 MCRegister Reg, unsigned SubIdx,
5757 RegState State,
5758 const TargetRegisterInfo *TRI) {
5759 if (!SubIdx)
5760 return MIB.addReg(Reg, State);
5761
5762 if (Reg.isPhysical())
5763 return MIB.addReg(TRI->getSubReg(Reg, SubIdx), State);
5764 return MIB.addReg(Reg, State, SubIdx);
5765}
5766
5769 const DebugLoc &DL, MCRegister DestReg,
5770 MCRegister SrcReg, bool KillSrc,
5771 ArrayRef<unsigned> Indices) const {
5772 assert(Subtarget.hasNEON() && "Unexpected register copy without NEON");
5774 uint16_t DestEncoding = TRI->getEncodingValue(DestReg);
5775 uint16_t SrcEncoding = TRI->getEncodingValue(SrcReg);
5776 unsigned NumRegs = Indices.size();
5777 MCRegister DestSubReg = TRI->getSubReg(DestReg, Indices[0]);
5778 assert(!AArch64::PNRRegClass.contains(DestSubReg) &&
5779 "Unexpected predicate tuple copy");
5780 unsigned MaxRegs = AArch64::PPRRegClass.contains(DestSubReg) ? 15 : 31;
5781
5782 int SubReg = 0, End = NumRegs, Incr = 1;
5783 // Copy in reverse if a forward copy will clobber the tuple
5784 if (((DestEncoding - SrcEncoding) & MaxRegs) < NumRegs) {
5785 SubReg = NumRegs - 1;
5786 End = -1;
5787 Incr = -1;
5788 }
5789
5790 for (; SubReg != End; SubReg += Incr) {
5791 DestSubReg = TRI->getSubReg(DestReg, Indices[SubReg]);
5792 MCRegister SrcSubReg = TRI->getSubReg(SrcReg, Indices[SubReg]);
5793 copyPhysRegImpl(MBB, I, DL, DestSubReg, SrcSubReg, KillSrc);
5794 }
5795}
5796
5799 const DebugLoc &DL, MCRegister DestReg,
5800 MCRegister SrcReg, bool KillSrc,
5801 unsigned Opcode, unsigned ZeroReg,
5802 llvm::ArrayRef<unsigned> Indices) const {
5804 unsigned NumRegs = Indices.size();
5805
5806#ifndef NDEBUG
5807 uint16_t DestEncoding = TRI->getEncodingValue(DestReg);
5808 uint16_t SrcEncoding = TRI->getEncodingValue(SrcReg);
5809 assert(DestEncoding % NumRegs == 0 && SrcEncoding % NumRegs == 0 &&
5810 "GPR reg sequences should not be able to overlap");
5811#endif
5812
5813 for (unsigned SubReg = 0; SubReg != NumRegs; ++SubReg) {
5814 const MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opcode));
5815 AddSubReg(MIB, DestReg, Indices[SubReg], RegState::Define, TRI);
5816 MIB.addReg(ZeroReg);
5817 AddSubReg(MIB, SrcReg, Indices[SubReg], getKillRegState(KillSrc), TRI);
5818 MIB.addImm(0);
5819 }
5820}
5821
5822/// Returns true if the instruction at I is in a streaming call site region,
5823/// within a single basic block.
5824/// A "call site streaming region" starts after smstart and ends at smstop
5825/// around a call to a streaming function. This walks backward from I.
5828 MachineFunction &MF = *MBB.getParent();
5830 if (!AFI->hasStreamingModeChanges())
5831 return false;
5832 // Walk backwards to find smstart/smstop
5833 for (MachineInstr &MI : reverse(make_range(MBB.begin(), I))) {
5834 unsigned Opc = MI.getOpcode();
5835 if (Opc == AArch64::MSRpstatesvcrImm1 || Opc == AArch64::MSRpstatePseudo) {
5836 // Check if this is SM change (not ZA)
5837 int64_t PState = MI.getOperand(0).getImm();
5838 if (PState == AArch64SVCR::SVCRSM || PState == AArch64SVCR::SVCRSMZA) {
5839 // Operand 1 is 1 for start, 0 for stop
5840 return MI.getOperand(1).getImm() == 1;
5841 }
5842 }
5843 }
5844 return false;
5845}
5846
5847/// Returns true if in a streaming call site region without SME-FA64.
5848static bool mustAvoidNeonAtMBBI(const AArch64Subtarget &Subtarget,
5851 return !Subtarget.hasSMEFA64() && isInStreamingCallSiteRegion(MBB, I);
5852}
5853
5856 const DebugLoc &DL, Register DestReg,
5857 Register SrcReg, bool KillSrc,
5858 bool RenamableDest,
5859 bool RenamableSrc) const {
5860 if (AArch64::GPR32spRegClass.contains(DestReg) &&
5861 AArch64::GPR32spRegClass.contains(SrcReg)) {
5862 if (DestReg == AArch64::WSP || SrcReg == AArch64::WSP) {
5863 // If either operand is WSP, expand to ADD #0.
5864 if (Subtarget.hasZeroCycleRegMoveGPR64() &&
5865 !Subtarget.hasZeroCycleRegMoveGPR32()) {
5866 // Cyclone recognizes "ADD Xd, Xn, #0" as a zero-cycle register move.
5867 MCRegister DestRegX = RI.getMatchingSuperReg(DestReg, AArch64::sub_32,
5868 &AArch64::GPR64spRegClass);
5869 MCRegister SrcRegX = RI.getMatchingSuperReg(SrcReg, AArch64::sub_32,
5870 &AArch64::GPR64spRegClass);
5871 // This instruction is reading and writing X registers. This may upset
5872 // the register scavenger and machine verifier, so we need to indicate
5873 // that we are reading an undefined value from SrcRegX, but a proper
5874 // value from SrcReg.
5875 BuildMI(MBB, I, DL, get(AArch64::ADDXri), DestRegX)
5876 .addReg(SrcRegX, RegState::Undef)
5877 .addImm(0)
5879 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
5880 ++NumZCRegMoveInstrsGPR;
5881 } else {
5882 BuildMI(MBB, I, DL, get(AArch64::ADDWri), DestReg)
5883 .addReg(SrcReg, getKillRegState(KillSrc))
5884 .addImm(0)
5886 if (Subtarget.hasZeroCycleRegMoveGPR32())
5887 ++NumZCRegMoveInstrsGPR;
5888 }
5889 } else if (Subtarget.hasZeroCycleRegMoveGPR64() &&
5890 !Subtarget.hasZeroCycleRegMoveGPR32()) {
5891 // Cyclone recognizes "ORR Xd, XZR, Xm" as a zero-cycle register move.
5892 MCRegister DestRegX = RI.getMatchingSuperReg(DestReg, AArch64::sub_32,
5893 &AArch64::GPR64spRegClass);
5894 assert(DestRegX.isValid() && "Destination super-reg not valid");
5895 MCRegister SrcRegX = RI.getMatchingSuperReg(SrcReg, AArch64::sub_32,
5896 &AArch64::GPR64spRegClass);
5897 assert(SrcRegX.isValid() && "Source super-reg not valid");
5898 // This instruction is reading and writing X registers. This may upset
5899 // the register scavenger and machine verifier, so we need to indicate
5900 // that we are reading an undefined value from SrcRegX, but a proper
5901 // value from SrcReg.
5902 BuildMI(MBB, I, DL, get(AArch64::ORRXrr), DestRegX)
5903 .addReg(AArch64::XZR)
5904 .addReg(SrcRegX, RegState::Undef)
5905 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
5906 ++NumZCRegMoveInstrsGPR;
5907 } else {
5908 // Otherwise, expand to ORR WZR.
5909 BuildMI(MBB, I, DL, get(AArch64::ORRWrr), DestReg)
5910 .addReg(AArch64::WZR)
5911 .addReg(SrcReg, getKillRegState(KillSrc));
5912 if (Subtarget.hasZeroCycleRegMoveGPR32())
5913 ++NumZCRegMoveInstrsGPR;
5914 }
5915 return;
5916 }
5917
5918 // GPR32 zeroing
5919 if (AArch64::GPR32spRegClass.contains(DestReg) && SrcReg == AArch64::WZR) {
5920 if (Subtarget.hasZeroCycleZeroingGPR64() &&
5921 !Subtarget.hasZeroCycleZeroingGPR32()) {
5922 MCRegister DestRegX = RI.getMatchingSuperReg(DestReg, AArch64::sub_32,
5923 &AArch64::GPR64spRegClass);
5924 assert(DestRegX.isValid() && "Destination super-reg not valid");
5925 BuildMI(MBB, I, DL, get(AArch64::MOVZXi), DestRegX)
5926 .addImm(0)
5928 ++NumZCZeroingInstrsGPR;
5929 } else if (Subtarget.hasZeroCycleZeroingGPR32()) {
5930 BuildMI(MBB, I, DL, get(AArch64::MOVZWi), DestReg)
5931 .addImm(0)
5933 ++NumZCZeroingInstrsGPR;
5934 } else {
5935 BuildMI(MBB, I, DL, get(AArch64::ORRWrr), DestReg)
5936 .addReg(AArch64::WZR)
5937 .addReg(AArch64::WZR);
5938 }
5939 return;
5940 }
5941
5942 if (AArch64::GPR64spRegClass.contains(DestReg) &&
5943 AArch64::GPR64spRegClass.contains(SrcReg)) {
5944 if (DestReg == AArch64::SP || SrcReg == AArch64::SP) {
5945 // If either operand is SP, expand to ADD #0.
5946 BuildMI(MBB, I, DL, get(AArch64::ADDXri), DestReg)
5947 .addReg(SrcReg, getKillRegState(KillSrc))
5948 .addImm(0)
5950 if (Subtarget.hasZeroCycleRegMoveGPR64())
5951 ++NumZCRegMoveInstrsGPR;
5952 } else {
5953 // Otherwise, expand to ORR XZR.
5954 BuildMI(MBB, I, DL, get(AArch64::ORRXrr), DestReg)
5955 .addReg(AArch64::XZR)
5956 .addReg(SrcReg, getKillRegState(KillSrc));
5957 if (Subtarget.hasZeroCycleRegMoveGPR64())
5958 ++NumZCRegMoveInstrsGPR;
5959 }
5960 return;
5961 }
5962
5963 // GPR64 zeroing
5964 if (AArch64::GPR64spRegClass.contains(DestReg) && SrcReg == AArch64::XZR) {
5965 if (Subtarget.hasZeroCycleZeroingGPR64()) {
5966 BuildMI(MBB, I, DL, get(AArch64::MOVZXi), DestReg)
5967 .addImm(0)
5969 ++NumZCZeroingInstrsGPR;
5970 } else {
5971 BuildMI(MBB, I, DL, get(AArch64::ORRXrr), DestReg)
5972 .addReg(AArch64::XZR)
5973 .addReg(AArch64::XZR);
5974 }
5975 return;
5976 }
5977
5978 // Copy a Predicate register by ORRing with itself.
5979 if (AArch64::PPRRegClass.contains(DestReg) &&
5980 AArch64::PPRRegClass.contains(SrcReg)) {
5981 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
5982 "Unexpected SVE register.");
5983 BuildMI(MBB, I, DL, get(AArch64::ORR_PPzPP), DestReg)
5984 .addReg(SrcReg) // Pg
5985 .addReg(SrcReg)
5986 .addReg(SrcReg, getKillRegState(KillSrc));
5987 return;
5988 }
5989
5990 // Copy a predicate-as-counter register by ORRing with itself as if it
5991 // were a regular predicate (mask) register.
5992 bool DestIsPNR = AArch64::PNRRegClass.contains(DestReg);
5993 bool SrcIsPNR = AArch64::PNRRegClass.contains(SrcReg);
5994 if (DestIsPNR || SrcIsPNR) {
5995 auto ToPPR = [](MCRegister R) -> MCRegister {
5996 return (R - AArch64::PN0) + AArch64::P0;
5997 };
5998 MCRegister PPRSrcReg = SrcIsPNR ? ToPPR(SrcReg) : SrcReg.asMCReg();
5999 MCRegister PPRDestReg = DestIsPNR ? ToPPR(DestReg) : DestReg.asMCReg();
6000
6001 if (PPRSrcReg != PPRDestReg) {
6002 auto NewMI = BuildMI(MBB, I, DL, get(AArch64::ORR_PPzPP), PPRDestReg)
6003 .addReg(PPRSrcReg) // Pg
6004 .addReg(PPRSrcReg)
6005 .addReg(PPRSrcReg, getKillRegState(KillSrc));
6006 if (DestIsPNR)
6007 NewMI.addDef(DestReg, RegState::Implicit);
6008 }
6009 return;
6010 }
6011
6012 // Copy a predicate register pair by copying the individual sub-registers.
6013 if (AArch64::PPR2RegClass.contains(DestReg) &&
6014 AArch64::PPR2RegClass.contains(SrcReg)) {
6015 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6016 "Unexpected SVE predicate register.");
6017 static const unsigned Indices[] = {AArch64::psub0, AArch64::psub1};
6018 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6019 return;
6020 }
6021
6022 // Copy a Z register by ORRing with itself.
6023 if (AArch64::ZPRRegClass.contains(DestReg) &&
6024 AArch64::ZPRRegClass.contains(SrcReg)) {
6025 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6026 "Unexpected SVE register.");
6027 BuildMI(MBB, I, DL, get(AArch64::ORR_ZZZ), DestReg)
6028 .addReg(SrcReg)
6029 .addReg(SrcReg, getKillRegState(KillSrc));
6030 return;
6031 }
6032
6033 // Copy a Z register pair by copying the individual sub-registers.
6034 if ((AArch64::ZPR2RegClass.contains(DestReg) ||
6035 AArch64::ZPR2StridedOrContiguousRegClass.contains(DestReg)) &&
6036 (AArch64::ZPR2RegClass.contains(SrcReg) ||
6037 AArch64::ZPR2StridedOrContiguousRegClass.contains(SrcReg))) {
6038 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6039 "Unexpected SVE register.");
6040 static const unsigned Indices[] = {AArch64::zsub0, AArch64::zsub1};
6041 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6042 return;
6043 }
6044
6045 // Copy a Z register triple by copying the individual sub-registers.
6046 if (AArch64::ZPR3RegClass.contains(DestReg) &&
6047 AArch64::ZPR3RegClass.contains(SrcReg)) {
6048 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6049 "Unexpected SVE register.");
6050 static const unsigned Indices[] = {AArch64::zsub0, AArch64::zsub1,
6051 AArch64::zsub2};
6052 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6053 return;
6054 }
6055
6056 // Copy a Z register quad by copying the individual sub-registers.
6057 if ((AArch64::ZPR4RegClass.contains(DestReg) ||
6058 AArch64::ZPR4StridedOrContiguousRegClass.contains(DestReg)) &&
6059 (AArch64::ZPR4RegClass.contains(SrcReg) ||
6060 AArch64::ZPR4StridedOrContiguousRegClass.contains(SrcReg))) {
6061 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6062 "Unexpected SVE register.");
6063 static const unsigned Indices[] = {AArch64::zsub0, AArch64::zsub1,
6064 AArch64::zsub2, AArch64::zsub3};
6065 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6066 return;
6067 }
6068
6069 // Copy a DDDD register quad by copying the individual sub-registers.
6070 if (AArch64::DDDDRegClass.contains(DestReg) &&
6071 AArch64::DDDDRegClass.contains(SrcReg)) {
6072 static const unsigned Indices[] = {AArch64::dsub0, AArch64::dsub1,
6073 AArch64::dsub2, AArch64::dsub3};
6074 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6075 return;
6076 }
6077
6078 // Copy a DDD register triple by copying the individual sub-registers.
6079 if (AArch64::DDDRegClass.contains(DestReg) &&
6080 AArch64::DDDRegClass.contains(SrcReg)) {
6081 static const unsigned Indices[] = {AArch64::dsub0, AArch64::dsub1,
6082 AArch64::dsub2};
6083 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6084 return;
6085 }
6086
6087 // Copy a DD register pair by copying the individual sub-registers.
6088 if (AArch64::DDRegClass.contains(DestReg) &&
6089 AArch64::DDRegClass.contains(SrcReg)) {
6090 static const unsigned Indices[] = {AArch64::dsub0, AArch64::dsub1};
6091 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6092 return;
6093 }
6094
6095 // Copy a QQQQ register quad by copying the individual sub-registers.
6096 if (AArch64::QQQQRegClass.contains(DestReg) &&
6097 AArch64::QQQQRegClass.contains(SrcReg)) {
6098 static const unsigned Indices[] = {AArch64::qsub0, AArch64::qsub1,
6099 AArch64::qsub2, AArch64::qsub3};
6100 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6101 return;
6102 }
6103
6104 // Copy a QQQ register triple by copying the individual sub-registers.
6105 if (AArch64::QQQRegClass.contains(DestReg) &&
6106 AArch64::QQQRegClass.contains(SrcReg)) {
6107 static const unsigned Indices[] = {AArch64::qsub0, AArch64::qsub1,
6108 AArch64::qsub2};
6109 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6110 return;
6111 }
6112
6113 // Copy a QQ register pair by copying the individual sub-registers.
6114 if (AArch64::QQRegClass.contains(DestReg) &&
6115 AArch64::QQRegClass.contains(SrcReg)) {
6116 static const unsigned Indices[] = {AArch64::qsub0, AArch64::qsub1};
6117 copyPhysRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, Indices);
6118 return;
6119 }
6120
6121 if (AArch64::XSeqPairsClassRegClass.contains(DestReg) &&
6122 AArch64::XSeqPairsClassRegClass.contains(SrcReg)) {
6123 static const unsigned Indices[] = {AArch64::sube64, AArch64::subo64};
6124 copyGPRRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, AArch64::ORRXrs,
6125 AArch64::XZR, Indices);
6126 return;
6127 }
6128
6129 if (AArch64::WSeqPairsClassRegClass.contains(DestReg) &&
6130 AArch64::WSeqPairsClassRegClass.contains(SrcReg)) {
6131 static const unsigned Indices[] = {AArch64::sube32, AArch64::subo32};
6132 copyGPRRegTuple(MBB, I, DL, DestReg, SrcReg, KillSrc, AArch64::ORRWrs,
6133 AArch64::WZR, Indices);
6134 return;
6135 }
6136
6137 if (AArch64::FPR128RegClass.contains(DestReg) &&
6138 AArch64::FPR128RegClass.contains(SrcReg)) {
6139 // In streaming regions, NEON is illegal but streaming-SVE is available.
6140 // Use SVE for copies if we're in a streaming region and SME is available.
6141 // With +sme-fa64, NEON is legal in streaming mode so we can use it.
6142 if ((Subtarget.isSVEorStreamingSVEAvailable() &&
6143 !Subtarget.isNeonAvailable()) ||
6144 mustAvoidNeonAtMBBI(Subtarget, MBB, I)) {
6145 BuildMI(MBB, I, DL, get(AArch64::ORR_ZZZ))
6146 .addReg(AArch64::Z0 + (DestReg - AArch64::Q0), RegState::Define)
6147 .addReg(AArch64::Z0 + (SrcReg - AArch64::Q0))
6148 .addReg(AArch64::Z0 + (SrcReg - AArch64::Q0));
6149 } else if (Subtarget.isNeonAvailable()) {
6150 BuildMI(MBB, I, DL, get(AArch64::ORRv16i8), DestReg)
6151 .addReg(SrcReg)
6152 .addReg(SrcReg, getKillRegState(KillSrc));
6153 if (Subtarget.hasZeroCycleRegMoveFPR128())
6154 ++NumZCRegMoveInstrsFPR;
6155 } else {
6156 BuildMI(MBB, I, DL, get(AArch64::STRQpre))
6157 .addReg(AArch64::SP, RegState::Define)
6158 .addReg(SrcReg, getKillRegState(KillSrc))
6159 .addReg(AArch64::SP)
6160 .addImm(-16);
6161 BuildMI(MBB, I, DL, get(AArch64::LDRQpost))
6162 .addReg(AArch64::SP, RegState::Define)
6163 .addReg(DestReg, RegState::Define)
6164 .addReg(AArch64::SP)
6165 .addImm(16);
6166 }
6167 return;
6168 }
6169
6170 if (AArch64::FPR64RegClass.contains(DestReg) &&
6171 AArch64::FPR64RegClass.contains(SrcReg)) {
6172 if (Subtarget.hasZeroCycleRegMoveFPR128() &&
6173 !Subtarget.hasZeroCycleRegMoveFPR64() &&
6174 !Subtarget.hasZeroCycleRegMoveFPR32() && Subtarget.isNeonAvailable() &&
6175 !mustAvoidNeonAtMBBI(Subtarget, MBB, I)) {
6176 MCRegister DestRegQ = RI.getMatchingSuperReg(DestReg, AArch64::dsub,
6177 &AArch64::FPR128RegClass);
6178 MCRegister SrcRegQ = RI.getMatchingSuperReg(SrcReg, AArch64::dsub,
6179 &AArch64::FPR128RegClass);
6180 // This instruction is reading and writing Q registers. This may upset
6181 // the register scavenger and machine verifier, so we need to indicate
6182 // that we are reading an undefined value from SrcRegQ, but a proper
6183 // value from SrcReg.
6184 BuildMI(MBB, I, DL, get(AArch64::ORRv16i8), DestRegQ)
6185 .addReg(SrcRegQ, RegState::Undef)
6186 .addReg(SrcRegQ, RegState::Undef)
6187 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
6188 ++NumZCRegMoveInstrsFPR;
6189 } else {
6190 BuildMI(MBB, I, DL, get(AArch64::FMOVDr), DestReg)
6191 .addReg(SrcReg, getKillRegState(KillSrc));
6192 if (Subtarget.hasZeroCycleRegMoveFPR64())
6193 ++NumZCRegMoveInstrsFPR;
6194 }
6195 return;
6196 }
6197
6198 if (AArch64::FPR32RegClass.contains(DestReg) &&
6199 AArch64::FPR32RegClass.contains(SrcReg)) {
6200 if (Subtarget.hasZeroCycleRegMoveFPR128() &&
6201 !Subtarget.hasZeroCycleRegMoveFPR64() &&
6202 !Subtarget.hasZeroCycleRegMoveFPR32() && Subtarget.isNeonAvailable() &&
6203 !mustAvoidNeonAtMBBI(Subtarget, MBB, I)) {
6204 MCRegister DestRegQ = RI.getMatchingSuperReg(DestReg, AArch64::ssub,
6205 &AArch64::FPR128RegClass);
6206 MCRegister SrcRegQ = RI.getMatchingSuperReg(SrcReg, AArch64::ssub,
6207 &AArch64::FPR128RegClass);
6208 // This instruction is reading and writing Q registers. This may upset
6209 // the register scavenger and machine verifier, so we need to indicate
6210 // that we are reading an undefined value from SrcRegQ, but a proper
6211 // value from SrcReg.
6212 BuildMI(MBB, I, DL, get(AArch64::ORRv16i8), DestRegQ)
6213 .addReg(SrcRegQ, RegState::Undef)
6214 .addReg(SrcRegQ, RegState::Undef)
6215 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
6216 ++NumZCRegMoveInstrsFPR;
6217 } else if (Subtarget.hasZeroCycleRegMoveFPR64() &&
6218 !Subtarget.hasZeroCycleRegMoveFPR32()) {
6219 MCRegister DestRegD = RI.getMatchingSuperReg(DestReg, AArch64::ssub,
6220 &AArch64::FPR64RegClass);
6221 MCRegister SrcRegD = RI.getMatchingSuperReg(SrcReg, AArch64::ssub,
6222 &AArch64::FPR64RegClass);
6223 // This instruction is reading and writing D registers. This may upset
6224 // the register scavenger and machine verifier, so we need to indicate
6225 // that we are reading an undefined value from SrcRegD, but a proper
6226 // value from SrcReg.
6227 BuildMI(MBB, I, DL, get(AArch64::FMOVDr), DestRegD)
6228 .addReg(SrcRegD, RegState::Undef)
6229 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
6230 ++NumZCRegMoveInstrsFPR;
6231 } else {
6232 BuildMI(MBB, I, DL, get(AArch64::FMOVSr), DestReg)
6233 .addReg(SrcReg, getKillRegState(KillSrc));
6234 if (Subtarget.hasZeroCycleRegMoveFPR32())
6235 ++NumZCRegMoveInstrsFPR;
6236 }
6237 return;
6238 }
6239
6240 if (AArch64::FPR16RegClass.contains(DestReg) &&
6241 AArch64::FPR16RegClass.contains(SrcReg)) {
6242 if (Subtarget.hasZeroCycleRegMoveFPR128() &&
6243 !Subtarget.hasZeroCycleRegMoveFPR64() &&
6244 !Subtarget.hasZeroCycleRegMoveFPR32() && Subtarget.isNeonAvailable() &&
6245 !mustAvoidNeonAtMBBI(Subtarget, MBB, I)) {
6246 MCRegister DestRegQ = RI.getMatchingSuperReg(DestReg, AArch64::hsub,
6247 &AArch64::FPR128RegClass);
6248 MCRegister SrcRegQ = RI.getMatchingSuperReg(SrcReg, AArch64::hsub,
6249 &AArch64::FPR128RegClass);
6250 // This instruction is reading and writing Q registers. This may upset
6251 // the register scavenger and machine verifier, so we need to indicate
6252 // that we are reading an undefined value from SrcRegQ, but a proper
6253 // value from SrcReg.
6254 BuildMI(MBB, I, DL, get(AArch64::ORRv16i8), DestRegQ)
6255 .addReg(SrcRegQ, RegState::Undef)
6256 .addReg(SrcRegQ, RegState::Undef)
6257 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
6258 } else if (Subtarget.hasZeroCycleRegMoveFPR64() &&
6259 !Subtarget.hasZeroCycleRegMoveFPR32()) {
6260 MCRegister DestRegD = RI.getMatchingSuperReg(DestReg, AArch64::hsub,
6261 &AArch64::FPR64RegClass);
6262 MCRegister SrcRegD = RI.getMatchingSuperReg(SrcReg, AArch64::hsub,
6263 &AArch64::FPR64RegClass);
6264 // This instruction is reading and writing D registers. This may upset
6265 // the register scavenger and machine verifier, so we need to indicate
6266 // that we are reading an undefined value from SrcRegD, but a proper
6267 // value from SrcReg.
6268 BuildMI(MBB, I, DL, get(AArch64::FMOVDr), DestRegD)
6269 .addReg(SrcRegD, RegState::Undef)
6270 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
6271 } else {
6272 DestReg = RI.getMatchingSuperReg(DestReg, AArch64::hsub,
6273 &AArch64::FPR32RegClass);
6274 SrcReg = RI.getMatchingSuperReg(SrcReg, AArch64::hsub,
6275 &AArch64::FPR32RegClass);
6276 BuildMI(MBB, I, DL, get(AArch64::FMOVSr), DestReg)
6277 .addReg(SrcReg, getKillRegState(KillSrc));
6278 }
6279 return;
6280 }
6281
6282 if (AArch64::FPR8RegClass.contains(DestReg) &&
6283 AArch64::FPR8RegClass.contains(SrcReg)) {
6284 if (Subtarget.hasZeroCycleRegMoveFPR128() &&
6285 !Subtarget.hasZeroCycleRegMoveFPR64() &&
6286 !Subtarget.hasZeroCycleRegMoveFPR32() && Subtarget.isNeonAvailable() &&
6287 !mustAvoidNeonAtMBBI(Subtarget, MBB, I)) {
6288 MCRegister DestRegQ = RI.getMatchingSuperReg(DestReg, AArch64::bsub,
6289 &AArch64::FPR128RegClass);
6290 MCRegister SrcRegQ = RI.getMatchingSuperReg(SrcReg, AArch64::bsub,
6291 &AArch64::FPR128RegClass);
6292 // This instruction is reading and writing Q registers. This may upset
6293 // the register scavenger and machine verifier, so we need to indicate
6294 // that we are reading an undefined value from SrcRegQ, but a proper
6295 // value from SrcReg.
6296 BuildMI(MBB, I, DL, get(AArch64::ORRv16i8), DestRegQ)
6297 .addReg(SrcRegQ, RegState::Undef)
6298 .addReg(SrcRegQ, RegState::Undef)
6299 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
6300 } else if (Subtarget.hasZeroCycleRegMoveFPR64() &&
6301 !Subtarget.hasZeroCycleRegMoveFPR32()) {
6302 MCRegister DestRegD = RI.getMatchingSuperReg(DestReg, AArch64::bsub,
6303 &AArch64::FPR64RegClass);
6304 MCRegister SrcRegD = RI.getMatchingSuperReg(SrcReg, AArch64::bsub,
6305 &AArch64::FPR64RegClass);
6306 // This instruction is reading and writing D registers. This may upset
6307 // the register scavenger and machine verifier, so we need to indicate
6308 // that we are reading an undefined value from SrcRegD, but a proper
6309 // value from SrcReg.
6310 BuildMI(MBB, I, DL, get(AArch64::FMOVDr), DestRegD)
6311 .addReg(SrcRegD, RegState::Undef)
6312 .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
6313 } else {
6314 DestReg = RI.getMatchingSuperReg(DestReg, AArch64::bsub,
6315 &AArch64::FPR32RegClass);
6316 SrcReg = RI.getMatchingSuperReg(SrcReg, AArch64::bsub,
6317 &AArch64::FPR32RegClass);
6318 BuildMI(MBB, I, DL, get(AArch64::FMOVSr), DestReg)
6319 .addReg(SrcReg, getKillRegState(KillSrc));
6320 }
6321 return;
6322 }
6323
6324 // Copies between GPR64 and FPR64.
6325 if (AArch64::FPR64RegClass.contains(DestReg) &&
6326 AArch64::GPR64RegClass.contains(SrcReg)) {
6327 if (AArch64::XZR == SrcReg) {
6328 BuildMI(MBB, I, DL, get(AArch64::FMOVD0), DestReg);
6329 } else {
6330 BuildMI(MBB, I, DL, get(AArch64::FMOVXDr), DestReg)
6331 .addReg(SrcReg, getKillRegState(KillSrc));
6332 }
6333 return;
6334 }
6335 if (AArch64::GPR64RegClass.contains(DestReg) &&
6336 AArch64::FPR64RegClass.contains(SrcReg)) {
6337 BuildMI(MBB, I, DL, get(AArch64::FMOVDXr), DestReg)
6338 .addReg(SrcReg, getKillRegState(KillSrc));
6339 return;
6340 }
6341 // Copies between GPR32 and FPR32.
6342 if (AArch64::FPR32RegClass.contains(DestReg) &&
6343 AArch64::GPR32RegClass.contains(SrcReg)) {
6344 if (AArch64::WZR == SrcReg) {
6345 BuildMI(MBB, I, DL, get(AArch64::FMOVS0), DestReg);
6346 } else {
6347 BuildMI(MBB, I, DL, get(AArch64::FMOVWSr), DestReg)
6348 .addReg(SrcReg, getKillRegState(KillSrc));
6349 }
6350 return;
6351 }
6352 if (AArch64::GPR32RegClass.contains(DestReg) &&
6353 AArch64::FPR32RegClass.contains(SrcReg)) {
6354 BuildMI(MBB, I, DL, get(AArch64::FMOVSWr), DestReg)
6355 .addReg(SrcReg, getKillRegState(KillSrc));
6356 return;
6357 }
6358
6359 if (DestReg == AArch64::NZCV) {
6360 assert(AArch64::GPR64RegClass.contains(SrcReg) && "Invalid NZCV copy");
6361 BuildMI(MBB, I, DL, get(AArch64::MSR))
6362 .addImm(AArch64SysReg::NZCV)
6363 .addReg(SrcReg, getKillRegState(KillSrc))
6364 .addReg(AArch64::NZCV, RegState::Implicit | RegState::Define);
6365 return;
6366 }
6367
6368 if (SrcReg == AArch64::NZCV) {
6369 assert(AArch64::GPR64RegClass.contains(DestReg) && "Invalid NZCV copy");
6370 BuildMI(MBB, I, DL, get(AArch64::MRS), DestReg)
6371 .addImm(AArch64SysReg::NZCV)
6372 .addReg(AArch64::NZCV, RegState::Implicit | getKillRegState(KillSrc));
6373 return;
6374 }
6375
6376#ifndef NDEBUG
6377 errs() << RI.getRegAsmName(DestReg) << " = COPY " << RI.getRegAsmName(SrcReg)
6378 << "\n";
6379#endif
6380 llvm_unreachable("unimplemented reg-to-reg copy");
6381}
6382
6385 const DebugLoc &DL, Register DestReg,
6386 Register SrcReg, bool KillSrc,
6387 bool RenamableDest,
6388 bool RenamableSrc) const {
6389 ++NumCopyInstrs;
6390 copyPhysRegImpl(MBB, I, DL, DestReg, SrcReg, KillSrc, RenamableDest,
6391 RenamableSrc);
6392 return;
6393}
6394
6397 MachineBasicBlock::iterator InsertBefore,
6398 const MCInstrDesc &MCID,
6399 Register SrcReg, bool IsKill,
6400 unsigned SubIdx0, unsigned SubIdx1, int FI,
6401 MachineMemOperand *MMO) {
6402 Register SrcReg0 = SrcReg;
6403 Register SrcReg1 = SrcReg;
6404 if (SrcReg.isPhysical()) {
6405 SrcReg0 = TRI.getSubReg(SrcReg, SubIdx0);
6406 SubIdx0 = 0;
6407 SrcReg1 = TRI.getSubReg(SrcReg, SubIdx1);
6408 SubIdx1 = 0;
6409 }
6410 BuildMI(MBB, InsertBefore, DebugLoc(), MCID)
6411 .addReg(SrcReg0, getKillRegState(IsKill), SubIdx0)
6412 .addReg(SrcReg1, getKillRegState(IsKill), SubIdx1)
6413 .addFrameIndex(FI)
6414 .addImm(0)
6415 .addMemOperand(MMO);
6416}
6417
6420 Register SrcReg, bool isKill, int FI,
6421 const TargetRegisterClass *RC,
6422 Register VReg,
6423 MachineInstr::MIFlag Flags) const {
6424 MachineFunction &MF = *MBB.getParent();
6425 MachineFrameInfo &MFI = MF.getFrameInfo();
6426
6428 MachineMemOperand *MMO =
6430 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
6431 unsigned Opc = 0;
6432 bool Offset = true;
6434 unsigned StackID = TargetStackID::Default;
6435 switch (RI.getSpillSize(*RC)) {
6436 case 1:
6437 if (AArch64::FPR8RegClass.hasSubClassEq(RC))
6438 Opc = AArch64::STRBui;
6439 break;
6440 case 2: {
6441 if (AArch64::FPR16RegClass.hasSubClassEq(RC))
6442 Opc = AArch64::STRHui;
6443 else if (AArch64::PNRRegClass.hasSubClassEq(RC) ||
6444 AArch64::PPRRegClass.hasSubClassEq(RC)) {
6445 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6446 "Unexpected register store without SVE store instructions");
6447 Opc = AArch64::STR_PXI;
6449 }
6450 break;
6451 }
6452 case 4:
6453 if (AArch64::GPR32allRegClass.hasSubClassEq(RC)) {
6454 Opc = AArch64::STRWui;
6455 if (SrcReg.isVirtual())
6456 MF.getRegInfo().constrainRegClass(SrcReg, &AArch64::GPR32RegClass);
6457 else
6458 assert(SrcReg != AArch64::WSP);
6459 } else if (AArch64::FPR32RegClass.hasSubClassEq(RC))
6460 Opc = AArch64::STRSui;
6461 else if (AArch64::PPR2RegClass.hasSubClassEq(RC)) {
6462 Opc = AArch64::STR_PPXI;
6464 }
6465 break;
6466 case 8:
6467 if (AArch64::GPR64allRegClass.hasSubClassEq(RC)) {
6468 Opc = AArch64::STRXui;
6469 if (SrcReg.isVirtual())
6470 MF.getRegInfo().constrainRegClass(SrcReg, &AArch64::GPR64RegClass);
6471 else
6472 assert(SrcReg != AArch64::SP);
6473 } else if (AArch64::FPR64RegClass.hasSubClassEq(RC)) {
6474 Opc = AArch64::STRDui;
6475 } else if (AArch64::WSeqPairsClassRegClass.hasSubClassEq(RC)) {
6477 get(AArch64::STPWi), SrcReg, isKill,
6478 AArch64::sube32, AArch64::subo32, FI, MMO);
6479 return;
6480 }
6481 break;
6482 case 16:
6483 if (AArch64::FPR128RegClass.hasSubClassEq(RC))
6484 Opc = AArch64::STRQui;
6485 else if (AArch64::DDRegClass.hasSubClassEq(RC)) {
6486 assert(Subtarget.hasNEON() && "Unexpected register store without NEON");
6487 Opc = AArch64::ST1Twov1d;
6488 Offset = false;
6489 } else if (AArch64::XSeqPairsClassRegClass.hasSubClassEq(RC)) {
6491 get(AArch64::STPXi), SrcReg, isKill,
6492 AArch64::sube64, AArch64::subo64, FI, MMO);
6493 return;
6494 } else if (AArch64::ZPRRegClass.hasSubClassEq(RC)) {
6495 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6496 "Unexpected register store without SVE store instructions");
6497 Opc = AArch64::STR_ZXI;
6499 }
6500 break;
6501 case 24:
6502 if (AArch64::DDDRegClass.hasSubClassEq(RC)) {
6503 assert(Subtarget.hasNEON() && "Unexpected register store without NEON");
6504 Opc = AArch64::ST1Threev1d;
6505 Offset = false;
6506 }
6507 break;
6508 case 32:
6509 if (AArch64::DDDDRegClass.hasSubClassEq(RC)) {
6510 assert(Subtarget.hasNEON() && "Unexpected register store without NEON");
6511 Opc = AArch64::ST1Fourv1d;
6512 Offset = false;
6513 } else if (AArch64::QQRegClass.hasSubClassEq(RC)) {
6514 assert(Subtarget.hasNEON() && "Unexpected register store without NEON");
6515 Opc = AArch64::ST1Twov2d;
6516 Offset = false;
6517 } else if (AArch64::ZPR2StridedOrContiguousRegClass.hasSubClassEq(RC)) {
6518 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6519 "Unexpected register store without SVE store instructions");
6520 Opc = AArch64::STR_ZZXI_STRIDED_CONTIGUOUS;
6522 } else if (AArch64::ZPR2RegClass.hasSubClassEq(RC)) {
6523 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6524 "Unexpected register store without SVE store instructions");
6525 Opc = AArch64::STR_ZZXI;
6527 }
6528 break;
6529 case 48:
6530 if (AArch64::QQQRegClass.hasSubClassEq(RC)) {
6531 assert(Subtarget.hasNEON() && "Unexpected register store without NEON");
6532 Opc = AArch64::ST1Threev2d;
6533 Offset = false;
6534 } else if (AArch64::ZPR3RegClass.hasSubClassEq(RC)) {
6535 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6536 "Unexpected register store without SVE store instructions");
6537 Opc = AArch64::STR_ZZZXI;
6539 }
6540 break;
6541 case 64:
6542 if (AArch64::QQQQRegClass.hasSubClassEq(RC)) {
6543 assert(Subtarget.hasNEON() && "Unexpected register store without NEON");
6544 Opc = AArch64::ST1Fourv2d;
6545 Offset = false;
6546 } else if (AArch64::ZPR4StridedOrContiguousRegClass.hasSubClassEq(RC)) {
6547 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6548 "Unexpected register store without SVE store instructions");
6549 Opc = AArch64::STR_ZZZZXI_STRIDED_CONTIGUOUS;
6551 } else if (AArch64::ZPR4RegClass.hasSubClassEq(RC)) {
6552 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6553 "Unexpected register store without SVE store instructions");
6554 Opc = AArch64::STR_ZZZZXI;
6556 }
6557 break;
6558 }
6559 assert(Opc && "Unknown register class");
6560 MFI.setStackID(FI, StackID);
6561
6563 .addReg(SrcReg, getKillRegState(isKill))
6564 .addFrameIndex(FI);
6565
6566 if (Offset)
6567 MI.addImm(0);
6568 if (PNRReg.isValid())
6569 MI.addDef(PNRReg, RegState::Implicit);
6570 MI.addMemOperand(MMO);
6571}
6572
6575 MachineBasicBlock::iterator InsertBefore,
6576 const MCInstrDesc &MCID,
6577 Register DestReg, unsigned SubIdx0,
6578 unsigned SubIdx1, int FI,
6579 MachineMemOperand *MMO) {
6580 Register DestReg0 = DestReg;
6581 Register DestReg1 = DestReg;
6582 bool IsUndef = true;
6583 if (DestReg.isPhysical()) {
6584 DestReg0 = TRI.getSubReg(DestReg, SubIdx0);
6585 SubIdx0 = 0;
6586 DestReg1 = TRI.getSubReg(DestReg, SubIdx1);
6587 SubIdx1 = 0;
6588 IsUndef = false;
6589 }
6590 BuildMI(MBB, InsertBefore, DebugLoc(), MCID)
6591 .addReg(DestReg0, RegState::Define | getUndefRegState(IsUndef), SubIdx0)
6592 .addReg(DestReg1, RegState::Define | getUndefRegState(IsUndef), SubIdx1)
6593 .addFrameIndex(FI)
6594 .addImm(0)
6595 .addMemOperand(MMO);
6596}
6597
6600 Register DestReg, int FI,
6601 const TargetRegisterClass *RC,
6602 Register VReg, unsigned SubReg,
6603 MachineInstr::MIFlag Flags) const {
6604 MachineFunction &MF = *MBB.getParent();
6605 MachineFrameInfo &MFI = MF.getFrameInfo();
6607 MachineMemOperand *MMO =
6609 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
6610
6611 unsigned Opc = 0;
6612 bool Offset = true;
6613 unsigned StackID = TargetStackID::Default;
6614 Register PNRReg;
6615 switch (TRI.getSpillSize(*RC)) {
6616 case 1:
6617 if (AArch64::FPR8RegClass.hasSubClassEq(RC))
6618 Opc = AArch64::LDRBui;
6619 break;
6620 case 2: {
6621 bool IsPNR = AArch64::PNRRegClass.hasSubClassEq(RC);
6622 if (AArch64::FPR16RegClass.hasSubClassEq(RC))
6623 Opc = AArch64::LDRHui;
6624 else if (IsPNR || AArch64::PPRRegClass.hasSubClassEq(RC)) {
6625 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6626 "Unexpected register load without SVE load instructions");
6627 if (IsPNR)
6628 PNRReg = DestReg;
6629 Opc = AArch64::LDR_PXI;
6631 }
6632 break;
6633 }
6634 case 4:
6635 if (AArch64::GPR32allRegClass.hasSubClassEq(RC)) {
6636 Opc = AArch64::LDRWui;
6637 if (DestReg.isVirtual())
6638 MF.getRegInfo().constrainRegClass(DestReg, &AArch64::GPR32RegClass);
6639 else
6640 assert(DestReg != AArch64::WSP);
6641 } else if (AArch64::FPR32RegClass.hasSubClassEq(RC))
6642 Opc = AArch64::LDRSui;
6643 else if (AArch64::PPR2RegClass.hasSubClassEq(RC)) {
6644 Opc = AArch64::LDR_PPXI;
6646 }
6647 break;
6648 case 8:
6649 if (AArch64::GPR64allRegClass.hasSubClassEq(RC)) {
6650 Opc = AArch64::LDRXui;
6651 if (DestReg.isVirtual())
6652 MF.getRegInfo().constrainRegClass(DestReg, &AArch64::GPR64RegClass);
6653 else
6654 assert(DestReg != AArch64::SP);
6655 } else if (AArch64::FPR64RegClass.hasSubClassEq(RC)) {
6656 Opc = AArch64::LDRDui;
6657 } else if (AArch64::WSeqPairsClassRegClass.hasSubClassEq(RC)) {
6659 get(AArch64::LDPWi), DestReg, AArch64::sube32,
6660 AArch64::subo32, FI, MMO);
6661 return;
6662 }
6663 break;
6664 case 16:
6665 if (AArch64::FPR128RegClass.hasSubClassEq(RC))
6666 Opc = AArch64::LDRQui;
6667 else if (AArch64::DDRegClass.hasSubClassEq(RC)) {
6668 assert(Subtarget.hasNEON() && "Unexpected register load without NEON");
6669 Opc = AArch64::LD1Twov1d;
6670 Offset = false;
6671 } else if (AArch64::XSeqPairsClassRegClass.hasSubClassEq(RC)) {
6673 get(AArch64::LDPXi), DestReg, AArch64::sube64,
6674 AArch64::subo64, FI, MMO);
6675 return;
6676 } else if (AArch64::ZPRRegClass.hasSubClassEq(RC)) {
6677 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6678 "Unexpected register load without SVE load instructions");
6679 Opc = AArch64::LDR_ZXI;
6681 }
6682 break;
6683 case 24:
6684 if (AArch64::DDDRegClass.hasSubClassEq(RC)) {
6685 assert(Subtarget.hasNEON() && "Unexpected register load without NEON");
6686 Opc = AArch64::LD1Threev1d;
6687 Offset = false;
6688 }
6689 break;
6690 case 32:
6691 if (AArch64::DDDDRegClass.hasSubClassEq(RC)) {
6692 assert(Subtarget.hasNEON() && "Unexpected register load without NEON");
6693 Opc = AArch64::LD1Fourv1d;
6694 Offset = false;
6695 } else if (AArch64::QQRegClass.hasSubClassEq(RC)) {
6696 assert(Subtarget.hasNEON() && "Unexpected register load without NEON");
6697 Opc = AArch64::LD1Twov2d;
6698 Offset = false;
6699 } else if (AArch64::ZPR2StridedOrContiguousRegClass.hasSubClassEq(RC)) {
6700 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6701 "Unexpected register load without SVE load instructions");
6702 Opc = AArch64::LDR_ZZXI_STRIDED_CONTIGUOUS;
6704 } else if (AArch64::ZPR2RegClass.hasSubClassEq(RC)) {
6705 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6706 "Unexpected register load without SVE load instructions");
6707 Opc = AArch64::LDR_ZZXI;
6709 }
6710 break;
6711 case 48:
6712 if (AArch64::QQQRegClass.hasSubClassEq(RC)) {
6713 assert(Subtarget.hasNEON() && "Unexpected register load without NEON");
6714 Opc = AArch64::LD1Threev2d;
6715 Offset = false;
6716 } else if (AArch64::ZPR3RegClass.hasSubClassEq(RC)) {
6717 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6718 "Unexpected register load without SVE load instructions");
6719 Opc = AArch64::LDR_ZZZXI;
6721 }
6722 break;
6723 case 64:
6724 if (AArch64::QQQQRegClass.hasSubClassEq(RC)) {
6725 assert(Subtarget.hasNEON() && "Unexpected register load without NEON");
6726 Opc = AArch64::LD1Fourv2d;
6727 Offset = false;
6728 } else if (AArch64::ZPR4StridedOrContiguousRegClass.hasSubClassEq(RC)) {
6729 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6730 "Unexpected register load without SVE load instructions");
6731 Opc = AArch64::LDR_ZZZZXI_STRIDED_CONTIGUOUS;
6733 } else if (AArch64::ZPR4RegClass.hasSubClassEq(RC)) {
6734 assert(Subtarget.isSVEorStreamingSVEAvailable() &&
6735 "Unexpected register load without SVE load instructions");
6736 Opc = AArch64::LDR_ZZZZXI;
6738 }
6739 break;
6740 }
6741
6742 assert(Opc && "Unknown register class");
6743 MFI.setStackID(FI, StackID);
6744
6746 .addReg(DestReg, getDefRegState(true))
6747 .addFrameIndex(FI);
6748 if (Offset)
6749 MI.addImm(0);
6750 if (PNRReg.isValid() && !PNRReg.isVirtual())
6751 MI.addDef(PNRReg, RegState::Implicit);
6752 MI.addMemOperand(MMO);
6753}
6754
6756 const MachineInstr &UseMI,
6757 const TargetRegisterInfo *TRI) {
6758 return any_of(instructionsWithoutDebug(std::next(DefMI.getIterator()),
6759 UseMI.getIterator()),
6760 [TRI](const MachineInstr &I) {
6761 return I.modifiesRegister(AArch64::NZCV, TRI) ||
6762 I.readsRegister(AArch64::NZCV, TRI);
6763 });
6764}
6765
6766void AArch64InstrInfo::decomposeStackOffsetForDwarfOffsets(
6767 const StackOffset &Offset, int64_t &ByteSized, int64_t &VGSized) {
6768 // The smallest scalable element supported by scaled SVE addressing
6769 // modes are predicates, which are 2 scalable bytes in size. So the scalable
6770 // byte offset must always be a multiple of 2.
6771 assert(Offset.getScalable() % 2 == 0 && "Invalid frame offset");
6772
6773 // VGSized offsets are divided by '2', because the VG register is the
6774 // the number of 64bit granules as opposed to 128bit vector chunks,
6775 // which is how the 'n' in e.g. MVT::nxv1i8 is modelled.
6776 // So, for a stack offset of 16 MVT::nxv1i8's, the size is n x 16 bytes.
6777 // VG = n * 2 and the dwarf offset must be VG * 8 bytes.
6778 ByteSized = Offset.getFixed();
6779 VGSized = Offset.getScalable() / 2;
6780}
6781
6782/// Returns the offset in parts to which this frame offset can be
6783/// decomposed for the purpose of describing a frame offset.
6784/// For non-scalable offsets this is simply its byte size.
6785void AArch64InstrInfo::decomposeStackOffsetForFrameOffsets(
6786 const StackOffset &Offset, int64_t &NumBytes, int64_t &NumPredicateVectors,
6787 int64_t &NumDataVectors) {
6788 // The smallest scalable element supported by scaled SVE addressing
6789 // modes are predicates, which are 2 scalable bytes in size. So the scalable
6790 // byte offset must always be a multiple of 2.
6791 assert(Offset.getScalable() % 2 == 0 && "Invalid frame offset");
6792
6793 NumBytes = Offset.getFixed();
6794 NumDataVectors = 0;
6795 NumPredicateVectors = Offset.getScalable() / 2;
6796 // This method is used to get the offsets to adjust the frame offset.
6797 // If the function requires ADDPL to be used and needs more than two ADDPL
6798 // instructions, part of the offset is folded into NumDataVectors so that it
6799 // uses ADDVL for part of it, reducing the number of ADDPL instructions.
6800 if (NumPredicateVectors % 8 == 0 || NumPredicateVectors < -64 ||
6801 NumPredicateVectors > 62) {
6802 NumDataVectors = NumPredicateVectors / 8;
6803 NumPredicateVectors -= NumDataVectors * 8;
6804 }
6805}
6806
6807// Convenience function to create a DWARF expression for: Constant `Operation`.
6808// This helper emits compact sequences for common cases. For example, for`-15
6809// DW_OP_plus`, this helper would create DW_OP_lit15 DW_OP_minus.
6812 if (Operation == dwarf::DW_OP_plus && Constant < 0 && -Constant <= 31) {
6813 // -Constant (1 to 31)
6814 Expr.push_back(dwarf::DW_OP_lit0 - Constant);
6815 Operation = dwarf::DW_OP_minus;
6816 } else if (Constant >= 0 && Constant <= 31) {
6817 // Literal value 0 to 31
6818 Expr.push_back(dwarf::DW_OP_lit0 + Constant);
6819 } else {
6820 // Signed constant
6821 Expr.push_back(dwarf::DW_OP_consts);
6823 }
6824 return Expr.push_back(Operation);
6825}
6826
6827// Convenience function to create a DWARF expression for a register.
6828static void appendReadRegExpr(SmallVectorImpl<char> &Expr, unsigned RegNum) {
6829 Expr.push_back((char)dwarf::DW_OP_bregx);
6831 Expr.push_back(0);
6832}
6833
6834// Convenience function to create a DWARF expression for loading a register from
6835// a CFA offset.
6837 int64_t OffsetFromDefCFA) {
6838 // This assumes the top of the DWARF stack contains the CFA.
6839 Expr.push_back(dwarf::DW_OP_dup);
6840 // Add the offset to the register.
6841 appendConstantExpr(Expr, OffsetFromDefCFA, dwarf::DW_OP_plus);
6842 // Dereference the address (loads a 64 bit value)..
6843 Expr.push_back(dwarf::DW_OP_deref);
6844}
6845
6846// Convenience function to create a comment for
6847// (+/-) NumBytes (* RegScale)?
6848static void appendOffsetComment(int NumBytes, llvm::raw_string_ostream &Comment,
6849 StringRef RegScale = {}) {
6850 if (NumBytes) {
6851 Comment << (NumBytes < 0 ? " - " : " + ") << std::abs(NumBytes);
6852 if (!RegScale.empty())
6853 Comment << ' ' << RegScale;
6854 }
6855}
6856
6857// Creates an MCCFIInstruction:
6858// { DW_CFA_def_cfa_expression, ULEB128 (sizeof expr), expr }
6860 unsigned Reg,
6861 const StackOffset &Offset) {
6862 int64_t NumBytes, NumVGScaledBytes;
6863 AArch64InstrInfo::decomposeStackOffsetForDwarfOffsets(Offset, NumBytes,
6864 NumVGScaledBytes);
6865 std::string CommentBuffer;
6866 llvm::raw_string_ostream Comment(CommentBuffer);
6867
6868 if (Reg == AArch64::SP)
6869 Comment << "sp";
6870 else if (Reg == AArch64::FP)
6871 Comment << "fp";
6872 else
6873 Comment << printReg(Reg, &TRI);
6874
6875 // Build up the expression (Reg + NumBytes + VG * NumVGScaledBytes)
6876 SmallString<64> Expr;
6877 unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true);
6878 assert(DwarfReg <= 31 && "DwarfReg out of bounds (0..31)");
6879 // Reg + NumBytes
6880 Expr.push_back(dwarf::DW_OP_breg0 + DwarfReg);
6881 appendLEB128<LEB128Sign::Signed>(Expr, NumBytes);
6882 appendOffsetComment(NumBytes, Comment);
6883 if (NumVGScaledBytes) {
6884 // + VG * NumVGScaledBytes
6885 appendOffsetComment(NumVGScaledBytes, Comment, "* VG");
6886 appendReadRegExpr(Expr, TRI.getDwarfRegNum(AArch64::VG, true));
6887 appendConstantExpr(Expr, NumVGScaledBytes, dwarf::DW_OP_mul);
6888 Expr.push_back(dwarf::DW_OP_plus);
6889 }
6890
6891 // Wrap this into DW_CFA_def_cfa.
6892 SmallString<64> DefCfaExpr;
6893 DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression);
6894 appendLEB128<LEB128Sign::Unsigned>(DefCfaExpr, Expr.size());
6895 DefCfaExpr.append(Expr.str());
6896 return MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str(), SMLoc(),
6897 Comment.str());
6898}
6899
6901 unsigned FrameReg, unsigned Reg,
6902 const StackOffset &Offset,
6903 bool LastAdjustmentWasScalable) {
6904 if (Offset.getScalable())
6905 return createDefCFAExpression(TRI, Reg, Offset);
6906
6907 if (FrameReg == Reg && !LastAdjustmentWasScalable)
6908 return MCCFIInstruction::cfiDefCfaOffset(nullptr, int(Offset.getFixed()));
6909
6910 unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true);
6911 return MCCFIInstruction::cfiDefCfa(nullptr, DwarfReg, (int)Offset.getFixed());
6912}
6913
6916 const StackOffset &OffsetFromDefCFA,
6917 std::optional<int64_t> IncomingVGOffsetFromDefCFA) {
6918 int64_t NumBytes, NumVGScaledBytes;
6919 AArch64InstrInfo::decomposeStackOffsetForDwarfOffsets(
6920 OffsetFromDefCFA, NumBytes, NumVGScaledBytes);
6921
6922 unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true);
6923
6924 // Non-scalable offsets can use DW_CFA_offset directly.
6925 if (!NumVGScaledBytes)
6926 return MCCFIInstruction::createOffset(nullptr, DwarfReg, NumBytes);
6927
6928 std::string CommentBuffer;
6929 llvm::raw_string_ostream Comment(CommentBuffer);
6930 Comment << printReg(Reg, &TRI) << " @ cfa";
6931
6932 // Build up expression (CFA + VG * NumVGScaledBytes + NumBytes)
6933 assert(NumVGScaledBytes && "Expected scalable offset");
6934 SmallString<64> OffsetExpr;
6935 // + VG * NumVGScaledBytes
6936 StringRef VGRegScale;
6937 if (IncomingVGOffsetFromDefCFA) {
6938 appendLoadRegExpr(OffsetExpr, *IncomingVGOffsetFromDefCFA);
6939 VGRegScale = "* IncomingVG";
6940 } else {
6941 appendReadRegExpr(OffsetExpr, TRI.getDwarfRegNum(AArch64::VG, true));
6942 VGRegScale = "* VG";
6943 }
6944 appendConstantExpr(OffsetExpr, NumVGScaledBytes, dwarf::DW_OP_mul);
6945 appendOffsetComment(NumVGScaledBytes, Comment, VGRegScale);
6946 OffsetExpr.push_back(dwarf::DW_OP_plus);
6947 if (NumBytes) {
6948 // + NumBytes
6949 appendOffsetComment(NumBytes, Comment);
6950 appendConstantExpr(OffsetExpr, NumBytes, dwarf::DW_OP_plus);
6951 }
6952
6953 // Wrap this into DW_CFA_expression
6954 SmallString<64> CfaExpr;
6955 CfaExpr.push_back(dwarf::DW_CFA_expression);
6956 appendLEB128<LEB128Sign::Unsigned>(CfaExpr, DwarfReg);
6957 appendLEB128<LEB128Sign::Unsigned>(CfaExpr, OffsetExpr.size());
6958 CfaExpr.append(OffsetExpr.str());
6959
6960 return MCCFIInstruction::createEscape(nullptr, CfaExpr.str(), SMLoc(),
6961 Comment.str());
6962}
6963
6964// Helper function to emit a frame offset adjustment from a given
6965// pointer (SrcReg), stored into DestReg. This function is explicit
6966// in that it requires the opcode.
6969 const DebugLoc &DL, unsigned DestReg,
6970 unsigned SrcReg, int64_t Offset, unsigned Opc,
6971 const TargetInstrInfo *TII,
6972 MachineInstr::MIFlag Flag, bool NeedsWinCFI,
6973 bool *HasWinCFI, bool EmitCFAOffset,
6974 StackOffset CFAOffset, unsigned FrameReg) {
6975 int Sign = 1;
6976 unsigned MaxEncoding, ShiftSize;
6977 switch (Opc) {
6978 case AArch64::ADDXri:
6979 case AArch64::ADDSXri:
6980 case AArch64::SUBXri:
6981 case AArch64::SUBSXri:
6982 MaxEncoding = 0xfff;
6983 ShiftSize = 12;
6984 break;
6985 case AArch64::ADDVL_XXI:
6986 case AArch64::ADDPL_XXI:
6987 case AArch64::ADDSVL_XXI:
6988 case AArch64::ADDSPL_XXI:
6989 MaxEncoding = 31;
6990 ShiftSize = 0;
6991 if (Offset < 0) {
6992 MaxEncoding = 32;
6993 Sign = -1;
6994 Offset = -Offset;
6995 }
6996 break;
6997 default:
6998 llvm_unreachable("Unsupported opcode");
6999 }
7000
7001 // `Offset` can be in bytes or in "scalable bytes".
7002 int VScale = 1;
7003 if (Opc == AArch64::ADDVL_XXI || Opc == AArch64::ADDSVL_XXI)
7004 VScale = 16;
7005 else if (Opc == AArch64::ADDPL_XXI || Opc == AArch64::ADDSPL_XXI)
7006 VScale = 2;
7007
7008 // FIXME: If the offset won't fit in 24-bits, compute the offset into a
7009 // scratch register. If DestReg is a virtual register, use it as the
7010 // scratch register; otherwise, create a new virtual register (to be
7011 // replaced by the scavenger at the end of PEI). That case can be optimized
7012 // slightly if DestReg is SP which is always 16-byte aligned, so the scratch
7013 // register can be loaded with offset%8 and the add/sub can use an extending
7014 // instruction with LSL#3.
7015 // Currently the function handles any offsets but generates a poor sequence
7016 // of code.
7017 // assert(Offset < (1 << 24) && "unimplemented reg plus immediate");
7018
7019 const unsigned MaxEncodableValue = MaxEncoding << ShiftSize;
7020 Register TmpReg = DestReg;
7021 if (TmpReg == AArch64::XZR)
7022 TmpReg = MBB.getParent()->getRegInfo().createVirtualRegister(
7023 &AArch64::GPR64RegClass);
7024 do {
7025 uint64_t ThisVal = std::min<uint64_t>(Offset, MaxEncodableValue);
7026 unsigned LocalShiftSize = 0;
7027 if (ThisVal > MaxEncoding) {
7028 ThisVal = ThisVal >> ShiftSize;
7029 LocalShiftSize = ShiftSize;
7030 }
7031 assert((ThisVal >> ShiftSize) <= MaxEncoding &&
7032 "Encoding cannot handle value that big");
7033
7034 Offset -= ThisVal << LocalShiftSize;
7035 if (Offset == 0)
7036 TmpReg = DestReg;
7037 auto MBI = BuildMI(MBB, MBBI, DL, TII->get(Opc), TmpReg)
7038 .addReg(SrcReg)
7039 .addImm(Sign * (int)ThisVal);
7040 if (ShiftSize)
7041 MBI = MBI.addImm(
7043 MBI = MBI.setMIFlag(Flag);
7044
7045 auto Change =
7046 VScale == 1
7047 ? StackOffset::getFixed(ThisVal << LocalShiftSize)
7048 : StackOffset::getScalable(VScale * (ThisVal << LocalShiftSize));
7049 if (Sign == -1 || Opc == AArch64::SUBXri || Opc == AArch64::SUBSXri)
7050 CFAOffset += Change;
7051 else
7052 CFAOffset -= Change;
7053 if (EmitCFAOffset && DestReg == TmpReg) {
7054 MachineFunction &MF = *MBB.getParent();
7055 const TargetSubtargetInfo &STI = MF.getSubtarget();
7056 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
7057
7058 unsigned CFIIndex = MF.addFrameInst(
7059 createDefCFA(TRI, FrameReg, DestReg, CFAOffset, VScale != 1));
7060 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
7061 .addCFIIndex(CFIIndex)
7062 .setMIFlags(Flag);
7063 }
7064
7065 if (NeedsWinCFI) {
7066 int Imm = (int)(ThisVal << LocalShiftSize);
7067 if (VScale != 1 && DestReg == AArch64::SP) {
7068 if (HasWinCFI)
7069 *HasWinCFI = true;
7070 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_AllocZ))
7071 .addImm(ThisVal)
7072 .setMIFlag(Flag);
7073 } else if ((DestReg == AArch64::FP && SrcReg == AArch64::SP) ||
7074 (SrcReg == AArch64::FP && DestReg == AArch64::SP)) {
7075 assert(VScale == 1 && "Expected non-scalable operation");
7076 if (HasWinCFI)
7077 *HasWinCFI = true;
7078 if (Imm == 0)
7079 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_SetFP)).setMIFlag(Flag);
7080 else
7081 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_AddFP))
7082 .addImm(Imm)
7083 .setMIFlag(Flag);
7084 assert(Offset == 0 && "Expected remaining offset to be zero to "
7085 "emit a single SEH directive");
7086 } else if (DestReg == AArch64::SP) {
7087 assert(VScale == 1 && "Expected non-scalable operation");
7088 if (HasWinCFI)
7089 *HasWinCFI = true;
7090 assert(SrcReg == AArch64::SP && "Unexpected SrcReg for SEH_StackAlloc");
7091 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_StackAlloc))
7092 .addImm(Imm)
7093 .setMIFlag(Flag);
7094 }
7095 }
7096
7097 SrcReg = TmpReg;
7098 } while (Offset);
7099}
7100
7103 unsigned DestReg, unsigned SrcReg,
7105 MachineInstr::MIFlag Flag, bool SetNZCV,
7106 bool NeedsWinCFI, bool *HasWinCFI,
7107 bool EmitCFAOffset, StackOffset CFAOffset,
7108 unsigned FrameReg) {
7109 // If a function is marked as arm_locally_streaming, then the runtime value of
7110 // vscale in the prologue/epilogue is different the runtime value of vscale
7111 // in the function's body. To avoid having to consider multiple vscales,
7112 // we can use `addsvl` to allocate any scalable stack-slots, which under
7113 // most circumstances will be only locals, not callee-save slots.
7114 const Function &F = MBB.getParent()->getFunction();
7115 bool UseSVL = F.hasFnAttribute("aarch64_pstate_sm_body");
7116
7117 int64_t Bytes, NumPredicateVectors, NumDataVectors;
7118 AArch64InstrInfo::decomposeStackOffsetForFrameOffsets(
7119 Offset, Bytes, NumPredicateVectors, NumDataVectors);
7120
7121 // Insert ADDSXri for scalable offset at the end.
7122 bool NeedsFinalDefNZCV = SetNZCV && (NumPredicateVectors || NumDataVectors);
7123 if (NeedsFinalDefNZCV)
7124 SetNZCV = false;
7125
7126 // First emit non-scalable frame offsets, or a simple 'mov'.
7127 if (Bytes || (!Offset && SrcReg != DestReg)) {
7128 assert((DestReg != AArch64::SP || Bytes % 8 == 0) &&
7129 "SP increment/decrement not 8-byte aligned");
7130 unsigned Opc = SetNZCV ? AArch64::ADDSXri : AArch64::ADDXri;
7131 if (Bytes < 0) {
7132 Bytes = -Bytes;
7133 Opc = SetNZCV ? AArch64::SUBSXri : AArch64::SUBXri;
7134 }
7135 emitFrameOffsetAdj(MBB, MBBI, DL, DestReg, SrcReg, Bytes, Opc, TII, Flag,
7136 NeedsWinCFI, HasWinCFI, EmitCFAOffset, CFAOffset,
7137 FrameReg);
7138 CFAOffset += (Opc == AArch64::ADDXri || Opc == AArch64::ADDSXri)
7139 ? StackOffset::getFixed(-Bytes)
7140 : StackOffset::getFixed(Bytes);
7141 SrcReg = DestReg;
7142 FrameReg = DestReg;
7143 }
7144
7145 assert(!(NeedsWinCFI && NumPredicateVectors) &&
7146 "WinCFI can't allocate fractions of an SVE data vector");
7147
7148 if (NumDataVectors) {
7149 emitFrameOffsetAdj(MBB, MBBI, DL, DestReg, SrcReg, NumDataVectors,
7150 UseSVL ? AArch64::ADDSVL_XXI : AArch64::ADDVL_XXI, TII,
7151 Flag, NeedsWinCFI, HasWinCFI, EmitCFAOffset, CFAOffset,
7152 FrameReg);
7153 CFAOffset += StackOffset::getScalable(-NumDataVectors * 16);
7154 SrcReg = DestReg;
7155 }
7156
7157 if (NumPredicateVectors) {
7158 assert(DestReg != AArch64::SP && "Unaligned access to SP");
7159 emitFrameOffsetAdj(MBB, MBBI, DL, DestReg, SrcReg, NumPredicateVectors,
7160 UseSVL ? AArch64::ADDSPL_XXI : AArch64::ADDPL_XXI, TII,
7161 Flag, NeedsWinCFI, HasWinCFI, EmitCFAOffset, CFAOffset,
7162 FrameReg);
7163 }
7164
7165 if (NeedsFinalDefNZCV)
7166 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDSXri), DestReg)
7167 .addReg(DestReg)
7168 .addImm(0)
7169 .addImm(0);
7170}
7171
7174 int FrameIndex, MachineInstr *&CopyMI, LiveIntervals *LIS,
7175 VirtRegMap *VRM) const {
7177 // This is a bit of a hack. Consider this instruction:
7178 //
7179 // %0 = COPY %sp; GPR64all:%0
7180 //
7181 // We explicitly chose GPR64all for the virtual register so such a copy might
7182 // be eliminated by RegisterCoalescer. However, that may not be possible, and
7183 // %0 may even spill. We can't spill %sp, and since it is in the GPR64all
7184 // register class, TargetInstrInfo::foldMemoryOperand() is going to try.
7185 //
7186 // To prevent that, we are going to constrain the %0 register class here.
7187 if (MI.isFullCopy()) {
7188 Register DstReg = MI.getOperand(0).getReg();
7189 Register SrcReg = MI.getOperand(1).getReg();
7190 if (SrcReg == AArch64::SP && DstReg.isVirtual()) {
7191 MF.getRegInfo().constrainRegClass(DstReg, &AArch64::GPR64RegClass);
7192 return nullptr;
7193 }
7194 if (DstReg == AArch64::SP && SrcReg.isVirtual()) {
7195 MF.getRegInfo().constrainRegClass(SrcReg, &AArch64::GPR64RegClass);
7196 return nullptr;
7197 }
7198 // Nothing can folded with copy from/to NZCV.
7199 if (SrcReg == AArch64::NZCV || DstReg == AArch64::NZCV)
7200 return nullptr;
7201 }
7202
7203 // Handle the case where a copy is being spilled or filled but the source
7204 // and destination register class don't match. For example:
7205 //
7206 // %0 = COPY %xzr; GPR64common:%0
7207 //
7208 // In this case we can still safely fold away the COPY and generate the
7209 // following spill code:
7210 //
7211 // STRXui %xzr, %stack.0
7212 //
7213 // This also eliminates spilled cross register class COPYs (e.g. between x and
7214 // d regs) of the same size. For example:
7215 //
7216 // %0 = COPY %1; GPR64:%0, FPR64:%1
7217 //
7218 // will be filled as
7219 //
7220 // LDRDui %0, fi<#0>
7221 //
7222 // instead of
7223 //
7224 // LDRXui %Temp, fi<#0>
7225 // %0 = FMOV %Temp
7226 //
7227 if (MI.isCopy() && Ops.size() == 1 &&
7228 // Make sure we're only folding the explicit COPY defs/uses.
7229 (Ops[0] == 0 || Ops[0] == 1)) {
7230 bool IsSpill = Ops[0] == 0;
7231 bool IsFill = !IsSpill;
7233 const MachineRegisterInfo &MRI = MF.getRegInfo();
7234 MachineBasicBlock &MBB = *MI.getParent();
7235 const MachineOperand &DstMO = MI.getOperand(0);
7236 const MachineOperand &SrcMO = MI.getOperand(1);
7237 Register DstReg = DstMO.getReg();
7238 Register SrcReg = SrcMO.getReg();
7239 // This is slightly expensive to compute for physical regs since
7240 // getMinimalPhysRegClass is slow.
7241 auto getRegClass = [&](unsigned Reg) {
7242 return Register::isVirtualRegister(Reg) ? MRI.getRegClass(Reg)
7243 : TRI.getMinimalPhysRegClass(Reg);
7244 };
7245
7246 if (DstMO.getSubReg() == 0 && SrcMO.getSubReg() == 0) {
7247 assert(TRI.getRegSizeInBits(*getRegClass(DstReg)) ==
7248 TRI.getRegSizeInBits(*getRegClass(SrcReg)) &&
7249 "Mismatched register size in non subreg COPY");
7250 if (IsSpill)
7251 storeRegToStackSlot(MBB, InsertPt, SrcReg, SrcMO.isKill(), FrameIndex,
7252 getRegClass(SrcReg), Register());
7253 else
7254 loadRegFromStackSlot(MBB, InsertPt, DstReg, FrameIndex,
7255 getRegClass(DstReg), Register());
7256 return &*--InsertPt;
7257 }
7258
7259 // Handle cases like spilling def of:
7260 //
7261 // %0:sub_32<def,read-undef> = COPY %wzr; GPR64common:%0
7262 //
7263 // where the physical register source can be widened and stored to the full
7264 // virtual reg destination stack slot, in this case producing:
7265 //
7266 // STRXui %xzr, %stack.0
7267 //
7268 if (IsSpill && DstMO.isUndef() && SrcReg == AArch64::WZR &&
7269 TRI.getRegSizeInBits(*getRegClass(DstReg)) == 64) {
7270 assert(SrcMO.getSubReg() == 0 &&
7271 "Unexpected subreg on physical register");
7272 storeRegToStackSlot(MBB, InsertPt, AArch64::XZR, SrcMO.isKill(),
7273 FrameIndex, &AArch64::GPR64RegClass, Register());
7274 return &*--InsertPt;
7275 }
7276
7277 // Handle cases like filling use of:
7278 //
7279 // %0:sub_32<def,read-undef> = COPY %1; GPR64:%0, GPR32:%1
7280 //
7281 // where we can load the full virtual reg source stack slot, into the subreg
7282 // destination, in this case producing:
7283 //
7284 // LDRWui %0:sub_32<def,read-undef>, %stack.0
7285 //
7286 if (IsFill && SrcMO.getSubReg() == 0 && DstMO.isUndef()) {
7287 const TargetRegisterClass *FillRC = nullptr;
7288 switch (DstMO.getSubReg()) {
7289 default:
7290 break;
7291 case AArch64::sub_32:
7292 if (AArch64::GPR64RegClass.hasSubClassEq(getRegClass(DstReg)))
7293 FillRC = &AArch64::GPR32RegClass;
7294 break;
7295 case AArch64::ssub:
7296 FillRC = &AArch64::FPR32RegClass;
7297 break;
7298 case AArch64::dsub:
7299 FillRC = &AArch64::FPR64RegClass;
7300 break;
7301 }
7302
7303 if (FillRC) {
7304 assert(TRI.getRegSizeInBits(*getRegClass(SrcReg)) ==
7305 TRI.getRegSizeInBits(*FillRC) &&
7306 "Mismatched regclass size on folded subreg COPY");
7307 loadRegFromStackSlot(MBB, InsertPt, DstReg, FrameIndex, FillRC,
7308 Register());
7309 MachineInstr &LoadMI = *--InsertPt;
7310 MachineOperand &LoadDst = LoadMI.getOperand(0);
7311 assert(LoadDst.getSubReg() == 0 && "unexpected subreg on fill load");
7312 LoadDst.setSubReg(DstMO.getSubReg());
7313 LoadDst.setIsUndef();
7314 return &LoadMI;
7315 }
7316 }
7317 }
7318
7319 // Cannot fold.
7320 return nullptr;
7321}
7322
7324 StackOffset &SOffset,
7325 bool *OutUseUnscaledOp,
7326 unsigned *OutUnscaledOp,
7327 int64_t *EmittableOffset) {
7328 // Set output values in case of early exit.
7329 if (EmittableOffset)
7330 *EmittableOffset = 0;
7331 if (OutUseUnscaledOp)
7332 *OutUseUnscaledOp = false;
7333 if (OutUnscaledOp)
7334 *OutUnscaledOp = 0;
7335
7336 // Exit early for structured vector spills/fills as they can't take an
7337 // immediate offset.
7338 switch (MI.getOpcode()) {
7339 default:
7340 break;
7341 case AArch64::LD1Rv1d:
7342 case AArch64::LD1Rv2s:
7343 case AArch64::LD1Rv2d:
7344 case AArch64::LD1Rv4h:
7345 case AArch64::LD1Rv4s:
7346 case AArch64::LD1Rv8b:
7347 case AArch64::LD1Rv8h:
7348 case AArch64::LD1Rv16b:
7349 case AArch64::LD1Twov2d:
7350 case AArch64::LD1Threev2d:
7351 case AArch64::LD1Fourv2d:
7352 case AArch64::LD1Twov1d:
7353 case AArch64::LD1Threev1d:
7354 case AArch64::LD1Fourv1d:
7355 case AArch64::ST1Twov2d:
7356 case AArch64::ST1Threev2d:
7357 case AArch64::ST1Fourv2d:
7358 case AArch64::ST1Twov1d:
7359 case AArch64::ST1Threev1d:
7360 case AArch64::ST1Fourv1d:
7361 case AArch64::ST1i8:
7362 case AArch64::ST1i16:
7363 case AArch64::ST1i32:
7364 case AArch64::ST1i64:
7365 case AArch64::IRG:
7366 case AArch64::IRGstack:
7367 case AArch64::STGloop:
7368 case AArch64::STZGloop:
7370 }
7371
7372 // Get the min/max offset and the scale.
7373 TypeSize ScaleValue(0U, false), Width(0U, false);
7374 int64_t MinOff, MaxOff;
7375 if (!AArch64InstrInfo::getMemOpInfo(MI.getOpcode(), ScaleValue, Width, MinOff,
7376 MaxOff))
7377 llvm_unreachable("unhandled opcode in isAArch64FrameOffsetLegal");
7378
7379 // Construct the complete offset.
7380 bool IsMulVL = ScaleValue.isScalable();
7381 unsigned Scale = ScaleValue.getKnownMinValue();
7382 int64_t Offset = IsMulVL ? SOffset.getScalable() : SOffset.getFixed();
7383
7384 const MachineOperand &ImmOpnd =
7385 MI.getOperand(AArch64InstrInfo::getLoadStoreImmIdx(MI.getOpcode()));
7386 Offset += ImmOpnd.getImm() * Scale;
7387
7388 // If the offset doesn't match the scale, we rewrite the instruction to
7389 // use the unscaled instruction instead. Likewise, if we have a negative
7390 // offset and there is an unscaled op to use.
7391 std::optional<unsigned> UnscaledOp =
7393 bool useUnscaledOp = UnscaledOp && (Offset % Scale || Offset < 0);
7394 if (useUnscaledOp &&
7395 !AArch64InstrInfo::getMemOpInfo(*UnscaledOp, ScaleValue, Width, MinOff,
7396 MaxOff))
7397 llvm_unreachable("unhandled opcode in isAArch64FrameOffsetLegal");
7398
7399 Scale = ScaleValue.getKnownMinValue();
7400 assert(IsMulVL == ScaleValue.isScalable() &&
7401 "Unscaled opcode has different value for scalable");
7402
7403 int64_t Remainder = Offset % Scale;
7404 assert(!(Remainder && useUnscaledOp) &&
7405 "Cannot have remainder when using unscaled op");
7406
7407 assert(MinOff < MaxOff && "Unexpected Min/Max offsets");
7408 int64_t NewOffset = Offset / Scale;
7409 if (MinOff <= NewOffset && NewOffset <= MaxOff)
7410 Offset = Remainder;
7411 else {
7412 // Try to minimise the number of instructions required to materialise the
7413 // offset calculation. Specifically, for fixed offsets, if masking out the
7414 // low 12 bits leaves a legal add immediate, we can realise the offset
7415 // calculation with a single add instruction. Whenever this is possible,
7416 // prefer this split.
7417 int64_t HighPart = Offset & ~0xFFF;
7418 int64_t LowPart = Offset & 0xFFF;
7419 int64_t LowScaled = LowPart / Scale;
7420 if (!IsMulVL && NewOffset >= 0 && LowPart % Scale == 0 &&
7421 MinOff <= LowScaled && LowScaled <= MaxOff &&
7423 NewOffset = LowScaled;
7424 Offset = HighPart;
7425 } else {
7426 // Default to a greedy split: take the memop immediate to be maximum /
7427 // minimum expressible offset and materialise the remainder.
7428 NewOffset = NewOffset < 0 ? MinOff : MaxOff;
7429 Offset = Offset - (NewOffset * Scale);
7430 }
7431 }
7432
7433 if (EmittableOffset)
7434 *EmittableOffset = NewOffset;
7435 if (OutUseUnscaledOp)
7436 *OutUseUnscaledOp = useUnscaledOp;
7437 if (OutUnscaledOp && UnscaledOp)
7438 *OutUnscaledOp = *UnscaledOp;
7439
7440 if (IsMulVL)
7441 SOffset = StackOffset::get(SOffset.getFixed(), Offset);
7442 else
7443 SOffset = StackOffset::get(Offset, SOffset.getScalable());
7445 (SOffset ? 0 : AArch64FrameOffsetIsLegal);
7446}
7447
7449 unsigned FrameReg, StackOffset &Offset,
7450 const AArch64InstrInfo *TII) {
7451 unsigned Opcode = MI.getOpcode();
7452 unsigned ImmIdx = FrameRegIdx + 1;
7453
7454 if (Opcode == AArch64::ADDSXri || Opcode == AArch64::ADDXri) {
7455 Offset += StackOffset::getFixed(MI.getOperand(ImmIdx).getImm());
7456 emitFrameOffset(*MI.getParent(), MI, MI.getDebugLoc(),
7457 MI.getOperand(0).getReg(), FrameReg, Offset, TII,
7458 MachineInstr::NoFlags, (Opcode == AArch64::ADDSXri));
7459 MI.eraseFromParent();
7460 Offset = StackOffset();
7461 return true;
7462 }
7463
7464 int64_t NewOffset;
7465 unsigned UnscaledOp;
7466 bool UseUnscaledOp;
7467 int Status = isAArch64FrameOffsetLegal(MI, Offset, &UseUnscaledOp,
7468 &UnscaledOp, &NewOffset);
7471 // Replace the FrameIndex with FrameReg.
7472 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
7473 if (UseUnscaledOp)
7474 MI.setDesc(TII->get(UnscaledOp));
7475
7476 MI.getOperand(ImmIdx).ChangeToImmediate(NewOffset);
7477 return !Offset;
7478 }
7479
7480 return false;
7481}
7482
7488
7489MCInst AArch64InstrInfo::getNop() const { return MCInstBuilder(AArch64::NOP); }
7490
7491// AArch64 supports MachineCombiner.
7492bool AArch64InstrInfo::useMachineCombiner() const { return true; }
7493
7494// True when Opc sets flag
7495static bool isCombineInstrSettingFlag(unsigned Opc) {
7496 switch (Opc) {
7497 case AArch64::ADDSWrr:
7498 case AArch64::ADDSWri:
7499 case AArch64::ADDSXrr:
7500 case AArch64::ADDSXri:
7501 case AArch64::SUBSWrr:
7502 case AArch64::SUBSXrr:
7503 // Note: MSUB Wd,Wn,Wm,Wi -> Wd = Wi - WnxWm, not Wd=WnxWm - Wi.
7504 case AArch64::SUBSWri:
7505 case AArch64::SUBSXri:
7506 return true;
7507 default:
7508 break;
7509 }
7510 return false;
7511}
7512
7513// 32b Opcodes that can be combined with a MUL
7514static bool isCombineInstrCandidate32(unsigned Opc) {
7515 switch (Opc) {
7516 case AArch64::ADDWrr:
7517 case AArch64::ADDWri:
7518 case AArch64::ADDWrs:
7519 case AArch64::SUBWrr:
7520 case AArch64::ADDSWrr:
7521 case AArch64::ADDSWri:
7522 case AArch64::SUBSWrr:
7523 // Note: MSUB Wd,Wn,Wm,Wi -> Wd = Wi - WnxWm, not Wd=WnxWm - Wi.
7524 case AArch64::SUBWri:
7525 case AArch64::SUBSWri:
7526 return true;
7527 default:
7528 break;
7529 }
7530 return false;
7531}
7532
7533// 64b Opcodes that can be combined with a MUL
7534static bool isCombineInstrCandidate64(unsigned Opc) {
7535 switch (Opc) {
7536 case AArch64::ADDXrr:
7537 case AArch64::ADDXri:
7538 case AArch64::ADDXrs:
7539 case AArch64::SUBXrr:
7540 case AArch64::ADDSXrr:
7541 case AArch64::ADDSXri:
7542 case AArch64::SUBSXrr:
7543 // Note: MSUB Wd,Wn,Wm,Wi -> Wd = Wi - WnxWm, not Wd=WnxWm - Wi.
7544 case AArch64::SUBXri:
7545 case AArch64::SUBSXri:
7546 case AArch64::ADDv8i8:
7547 case AArch64::ADDv16i8:
7548 case AArch64::ADDv4i16:
7549 case AArch64::ADDv8i16:
7550 case AArch64::ADDv2i32:
7551 case AArch64::ADDv4i32:
7552 case AArch64::SUBv8i8:
7553 case AArch64::SUBv16i8:
7554 case AArch64::SUBv4i16:
7555 case AArch64::SUBv8i16:
7556 case AArch64::SUBv2i32:
7557 case AArch64::SUBv4i32:
7558 return true;
7559 default:
7560 break;
7561 }
7562 return false;
7563}
7564
7565// FP Opcodes that can be combined with a FMUL.
7566static bool isCombineInstrCandidateFP(const MachineInstr &Inst) {
7567 switch (Inst.getOpcode()) {
7568 default:
7569 break;
7570 case AArch64::FADDHrr:
7571 case AArch64::FADDSrr:
7572 case AArch64::FADDDrr:
7573 case AArch64::FADDv4f16:
7574 case AArch64::FADDv8f16:
7575 case AArch64::FADDv2f32:
7576 case AArch64::FADDv2f64:
7577 case AArch64::FADDv4f32:
7578 case AArch64::FSUBHrr:
7579 case AArch64::FSUBSrr:
7580 case AArch64::FSUBDrr:
7581 case AArch64::FSUBv4f16:
7582 case AArch64::FSUBv8f16:
7583 case AArch64::FSUBv2f32:
7584 case AArch64::FSUBv2f64:
7585 case AArch64::FSUBv4f32:
7586 // We can fuse FADD/FSUB with FMUL, if FADD/FSUB has the contract fast-math
7587 // flag.
7588 return Inst.getFlag(MachineInstr::FmContract);
7589 }
7590 return false;
7591}
7592
7593// Opcodes that can be combined with a MUL
7597
7598//
7599// Utility routine that checks if \param MO is defined by an
7600// \param CombineOpc instruction in the basic block \param MBB
7602 unsigned CombineOpc, unsigned ZeroReg = 0,
7603 bool CheckZeroReg = false) {
7604 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
7605 MachineInstr *MI = nullptr;
7606
7607 if (MO.isReg() && MO.getReg().isVirtual())
7608 MI = MRI.getUniqueVRegDef(MO.getReg());
7609 // And it needs to be in the trace (otherwise, it won't have a depth).
7610 if (!MI || MI->getParent() != &MBB || MI->getOpcode() != CombineOpc)
7611 return false;
7612 // Must only used by the user we combine with.
7613 if (!MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()))
7614 return false;
7615
7616 if (CheckZeroReg) {
7617 assert(MI->getNumOperands() >= 4 && MI->getOperand(0).isReg() &&
7618 MI->getOperand(1).isReg() && MI->getOperand(2).isReg() &&
7619 MI->getOperand(3).isReg() && "MAdd/MSub must have a least 4 regs");
7620 // The third input reg must be zero.
7621 if (MI->getOperand(3).getReg() != ZeroReg)
7622 return false;
7623 }
7624
7625 if (isCombineInstrSettingFlag(CombineOpc) &&
7626 MI->findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr, true) == -1)
7627 return false;
7628
7629 return true;
7630}
7631
7632//
7633// Is \param MO defined by an integer multiply and can be combined?
7635 unsigned MulOpc, unsigned ZeroReg) {
7636 return canCombine(MBB, MO, MulOpc, ZeroReg, true);
7637}
7638
7639//
7640// Is \param MO defined by a floating-point multiply and can be combined?
7642 unsigned MulOpc) {
7643 return canCombine(MBB, MO, MulOpc);
7644}
7645
7646// TODO: There are many more machine instruction opcodes to match:
7647// 1. Other data types (integer, vectors)
7648// 2. Other math / logic operations (xor, or)
7649// 3. Other forms of the same operation (intrinsics and other variants)
7650bool AArch64InstrInfo::isAssociativeAndCommutative(const MachineInstr &Inst,
7651 bool Invert) const {
7652 if (Invert)
7653 return false;
7654 switch (Inst.getOpcode()) {
7655 // == Floating-point types ==
7656 // -- Floating-point instructions --
7657 case AArch64::FADDHrr:
7658 case AArch64::FADDSrr:
7659 case AArch64::FADDDrr:
7660 case AArch64::FMULHrr:
7661 case AArch64::FMULSrr:
7662 case AArch64::FMULDrr:
7663 case AArch64::FMULX16:
7664 case AArch64::FMULX32:
7665 case AArch64::FMULX64:
7666 // -- Advanced SIMD instructions --
7667 case AArch64::FADDv4f16:
7668 case AArch64::FADDv8f16:
7669 case AArch64::FADDv2f32:
7670 case AArch64::FADDv4f32:
7671 case AArch64::FADDv2f64:
7672 case AArch64::FMULv4f16:
7673 case AArch64::FMULv8f16:
7674 case AArch64::FMULv2f32:
7675 case AArch64::FMULv4f32:
7676 case AArch64::FMULv2f64:
7677 case AArch64::FMULXv4f16:
7678 case AArch64::FMULXv8f16:
7679 case AArch64::FMULXv2f32:
7680 case AArch64::FMULXv4f32:
7681 case AArch64::FMULXv2f64:
7682 // -- SVE instructions --
7683 // Opcodes FMULX_ZZZ_? don't exist because there is no unpredicated FMULX
7684 // in the SVE instruction set (though there are predicated ones).
7685 case AArch64::FADD_ZZZ_H:
7686 case AArch64::FADD_ZZZ_S:
7687 case AArch64::FADD_ZZZ_D:
7688 case AArch64::FMUL_ZZZ_H:
7689 case AArch64::FMUL_ZZZ_S:
7690 case AArch64::FMUL_ZZZ_D:
7693
7694 // == Integer types ==
7695 // -- Base instructions --
7696 // Opcodes MULWrr and MULXrr don't exist because
7697 // `MUL <Wd>, <Wn>, <Wm>` and `MUL <Xd>, <Xn>, <Xm>` are aliases of
7698 // `MADD <Wd>, <Wn>, <Wm>, WZR` and `MADD <Xd>, <Xn>, <Xm>, XZR` respectively.
7699 // The machine-combiner does not support three-source-operands machine
7700 // instruction. So we cannot reassociate MULs.
7701 case AArch64::ADDWrr:
7702 case AArch64::ADDXrr:
7703 case AArch64::ANDWrr:
7704 case AArch64::ANDXrr:
7705 case AArch64::ORRWrr:
7706 case AArch64::ORRXrr:
7707 case AArch64::EORWrr:
7708 case AArch64::EORXrr:
7709 case AArch64::EONWrr:
7710 case AArch64::EONXrr:
7711 // -- Advanced SIMD instructions --
7712 // Opcodes MULv1i64 and MULv2i64 don't exist because there is no 64-bit MUL
7713 // in the Advanced SIMD instruction set.
7714 case AArch64::ADDv8i8:
7715 case AArch64::ADDv16i8:
7716 case AArch64::ADDv4i16:
7717 case AArch64::ADDv8i16:
7718 case AArch64::ADDv2i32:
7719 case AArch64::ADDv4i32:
7720 case AArch64::ADDv1i64:
7721 case AArch64::ADDv2i64:
7722 case AArch64::MULv8i8:
7723 case AArch64::MULv16i8:
7724 case AArch64::MULv4i16:
7725 case AArch64::MULv8i16:
7726 case AArch64::MULv2i32:
7727 case AArch64::MULv4i32:
7728 case AArch64::ANDv8i8:
7729 case AArch64::ANDv16i8:
7730 case AArch64::ORRv8i8:
7731 case AArch64::ORRv16i8:
7732 case AArch64::EORv8i8:
7733 case AArch64::EORv16i8:
7734 // -- SVE instructions --
7735 case AArch64::ADD_ZZZ_B:
7736 case AArch64::ADD_ZZZ_H:
7737 case AArch64::ADD_ZZZ_S:
7738 case AArch64::ADD_ZZZ_D:
7739 case AArch64::MUL_ZZZ_B:
7740 case AArch64::MUL_ZZZ_H:
7741 case AArch64::MUL_ZZZ_S:
7742 case AArch64::MUL_ZZZ_D:
7743 case AArch64::AND_ZZZ:
7744 case AArch64::ORR_ZZZ:
7745 case AArch64::EOR_ZZZ:
7746 return true;
7747
7748 default:
7749 return false;
7750 }
7751}
7752
7753/// Find instructions that can be turned into madd.
7755 SmallVectorImpl<unsigned> &Patterns) {
7756 unsigned Opc = Root.getOpcode();
7757 MachineBasicBlock &MBB = *Root.getParent();
7758 bool Found = false;
7759
7761 return false;
7763 int Cmp_NZCV =
7764 Root.findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr, true);
7765 // When NZCV is live bail out.
7766 if (Cmp_NZCV == -1)
7767 return false;
7768 unsigned NewOpc = convertToNonFlagSettingOpc(Root);
7769 // When opcode can't change bail out.
7770 // CHECKME: do we miss any cases for opcode conversion?
7771 if (NewOpc == Opc)
7772 return false;
7773 Opc = NewOpc;
7774 }
7775
7776 auto setFound = [&](int Opcode, int Operand, unsigned ZeroReg,
7777 unsigned Pattern) {
7778 if (canCombineWithMUL(MBB, Root.getOperand(Operand), Opcode, ZeroReg)) {
7779 Patterns.push_back(Pattern);
7780 Found = true;
7781 }
7782 };
7783
7784 const AArch64Subtarget &STI =
7785 MBB.getParent()->getSubtarget<AArch64Subtarget>();
7786 auto setShfFound = [&](int Opcode, unsigned ZeroReg, unsigned Pattern) {
7787 // TODO: Currently its not possible to reject the combine for Apple targets
7788 // based on the scheduling model, because we have gaps in modeling and
7789 // analysis. Once we fill the gaps, remove the subtarget feature and the
7790 // associated check here.
7791 if (STI.hasShiftMaddSlow())
7792 return;
7793
7794 unsigned ShiftImm = Root.getOperand(3).getImm();
7796
7797 if ((ShiftTy != AArch64_AM::LSL && ShiftTy != AArch64_AM::LSR &&
7798 ShiftTy != AArch64_AM::ASR) ||
7799 AArch64_AM::getShiftValue(ShiftImm) == 0)
7800 return;
7801
7802 if (!canCombineWithMUL(MBB, Root.getOperand(1), Opcode, ZeroReg))
7803 return;
7804
7805 Patterns.push_back(Pattern);
7806 Found = true;
7807 };
7808
7809 auto setVFound = [&](int Opcode, int Operand, unsigned Pattern) {
7810 if (canCombine(MBB, Root.getOperand(Operand), Opcode)) {
7811 Patterns.push_back(Pattern);
7812 Found = true;
7813 }
7814 };
7815
7817
7818 switch (Opc) {
7819 default:
7820 break;
7821 case AArch64::ADDWrr:
7822 assert(Root.getOperand(1).isReg() && Root.getOperand(2).isReg() &&
7823 "ADDWrr does not have register operands");
7824 setFound(AArch64::MADDWrrr, 1, AArch64::WZR, MCP::MULADDW_OP1);
7825 setFound(AArch64::MADDWrrr, 2, AArch64::WZR, MCP::MULADDW_OP2);
7826 break;
7827 case AArch64::ADDXrr:
7828 setFound(AArch64::MADDXrrr, 1, AArch64::XZR, MCP::MULADDX_OP1);
7829 setFound(AArch64::MADDXrrr, 2, AArch64::XZR, MCP::MULADDX_OP2);
7830 break;
7831 case AArch64::SUBWrr:
7832 setFound(AArch64::MADDWrrr, 2, AArch64::WZR, MCP::MULSUBW_OP2);
7833 setFound(AArch64::MADDWrrr, 1, AArch64::WZR, MCP::MULSUBW_OP1);
7834 break;
7835 case AArch64::SUBXrr:
7836 setFound(AArch64::MADDXrrr, 2, AArch64::XZR, MCP::MULSUBX_OP2);
7837 setFound(AArch64::MADDXrrr, 1, AArch64::XZR, MCP::MULSUBX_OP1);
7838 break;
7839 case AArch64::ADDWri:
7840 setFound(AArch64::MADDWrrr, 1, AArch64::WZR, MCP::MULADDWI_OP1);
7841 break;
7842 case AArch64::ADDXri:
7843 setFound(AArch64::MADDXrrr, 1, AArch64::XZR, MCP::MULADDXI_OP1);
7844 break;
7845 case AArch64::SUBWri:
7846 setFound(AArch64::MADDWrrr, 1, AArch64::WZR, MCP::MULSUBWI_OP1);
7847 break;
7848 case AArch64::SUBXri:
7849 setFound(AArch64::MADDXrrr, 1, AArch64::XZR, MCP::MULSUBXI_OP1);
7850 break;
7851 case AArch64::ADDWrs:
7852 setShfFound(AArch64::MADDWrrr, AArch64::WZR, MCP::MULADDWS_OP1);
7853 break;
7854 case AArch64::ADDXrs:
7855 setShfFound(AArch64::MADDXrrr, AArch64::XZR, MCP::MULADDXS_OP1);
7856 break;
7857 case AArch64::ADDv8i8:
7858 setVFound(AArch64::MULv8i8, 1, MCP::MULADDv8i8_OP1);
7859 setVFound(AArch64::MULv8i8, 2, MCP::MULADDv8i8_OP2);
7860 break;
7861 case AArch64::ADDv16i8:
7862 setVFound(AArch64::MULv16i8, 1, MCP::MULADDv16i8_OP1);
7863 setVFound(AArch64::MULv16i8, 2, MCP::MULADDv16i8_OP2);
7864 break;
7865 case AArch64::ADDv4i16:
7866 setVFound(AArch64::MULv4i16, 1, MCP::MULADDv4i16_OP1);
7867 setVFound(AArch64::MULv4i16, 2, MCP::MULADDv4i16_OP2);
7868 setVFound(AArch64::MULv4i16_indexed, 1, MCP::MULADDv4i16_indexed_OP1);
7869 setVFound(AArch64::MULv4i16_indexed, 2, MCP::MULADDv4i16_indexed_OP2);
7870 break;
7871 case AArch64::ADDv8i16:
7872 setVFound(AArch64::MULv8i16, 1, MCP::MULADDv8i16_OP1);
7873 setVFound(AArch64::MULv8i16, 2, MCP::MULADDv8i16_OP2);
7874 setVFound(AArch64::MULv8i16_indexed, 1, MCP::MULADDv8i16_indexed_OP1);
7875 setVFound(AArch64::MULv8i16_indexed, 2, MCP::MULADDv8i16_indexed_OP2);
7876 break;
7877 case AArch64::ADDv2i32:
7878 setVFound(AArch64::MULv2i32, 1, MCP::MULADDv2i32_OP1);
7879 setVFound(AArch64::MULv2i32, 2, MCP::MULADDv2i32_OP2);
7880 setVFound(AArch64::MULv2i32_indexed, 1, MCP::MULADDv2i32_indexed_OP1);
7881 setVFound(AArch64::MULv2i32_indexed, 2, MCP::MULADDv2i32_indexed_OP2);
7882 break;
7883 case AArch64::ADDv4i32:
7884 setVFound(AArch64::MULv4i32, 1, MCP::MULADDv4i32_OP1);
7885 setVFound(AArch64::MULv4i32, 2, MCP::MULADDv4i32_OP2);
7886 setVFound(AArch64::MULv4i32_indexed, 1, MCP::MULADDv4i32_indexed_OP1);
7887 setVFound(AArch64::MULv4i32_indexed, 2, MCP::MULADDv4i32_indexed_OP2);
7888 break;
7889 case AArch64::SUBv8i8:
7890 setVFound(AArch64::MULv8i8, 1, MCP::MULSUBv8i8_OP1);
7891 setVFound(AArch64::MULv8i8, 2, MCP::MULSUBv8i8_OP2);
7892 break;
7893 case AArch64::SUBv16i8:
7894 setVFound(AArch64::MULv16i8, 1, MCP::MULSUBv16i8_OP1);
7895 setVFound(AArch64::MULv16i8, 2, MCP::MULSUBv16i8_OP2);
7896 break;
7897 case AArch64::SUBv4i16:
7898 setVFound(AArch64::MULv4i16, 1, MCP::MULSUBv4i16_OP1);
7899 setVFound(AArch64::MULv4i16, 2, MCP::MULSUBv4i16_OP2);
7900 setVFound(AArch64::MULv4i16_indexed, 1, MCP::MULSUBv4i16_indexed_OP1);
7901 setVFound(AArch64::MULv4i16_indexed, 2, MCP::MULSUBv4i16_indexed_OP2);
7902 break;
7903 case AArch64::SUBv8i16:
7904 setVFound(AArch64::MULv8i16, 1, MCP::MULSUBv8i16_OP1);
7905 setVFound(AArch64::MULv8i16, 2, MCP::MULSUBv8i16_OP2);
7906 setVFound(AArch64::MULv8i16_indexed, 1, MCP::MULSUBv8i16_indexed_OP1);
7907 setVFound(AArch64::MULv8i16_indexed, 2, MCP::MULSUBv8i16_indexed_OP2);
7908 break;
7909 case AArch64::SUBv2i32:
7910 setVFound(AArch64::MULv2i32, 1, MCP::MULSUBv2i32_OP1);
7911 setVFound(AArch64::MULv2i32, 2, MCP::MULSUBv2i32_OP2);
7912 setVFound(AArch64::MULv2i32_indexed, 1, MCP::MULSUBv2i32_indexed_OP1);
7913 setVFound(AArch64::MULv2i32_indexed, 2, MCP::MULSUBv2i32_indexed_OP2);
7914 break;
7915 case AArch64::SUBv4i32:
7916 setVFound(AArch64::MULv4i32, 1, MCP::MULSUBv4i32_OP1);
7917 setVFound(AArch64::MULv4i32, 2, MCP::MULSUBv4i32_OP2);
7918 setVFound(AArch64::MULv4i32_indexed, 1, MCP::MULSUBv4i32_indexed_OP1);
7919 setVFound(AArch64::MULv4i32_indexed, 2, MCP::MULSUBv4i32_indexed_OP2);
7920 break;
7921 }
7922 return Found;
7923}
7924
7925bool AArch64InstrInfo::isAccumulationOpcode(unsigned Opcode) const {
7926 switch (Opcode) {
7927 default:
7928 break;
7929 case AArch64::UABALB_ZZZ_D:
7930 case AArch64::UABALB_ZZZ_H:
7931 case AArch64::UABALB_ZZZ_S:
7932 case AArch64::UABALT_ZZZ_D:
7933 case AArch64::UABALT_ZZZ_H:
7934 case AArch64::UABALT_ZZZ_S:
7935 case AArch64::SABALB_ZZZ_D:
7936 case AArch64::SABALB_ZZZ_S:
7937 case AArch64::SABALB_ZZZ_H:
7938 case AArch64::SABALT_ZZZ_D:
7939 case AArch64::SABALT_ZZZ_S:
7940 case AArch64::SABALT_ZZZ_H:
7941 case AArch64::UABALv16i8_v8i16:
7942 case AArch64::UABALv2i32_v2i64:
7943 case AArch64::UABALv4i16_v4i32:
7944 case AArch64::UABALv4i32_v2i64:
7945 case AArch64::UABALv8i16_v4i32:
7946 case AArch64::UABALv8i8_v8i16:
7947 case AArch64::UABAv16i8:
7948 case AArch64::UABAv2i32:
7949 case AArch64::UABAv4i16:
7950 case AArch64::UABAv4i32:
7951 case AArch64::UABAv8i16:
7952 case AArch64::UABAv8i8:
7953 case AArch64::SABALv16i8_v8i16:
7954 case AArch64::SABALv2i32_v2i64:
7955 case AArch64::SABALv4i16_v4i32:
7956 case AArch64::SABALv4i32_v2i64:
7957 case AArch64::SABALv8i16_v4i32:
7958 case AArch64::SABALv8i8_v8i16:
7959 case AArch64::SABAv16i8:
7960 case AArch64::SABAv2i32:
7961 case AArch64::SABAv4i16:
7962 case AArch64::SABAv4i32:
7963 case AArch64::SABAv8i16:
7964 case AArch64::SABAv8i8:
7965 return true;
7966 }
7967
7968 return false;
7969}
7970
7971unsigned AArch64InstrInfo::getAccumulationStartOpcode(
7972 unsigned AccumulationOpcode) const {
7973 switch (AccumulationOpcode) {
7974 default:
7975 llvm_unreachable("Unsupported accumulation Opcode!");
7976 case AArch64::UABALB_ZZZ_D:
7977 return AArch64::UABDLB_ZZZ_D;
7978 case AArch64::UABALB_ZZZ_H:
7979 return AArch64::UABDLB_ZZZ_H;
7980 case AArch64::UABALB_ZZZ_S:
7981 return AArch64::UABDLB_ZZZ_S;
7982 case AArch64::UABALT_ZZZ_D:
7983 return AArch64::UABDLT_ZZZ_D;
7984 case AArch64::UABALT_ZZZ_H:
7985 return AArch64::UABDLT_ZZZ_H;
7986 case AArch64::UABALT_ZZZ_S:
7987 return AArch64::UABDLT_ZZZ_S;
7988 case AArch64::UABALv16i8_v8i16:
7989 return AArch64::UABDLv16i8_v8i16;
7990 case AArch64::UABALv2i32_v2i64:
7991 return AArch64::UABDLv2i32_v2i64;
7992 case AArch64::UABALv4i16_v4i32:
7993 return AArch64::UABDLv4i16_v4i32;
7994 case AArch64::UABALv4i32_v2i64:
7995 return AArch64::UABDLv4i32_v2i64;
7996 case AArch64::UABALv8i16_v4i32:
7997 return AArch64::UABDLv8i16_v4i32;
7998 case AArch64::UABALv8i8_v8i16:
7999 return AArch64::UABDLv8i8_v8i16;
8000 case AArch64::UABAv16i8:
8001 return AArch64::UABDv16i8;
8002 case AArch64::UABAv2i32:
8003 return AArch64::UABDv2i32;
8004 case AArch64::UABAv4i16:
8005 return AArch64::UABDv4i16;
8006 case AArch64::UABAv4i32:
8007 return AArch64::UABDv4i32;
8008 case AArch64::UABAv8i16:
8009 return AArch64::UABDv8i16;
8010 case AArch64::UABAv8i8:
8011 return AArch64::UABDv8i8;
8012 case AArch64::SABALB_ZZZ_D:
8013 return AArch64::SABDLB_ZZZ_D;
8014 case AArch64::SABALB_ZZZ_S:
8015 return AArch64::SABDLB_ZZZ_S;
8016 case AArch64::SABALB_ZZZ_H:
8017 return AArch64::SABDLB_ZZZ_H;
8018 case AArch64::SABALT_ZZZ_D:
8019 return AArch64::SABDLT_ZZZ_D;
8020 case AArch64::SABALT_ZZZ_S:
8021 return AArch64::SABDLT_ZZZ_S;
8022 case AArch64::SABALT_ZZZ_H:
8023 return AArch64::SABDLT_ZZZ_H;
8024 case AArch64::SABALv16i8_v8i16:
8025 return AArch64::SABDLv16i8_v8i16;
8026 case AArch64::SABALv2i32_v2i64:
8027 return AArch64::SABDLv2i32_v2i64;
8028 case AArch64::SABALv4i16_v4i32:
8029 return AArch64::SABDLv4i16_v4i32;
8030 case AArch64::SABALv4i32_v2i64:
8031 return AArch64::SABDLv4i32_v2i64;
8032 case AArch64::SABALv8i16_v4i32:
8033 return AArch64::SABDLv8i16_v4i32;
8034 case AArch64::SABALv8i8_v8i16:
8035 return AArch64::SABDLv8i8_v8i16;
8036 case AArch64::SABAv16i8:
8037 return AArch64::SABDv16i8;
8038 case AArch64::SABAv2i32:
8039 return AArch64::SABDv2i32;
8040 case AArch64::SABAv4i16:
8041 return AArch64::SABDv4i16;
8042 case AArch64::SABAv4i32:
8043 return AArch64::SABDv4i32;
8044 case AArch64::SABAv8i16:
8045 return AArch64::SABDv8i16;
8046 case AArch64::SABAv8i8:
8047 return AArch64::SABDv8i8;
8048 }
8049}
8050
8051/// Floating-Point Support
8052
8053/// Find instructions that can be turned into madd.
8055 SmallVectorImpl<unsigned> &Patterns) {
8056
8057 if (!isCombineInstrCandidateFP(Root))
8058 return false;
8059
8060 MachineBasicBlock &MBB = *Root.getParent();
8061 bool Found = false;
8062
8063 auto Match = [&](int Opcode, int Operand, unsigned Pattern) -> bool {
8064 if (canCombineWithFMUL(MBB, Root.getOperand(Operand), Opcode)) {
8065 Patterns.push_back(Pattern);
8066 return true;
8067 }
8068 return false;
8069 };
8070
8072
8073 switch (Root.getOpcode()) {
8074 default:
8075 assert(false && "Unsupported FP instruction in combiner\n");
8076 break;
8077 case AArch64::FADDHrr:
8078 assert(Root.getOperand(1).isReg() && Root.getOperand(2).isReg() &&
8079 "FADDHrr does not have register operands");
8080
8081 Found = Match(AArch64::FMULHrr, 1, MCP::FMULADDH_OP1);
8082 Found |= Match(AArch64::FMULHrr, 2, MCP::FMULADDH_OP2);
8083 break;
8084 case AArch64::FADDSrr:
8085 assert(Root.getOperand(1).isReg() && Root.getOperand(2).isReg() &&
8086 "FADDSrr does not have register operands");
8087
8088 Found |= Match(AArch64::FMULSrr, 1, MCP::FMULADDS_OP1) ||
8089 Match(AArch64::FMULv1i32_indexed, 1, MCP::FMLAv1i32_indexed_OP1);
8090
8091 Found |= Match(AArch64::FMULSrr, 2, MCP::FMULADDS_OP2) ||
8092 Match(AArch64::FMULv1i32_indexed, 2, MCP::FMLAv1i32_indexed_OP2);
8093 break;
8094 case AArch64::FADDDrr:
8095 Found |= Match(AArch64::FMULDrr, 1, MCP::FMULADDD_OP1) ||
8096 Match(AArch64::FMULv1i64_indexed, 1, MCP::FMLAv1i64_indexed_OP1);
8097
8098 Found |= Match(AArch64::FMULDrr, 2, MCP::FMULADDD_OP2) ||
8099 Match(AArch64::FMULv1i64_indexed, 2, MCP::FMLAv1i64_indexed_OP2);
8100 break;
8101 case AArch64::FADDv4f16:
8102 Found |= Match(AArch64::FMULv4i16_indexed, 1, MCP::FMLAv4i16_indexed_OP1) ||
8103 Match(AArch64::FMULv4f16, 1, MCP::FMLAv4f16_OP1);
8104
8105 Found |= Match(AArch64::FMULv4i16_indexed, 2, MCP::FMLAv4i16_indexed_OP2) ||
8106 Match(AArch64::FMULv4f16, 2, MCP::FMLAv4f16_OP2);
8107 break;
8108 case AArch64::FADDv8f16:
8109 Found |= Match(AArch64::FMULv8i16_indexed, 1, MCP::FMLAv8i16_indexed_OP1) ||
8110 Match(AArch64::FMULv8f16, 1, MCP::FMLAv8f16_OP1);
8111
8112 Found |= Match(AArch64::FMULv8i16_indexed, 2, MCP::FMLAv8i16_indexed_OP2) ||
8113 Match(AArch64::FMULv8f16, 2, MCP::FMLAv8f16_OP2);
8114 break;
8115 case AArch64::FADDv2f32:
8116 Found |= Match(AArch64::FMULv2i32_indexed, 1, MCP::FMLAv2i32_indexed_OP1) ||
8117 Match(AArch64::FMULv2f32, 1, MCP::FMLAv2f32_OP1);
8118
8119 Found |= Match(AArch64::FMULv2i32_indexed, 2, MCP::FMLAv2i32_indexed_OP2) ||
8120 Match(AArch64::FMULv2f32, 2, MCP::FMLAv2f32_OP2);
8121 break;
8122 case AArch64::FADDv2f64:
8123 Found |= Match(AArch64::FMULv2i64_indexed, 1, MCP::FMLAv2i64_indexed_OP1) ||
8124 Match(AArch64::FMULv2f64, 1, MCP::FMLAv2f64_OP1);
8125
8126 Found |= Match(AArch64::FMULv2i64_indexed, 2, MCP::FMLAv2i64_indexed_OP2) ||
8127 Match(AArch64::FMULv2f64, 2, MCP::FMLAv2f64_OP2);
8128 break;
8129 case AArch64::FADDv4f32:
8130 Found |= Match(AArch64::FMULv4i32_indexed, 1, MCP::FMLAv4i32_indexed_OP1) ||
8131 Match(AArch64::FMULv4f32, 1, MCP::FMLAv4f32_OP1);
8132
8133 Found |= Match(AArch64::FMULv4i32_indexed, 2, MCP::FMLAv4i32_indexed_OP2) ||
8134 Match(AArch64::FMULv4f32, 2, MCP::FMLAv4f32_OP2);
8135 break;
8136 case AArch64::FSUBHrr:
8137 Found = Match(AArch64::FMULHrr, 1, MCP::FMULSUBH_OP1);
8138 Found |= Match(AArch64::FMULHrr, 2, MCP::FMULSUBH_OP2);
8139 Found |= Match(AArch64::FNMULHrr, 1, MCP::FNMULSUBH_OP1);
8140 break;
8141 case AArch64::FSUBSrr:
8142 Found = Match(AArch64::FMULSrr, 1, MCP::FMULSUBS_OP1);
8143
8144 Found |= Match(AArch64::FMULSrr, 2, MCP::FMULSUBS_OP2) ||
8145 Match(AArch64::FMULv1i32_indexed, 2, MCP::FMLSv1i32_indexed_OP2);
8146
8147 Found |= Match(AArch64::FNMULSrr, 1, MCP::FNMULSUBS_OP1);
8148 break;
8149 case AArch64::FSUBDrr:
8150 Found = Match(AArch64::FMULDrr, 1, MCP::FMULSUBD_OP1);
8151
8152 Found |= Match(AArch64::FMULDrr, 2, MCP::FMULSUBD_OP2) ||
8153 Match(AArch64::FMULv1i64_indexed, 2, MCP::FMLSv1i64_indexed_OP2);
8154
8155 Found |= Match(AArch64::FNMULDrr, 1, MCP::FNMULSUBD_OP1);
8156 break;
8157 case AArch64::FSUBv4f16:
8158 Found |= Match(AArch64::FMULv4i16_indexed, 2, MCP::FMLSv4i16_indexed_OP2) ||
8159 Match(AArch64::FMULv4f16, 2, MCP::FMLSv4f16_OP2);
8160
8161 Found |= Match(AArch64::FMULv4i16_indexed, 1, MCP::FMLSv4i16_indexed_OP1) ||
8162 Match(AArch64::FMULv4f16, 1, MCP::FMLSv4f16_OP1);
8163 break;
8164 case AArch64::FSUBv8f16:
8165 Found |= Match(AArch64::FMULv8i16_indexed, 2, MCP::FMLSv8i16_indexed_OP2) ||
8166 Match(AArch64::FMULv8f16, 2, MCP::FMLSv8f16_OP2);
8167
8168 Found |= Match(AArch64::FMULv8i16_indexed, 1, MCP::FMLSv8i16_indexed_OP1) ||
8169 Match(AArch64::FMULv8f16, 1, MCP::FMLSv8f16_OP1);
8170 break;
8171 case AArch64::FSUBv2f32:
8172 Found |= Match(AArch64::FMULv2i32_indexed, 2, MCP::FMLSv2i32_indexed_OP2) ||
8173 Match(AArch64::FMULv2f32, 2, MCP::FMLSv2f32_OP2);
8174
8175 Found |= Match(AArch64::FMULv2i32_indexed, 1, MCP::FMLSv2i32_indexed_OP1) ||
8176 Match(AArch64::FMULv2f32, 1, MCP::FMLSv2f32_OP1);
8177 break;
8178 case AArch64::FSUBv2f64:
8179 Found |= Match(AArch64::FMULv2i64_indexed, 2, MCP::FMLSv2i64_indexed_OP2) ||
8180 Match(AArch64::FMULv2f64, 2, MCP::FMLSv2f64_OP2);
8181
8182 Found |= Match(AArch64::FMULv2i64_indexed, 1, MCP::FMLSv2i64_indexed_OP1) ||
8183 Match(AArch64::FMULv2f64, 1, MCP::FMLSv2f64_OP1);
8184 break;
8185 case AArch64::FSUBv4f32:
8186 Found |= Match(AArch64::FMULv4i32_indexed, 2, MCP::FMLSv4i32_indexed_OP2) ||
8187 Match(AArch64::FMULv4f32, 2, MCP::FMLSv4f32_OP2);
8188
8189 Found |= Match(AArch64::FMULv4i32_indexed, 1, MCP::FMLSv4i32_indexed_OP1) ||
8190 Match(AArch64::FMULv4f32, 1, MCP::FMLSv4f32_OP1);
8191 break;
8192 }
8193 return Found;
8194}
8195
8197 SmallVectorImpl<unsigned> &Patterns) {
8198 MachineBasicBlock &MBB = *Root.getParent();
8199 bool Found = false;
8200
8201 auto Match = [&](unsigned Opcode, int Operand, unsigned Pattern) -> bool {
8202 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
8203 MachineOperand &MO = Root.getOperand(Operand);
8204 MachineInstr *MI = nullptr;
8205 if (MO.isReg() && MO.getReg().isVirtual())
8206 MI = MRI.getUniqueVRegDef(MO.getReg());
8207 // Ignore No-op COPYs in FMUL(COPY(DUP(..)))
8208 if (MI && MI->getOpcode() == TargetOpcode::COPY &&
8209 MI->getOperand(1).getReg().isVirtual())
8210 MI = MRI.getUniqueVRegDef(MI->getOperand(1).getReg());
8211 if (MI && MI->getOpcode() == Opcode) {
8212 Patterns.push_back(Pattern);
8213 return true;
8214 }
8215 return false;
8216 };
8217
8219
8220 switch (Root.getOpcode()) {
8221 default:
8222 return false;
8223 case AArch64::FMULv2f32:
8224 Found = Match(AArch64::DUPv2i32lane, 1, MCP::FMULv2i32_indexed_OP1);
8225 Found |= Match(AArch64::DUPv2i32lane, 2, MCP::FMULv2i32_indexed_OP2);
8226 break;
8227 case AArch64::FMULv2f64:
8228 Found = Match(AArch64::DUPv2i64lane, 1, MCP::FMULv2i64_indexed_OP1);
8229 Found |= Match(AArch64::DUPv2i64lane, 2, MCP::FMULv2i64_indexed_OP2);
8230 break;
8231 case AArch64::FMULv4f16:
8232 Found = Match(AArch64::DUPv4i16lane, 1, MCP::FMULv4i16_indexed_OP1);
8233 Found |= Match(AArch64::DUPv4i16lane, 2, MCP::FMULv4i16_indexed_OP2);
8234 break;
8235 case AArch64::FMULv4f32:
8236 Found = Match(AArch64::DUPv4i32lane, 1, MCP::FMULv4i32_indexed_OP1);
8237 Found |= Match(AArch64::DUPv4i32lane, 2, MCP::FMULv4i32_indexed_OP2);
8238 break;
8239 case AArch64::FMULv8f16:
8240 Found = Match(AArch64::DUPv8i16lane, 1, MCP::FMULv8i16_indexed_OP1);
8241 Found |= Match(AArch64::DUPv8i16lane, 2, MCP::FMULv8i16_indexed_OP2);
8242 break;
8243 }
8244
8245 return Found;
8246}
8247
8249 SmallVectorImpl<unsigned> &Patterns) {
8250 unsigned Opc = Root.getOpcode();
8251 MachineBasicBlock &MBB = *Root.getParent();
8252 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
8253
8254 auto Match = [&](unsigned Opcode, unsigned Pattern) -> bool {
8255 MachineOperand &MO = Root.getOperand(1);
8256 MachineInstr *MI = MRI.getUniqueVRegDef(MO.getReg());
8257 if (MI != nullptr && (MI->getOpcode() == Opcode) &&
8258 MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()) &&
8262 MI->getFlag(MachineInstr::MIFlag::FmNsz)) {
8263 Patterns.push_back(Pattern);
8264 return true;
8265 }
8266 return false;
8267 };
8268
8269 switch (Opc) {
8270 default:
8271 break;
8272 case AArch64::FNEGDr:
8273 return Match(AArch64::FMADDDrrr, AArch64MachineCombinerPattern::FNMADD);
8274 case AArch64::FNEGSr:
8275 return Match(AArch64::FMADDSrrr, AArch64MachineCombinerPattern::FNMADD);
8276 }
8277
8278 return false;
8279}
8280
8281/// Return true when a code sequence can improve throughput. It
8282/// should be called only for instructions in loops.
8283/// \param Pattern - combiner pattern
8285 switch (Pattern) {
8286 default:
8287 break;
8393 return true;
8394 } // end switch (Pattern)
8395 return false;
8396}
8397
8398/// Find other MI combine patterns.
8400 SmallVectorImpl<unsigned> &Patterns) {
8401 // A - (B + C) ==> (A - B) - C or (A - C) - B
8402 unsigned Opc = Root.getOpcode();
8403 MachineBasicBlock &MBB = *Root.getParent();
8404
8405 switch (Opc) {
8406 case AArch64::SUBWrr:
8407 case AArch64::SUBSWrr:
8408 case AArch64::SUBXrr:
8409 case AArch64::SUBSXrr:
8410 // Found candidate root.
8411 break;
8412 default:
8413 return false;
8414 }
8415
8417 Root.findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr, true) ==
8418 -1)
8419 return false;
8420
8421 if (canCombine(MBB, Root.getOperand(2), AArch64::ADDWrr) ||
8422 canCombine(MBB, Root.getOperand(2), AArch64::ADDSWrr) ||
8423 canCombine(MBB, Root.getOperand(2), AArch64::ADDXrr) ||
8424 canCombine(MBB, Root.getOperand(2), AArch64::ADDSXrr)) {
8427 return true;
8428 }
8429
8430 return false;
8431}
8432
8433/// Check if the given instruction forms a gather load pattern that can be
8434/// optimized for better Memory-Level Parallelism (MLP). This function
8435/// identifies chains of NEON lane load instructions that load data from
8436/// different memory addresses into individual lanes of a 128-bit vector
8437/// register, then attempts to split the pattern into parallel loads to break
8438/// the serial dependency between instructions.
8439///
8440/// Pattern Matched:
8441/// Initial scalar load -> SUBREG_TO_REG (lane 0) -> LD1i* (lane 1) ->
8442/// LD1i* (lane 2) -> ... -> LD1i* (lane N-1, Root)
8443///
8444/// Transformed Into:
8445/// Two parallel vector loads using fewer lanes each, followed by ZIP1v2i64
8446/// to combine the results, enabling better memory-level parallelism.
8447///
8448/// Supported Element Types:
8449/// - 32-bit elements (LD1i32, 4 lanes total)
8450/// - 16-bit elements (LD1i16, 8 lanes total)
8451/// - 8-bit elements (LD1i8, 16 lanes total)
8453 SmallVectorImpl<unsigned> &Patterns,
8454 unsigned LoadLaneOpCode, unsigned NumLanes) {
8455 const MachineFunction *MF = Root.getMF();
8456
8457 // Early exit if optimizing for size.
8458 if (MF->getFunction().hasMinSize())
8459 return false;
8460
8461 const MachineRegisterInfo &MRI = MF->getRegInfo();
8463
8464 // The root of the pattern must load into the last lane of the vector.
8465 if (Root.getOperand(2).getImm() != NumLanes - 1)
8466 return false;
8467
8468 // Check that we have load into all lanes except lane 0.
8469 // For each load we also want to check that:
8470 // 1. It has a single non-debug use (since we will be replacing the virtual
8471 // register)
8472 // 2. That the addressing mode only uses a single pointer operand
8473 auto *CurrInstr = MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
8474 auto Range = llvm::seq<unsigned>(1, NumLanes - 1);
8475 SmallSet<unsigned, 16> RemainingLanes(Range.begin(), Range.end());
8477 while (!RemainingLanes.empty() && CurrInstr &&
8478 CurrInstr->getOpcode() == LoadLaneOpCode &&
8479 MRI.hasOneNonDBGUse(CurrInstr->getOperand(0).getReg()) &&
8480 CurrInstr->getNumOperands() == 4) {
8481 RemainingLanes.erase(CurrInstr->getOperand(2).getImm());
8482 LoadInstrs.push_back(CurrInstr);
8483 CurrInstr = MRI.getUniqueVRegDef(CurrInstr->getOperand(1).getReg());
8484 }
8485
8486 // Check that we have found a match for lanes N-1.. 1.
8487 if (!RemainingLanes.empty())
8488 return false;
8489
8490 // Match the SUBREG_TO_REG sequence.
8491 if (CurrInstr->getOpcode() != TargetOpcode::SUBREG_TO_REG)
8492 return false;
8493
8494 // Verify that the subreg to reg loads an integer into the first lane.
8495 auto Lane0LoadReg = CurrInstr->getOperand(1).getReg();
8496 unsigned SingleLaneSizeInBits = 128 / NumLanes;
8497 if (TRI->getRegSizeInBits(Lane0LoadReg, MRI) != SingleLaneSizeInBits)
8498 return false;
8499
8500 // Verify that it also has a single non debug use.
8501 if (!MRI.hasOneNonDBGUse(Lane0LoadReg))
8502 return false;
8503
8504 LoadInstrs.push_back(MRI.getUniqueVRegDef(Lane0LoadReg));
8505
8506 // If there is any chance of aliasing, do not apply the pattern.
8507 // Walk backward through the MBB starting from Root.
8508 // Exit early if we've encountered all load instructions or hit the search
8509 // limit.
8510 auto MBBItr = Root.getIterator();
8511 unsigned RemainingSteps =
8512 MF->getSubtarget<AArch64Subtarget>().getCLOpts().search_limit;
8513 SmallPtrSet<const MachineInstr *, 16> RemainingLoadInstrs;
8514 RemainingLoadInstrs.insert(LoadInstrs.begin(), LoadInstrs.end());
8515 const MachineBasicBlock *MBB = Root.getParent();
8516
8517 for (; MBBItr != MBB->begin() && RemainingSteps > 0 &&
8518 !RemainingLoadInstrs.empty();
8519 --MBBItr, --RemainingSteps) {
8520 const MachineInstr &CurrInstr = *MBBItr;
8521
8522 // Remove this instruction from remaining loads if it's one we're tracking.
8523 RemainingLoadInstrs.erase(&CurrInstr);
8524
8525 // Check for potential aliasing with any of the load instructions to
8526 // optimize.
8527 if (CurrInstr.isLoadFoldBarrier())
8528 return false;
8529 }
8530
8531 // If we hit the search limit without finding all load instructions,
8532 // don't match the pattern.
8533 if (RemainingSteps == 0 && !RemainingLoadInstrs.empty())
8534 return false;
8535
8536 switch (NumLanes) {
8537 case 4:
8539 break;
8540 case 8:
8542 break;
8543 case 16:
8545 break;
8546 default:
8547 llvm_unreachable("Got bad number of lanes for gather pattern.");
8548 }
8549
8550 return true;
8551}
8552
8553/// Search for patterns of LD instructions we can optimize.
8555 SmallVectorImpl<unsigned> &Patterns) {
8556
8557 // The pattern searches for loads into single lanes.
8558 switch (Root.getOpcode()) {
8559 case AArch64::LD1i32:
8560 return getGatherLanePattern(Root, Patterns, Root.getOpcode(), 4);
8561 case AArch64::LD1i16:
8562 return getGatherLanePattern(Root, Patterns, Root.getOpcode(), 8);
8563 case AArch64::LD1i8:
8564 return getGatherLanePattern(Root, Patterns, Root.getOpcode(), 16);
8565 default:
8566 return false;
8567 }
8568}
8569
8570/// Generate optimized instruction sequence for gather load patterns to improve
8571/// Memory-Level Parallelism (MLP). This function transforms a chain of
8572/// sequential NEON lane loads into parallel vector loads that can execute
8573/// concurrently.
8574static void
8578 DenseMap<Register, unsigned> &InstrIdxForVirtReg,
8579 unsigned Pattern, unsigned NumLanes) {
8580 MachineFunction &MF = *Root.getParent()->getParent();
8583
8584 // Gather the initial load instructions to build the pattern.
8585 SmallVector<MachineInstr *, 16> LoadToLaneInstrs;
8586 MachineInstr *CurrInstr = &Root;
8587 for (unsigned i = 0; i < NumLanes - 1; ++i) {
8588 LoadToLaneInstrs.push_back(CurrInstr);
8589 CurrInstr = MRI.getUniqueVRegDef(CurrInstr->getOperand(1).getReg());
8590 }
8591
8592 // Sort the load instructions according to the lane.
8593 llvm::sort(LoadToLaneInstrs,
8594 [](const MachineInstr *A, const MachineInstr *B) {
8595 return A->getOperand(2).getImm() > B->getOperand(2).getImm();
8596 });
8597
8598 MachineInstr *SubregToReg = CurrInstr;
8599 LoadToLaneInstrs.push_back(
8600 MRI.getUniqueVRegDef(SubregToReg->getOperand(1).getReg()));
8601 auto LoadToLaneInstrsAscending = llvm::reverse(LoadToLaneInstrs);
8602
8603 const TargetRegisterClass *FPR128RegClass =
8604 MRI.getRegClass(Root.getOperand(0).getReg());
8605
8606 // Helper lambda to create a LD1 instruction.
8607 auto CreateLD1Instruction = [&](MachineInstr *OriginalInstr,
8608 Register SrcRegister, unsigned Lane,
8609 Register OffsetRegister) {
8610 auto NewRegister = MRI.createVirtualRegister(FPR128RegClass);
8611 MachineInstrBuilder LoadIndexIntoRegister =
8612 BuildMI(MF, MIMetadata(*OriginalInstr), TII->get(Root.getOpcode()),
8613 NewRegister)
8614 .addReg(SrcRegister)
8615 .addImm(Lane)
8616 .addReg(OffsetRegister)
8617 .setMemRefs(OriginalInstr->memoperands());
8618 InstrIdxForVirtReg.insert(std::make_pair(NewRegister, InsInstrs.size()));
8619 InsInstrs.push_back(LoadIndexIntoRegister);
8620 return NewRegister;
8621 };
8622
8623 // Helper to create load instruction based on the NumLanes in the NEON
8624 // register we are rewriting.
8625 auto CreateLDRInstruction =
8626 [&](unsigned NumLanes, Register DestReg, Register OffsetReg,
8628 unsigned Opcode;
8629 switch (NumLanes) {
8630 case 4:
8631 Opcode = AArch64::LDRSui;
8632 break;
8633 case 8:
8634 Opcode = AArch64::LDRHui;
8635 break;
8636 case 16:
8637 Opcode = AArch64::LDRBui;
8638 break;
8639 default:
8641 "Got unsupported number of lanes in machine-combiner gather pattern");
8642 }
8643 // Immediate offset load
8644 return BuildMI(MF, MIMetadata(Root), TII->get(Opcode), DestReg)
8645 .addReg(OffsetReg)
8646 .addImm(0)
8647 .setMemRefs(MMOs);
8648 };
8649
8650 // Load the remaining lanes into register 0.
8651 auto LanesToLoadToReg0 =
8652 llvm::make_range(LoadToLaneInstrsAscending.begin() + 1,
8653 LoadToLaneInstrsAscending.begin() + NumLanes / 2);
8654 Register PrevReg = SubregToReg->getOperand(0).getReg();
8655 for (auto [Index, LoadInstr] : llvm::enumerate(LanesToLoadToReg0)) {
8656 const MachineOperand &OffsetRegOperand = LoadInstr->getOperand(3);
8657 PrevReg = CreateLD1Instruction(LoadInstr, PrevReg, Index + 1,
8658 OffsetRegOperand.getReg());
8659 DelInstrs.push_back(LoadInstr);
8660 }
8661 Register LastLoadReg0 = PrevReg;
8662
8663 // First load into register 1. Perform an integer load to zero out the upper
8664 // lanes in a single instruction.
8665 MachineInstr *Lane0Load = *LoadToLaneInstrsAscending.begin();
8666 MachineInstr *OriginalSplitLoad =
8667 *std::next(LoadToLaneInstrsAscending.begin(), NumLanes / 2);
8668 Register DestRegForMiddleIndex = MRI.createVirtualRegister(
8669 MRI.getRegClass(Lane0Load->getOperand(0).getReg()));
8670
8671 const MachineOperand &OriginalSplitToLoadOffsetOperand =
8672 OriginalSplitLoad->getOperand(3);
8673 MachineInstrBuilder MiddleIndexLoadInstr =
8674 CreateLDRInstruction(NumLanes, DestRegForMiddleIndex,
8675 OriginalSplitToLoadOffsetOperand.getReg(),
8676 OriginalSplitLoad->memoperands());
8677
8678 InstrIdxForVirtReg.insert(
8679 std::make_pair(DestRegForMiddleIndex, InsInstrs.size()));
8680 InsInstrs.push_back(MiddleIndexLoadInstr);
8681 DelInstrs.push_back(OriginalSplitLoad);
8682
8683 // Subreg To Reg instruction for register 1.
8684 Register DestRegForSubregToReg = MRI.createVirtualRegister(FPR128RegClass);
8685 unsigned SubregType;
8686 switch (NumLanes) {
8687 case 4:
8688 SubregType = AArch64::ssub;
8689 break;
8690 case 8:
8691 SubregType = AArch64::hsub;
8692 break;
8693 case 16:
8694 SubregType = AArch64::bsub;
8695 break;
8696 default:
8698 "Got invalid NumLanes for machine-combiner gather pattern");
8699 }
8700
8701 auto SubRegToRegInstr =
8702 BuildMI(MF, MIMetadata(Root), TII->get(SubregToReg->getOpcode()),
8703 DestRegForSubregToReg)
8704 .addReg(DestRegForMiddleIndex)
8705 .addImm(SubregType);
8706 InstrIdxForVirtReg.insert(
8707 std::make_pair(DestRegForSubregToReg, InsInstrs.size()));
8708 InsInstrs.push_back(SubRegToRegInstr);
8709
8710 // Load remaining lanes into register 1.
8711 auto LanesToLoadToReg1 =
8712 llvm::make_range(LoadToLaneInstrsAscending.begin() + NumLanes / 2 + 1,
8713 LoadToLaneInstrsAscending.end());
8714 PrevReg = SubRegToRegInstr->getOperand(0).getReg();
8715 for (auto [Index, LoadInstr] : llvm::enumerate(LanesToLoadToReg1)) {
8716 const MachineOperand &OffsetRegOperand = LoadInstr->getOperand(3);
8717 PrevReg = CreateLD1Instruction(LoadInstr, PrevReg, Index + 1,
8718 OffsetRegOperand.getReg());
8719
8720 // Do not add the last reg to DelInstrs - it will be removed later.
8721 if (Index == NumLanes / 2 - 2) {
8722 break;
8723 }
8724 DelInstrs.push_back(LoadInstr);
8725 }
8726 Register LastLoadReg1 = PrevReg;
8727
8728 // Create the final zip instruction to combine the results.
8729 MachineInstrBuilder ZipInstr =
8730 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::ZIP1v2i64),
8731 Root.getOperand(0).getReg())
8732 .addReg(LastLoadReg0)
8733 .addReg(LastLoadReg1);
8734 InsInstrs.push_back(ZipInstr);
8735}
8736
8750
8751/// Return true when there is potentially a faster code sequence for an
8752/// instruction chain ending in \p Root. All potential patterns are listed in
8753/// the \p Pattern vector. Pattern should be sorted in priority order since the
8754/// pattern evaluator stops checking as soon as it finds a faster sequence.
8755
8756bool AArch64InstrInfo::getMachineCombinerPatterns(
8757 MachineInstr &Root, SmallVectorImpl<unsigned> &Patterns,
8758 bool DoRegPressureReduce) const {
8759 // Integer patterns
8760 if (getMaddPatterns(Root, Patterns))
8761 return true;
8762 // Floating point patterns
8763 if (getFMULPatterns(Root, Patterns))
8764 return true;
8765 if (getFMAPatterns(Root, Patterns))
8766 return true;
8767 if (getFNEGPatterns(Root, Patterns))
8768 return true;
8769
8770 // Other patterns
8771 if (getMiscPatterns(Root, Patterns))
8772 return true;
8773
8774 // Load patterns
8775 if (getLoadPatterns(Root, Patterns))
8776 return true;
8777
8778 return TargetInstrInfo::getMachineCombinerPatterns(Root, Patterns,
8779 DoRegPressureReduce);
8780}
8781
8783/// genFusedMultiply - Generate fused multiply instructions.
8784/// This function supports both integer and floating point instructions.
8785/// A typical example:
8786/// F|MUL I=A,B,0
8787/// F|ADD R,I,C
8788/// ==> F|MADD R,A,B,C
8789/// \param MF Containing MachineFunction
8790/// \param MRI Register information
8791/// \param TII Target information
8792/// \param Root is the F|ADD instruction
8793/// \param [out] InsInstrs is a vector of machine instructions and will
8794/// contain the generated madd instruction
8795/// \param IdxMulOpd is index of operand in Root that is the result of
8796/// the F|MUL. In the example above IdxMulOpd is 1.
8797/// \param MaddOpc the opcode fo the f|madd instruction
8798/// \param RC Register class of operands
8799/// \param kind of fma instruction (addressing mode) to be generated
8800/// \param ReplacedAddend is the result register from the instruction
8801/// replacing the non-combined operand, if any.
8802static MachineInstr *
8804 const TargetInstrInfo *TII, MachineInstr &Root,
8805 SmallVectorImpl<MachineInstr *> &InsInstrs, unsigned IdxMulOpd,
8806 unsigned MaddOpc, const TargetRegisterClass *RC,
8808 const Register *ReplacedAddend = nullptr) {
8809 assert(IdxMulOpd == 1 || IdxMulOpd == 2);
8810
8811 unsigned IdxOtherOpd = IdxMulOpd == 1 ? 2 : 1;
8812 MachineInstr *MUL = MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());
8813 Register ResultReg = Root.getOperand(0).getReg();
8814 Register SrcReg0 = MUL->getOperand(1).getReg();
8815 Register SrcReg1 = MUL->getOperand(2).getReg();
8816
8817 Register SrcReg2 =
8818 ReplacedAddend ? *ReplacedAddend : Root.getOperand(IdxOtherOpd).getReg();
8819
8820 if (ResultReg.isVirtual())
8821 MRI.constrainRegClass(ResultReg, RC);
8822 if (SrcReg0.isVirtual())
8823 MRI.constrainRegClass(SrcReg0, RC);
8824 if (SrcReg1.isVirtual())
8825 MRI.constrainRegClass(SrcReg1, RC);
8826 if (SrcReg2.isVirtual())
8827 MRI.constrainRegClass(SrcReg2, RC);
8828
8830 if (kind == FMAInstKind::Default)
8831 MIB = BuildMI(MF, MIMetadata(Root), TII->get(MaddOpc), ResultReg)
8832 .addReg(SrcReg0)
8833 .addReg(SrcReg1)
8834 .addReg(SrcReg2);
8835 else if (kind == FMAInstKind::Indexed)
8836 MIB = BuildMI(MF, MIMetadata(Root), TII->get(MaddOpc), ResultReg)
8837 .addReg(SrcReg2)
8838 .addReg(SrcReg0)
8839 .addReg(SrcReg1)
8840 .addImm(MUL->getOperand(3).getImm());
8841 else if (kind == FMAInstKind::Accumulator)
8842 MIB = BuildMI(MF, MIMetadata(Root), TII->get(MaddOpc), ResultReg)
8843 .addReg(SrcReg2)
8844 .addReg(SrcReg0)
8845 .addReg(SrcReg1);
8846 else
8847 assert(false && "Invalid FMA instruction kind \n");
8848 // Insert the MADD (MADD, FMA, FMS, FMLA, FMSL)
8849 InsInstrs.push_back(MIB);
8850 return MUL;
8851}
8852
8853/// MUL I=A,B,0
8854/// ADDrs R,I,C,shift
8855/// ==>
8856/// SBFM/UBFM J=C,shift
8857/// MADD R,A,B,J
8859 const TargetInstrInfo *TII, MachineInstr &Root,
8862 unsigned MaddOpc, bool Is64Bit,
8863 DenseMap<Register, unsigned> &InstrIdxForVirtReg) {
8864 const TargetRegisterClass *RC =
8865 Is64Bit ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass;
8866 MachineInstr *MUL = MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
8867 Register ResultReg = Root.getOperand(0).getReg();
8868 Register SrcReg0 = MUL->getOperand(1).getReg();
8869 Register SrcReg1 = MUL->getOperand(2).getReg();
8870 Register ShiftedReg = Root.getOperand(2).getReg();
8871
8872 if (ResultReg.isVirtual())
8873 MRI.constrainRegClass(ResultReg, RC);
8874 if (SrcReg0.isVirtual())
8875 MRI.constrainRegClass(SrcReg0, RC);
8876 if (SrcReg1.isVirtual())
8877 MRI.constrainRegClass(SrcReg1, RC);
8878 if (ShiftedReg.isVirtual())
8879 MRI.constrainRegClass(ShiftedReg, RC);
8880
8881 unsigned ShiftImm = Root.getOperand(3).getImm();
8882 unsigned ShiftVal = AArch64_AM::getShiftValue(ShiftImm);
8883 unsigned RegSize = Is64Bit ? 64 : 32;
8884 unsigned BFMOpc;
8885 unsigned ImmR, ImmS;
8886 switch (AArch64_AM::getShiftType(ShiftImm)) {
8887 case AArch64_AM::ASR:
8888 BFMOpc = Is64Bit ? AArch64::SBFMXri : AArch64::SBFMWri;
8889 ImmR = ShiftVal;
8890 ImmS = RegSize - 1;
8891 break;
8892 case AArch64_AM::LSR:
8893 BFMOpc = Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri;
8894 ImmR = ShiftVal;
8895 ImmS = RegSize - 1;
8896 break;
8897 case AArch64_AM::LSL:
8898 BFMOpc = Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri;
8899 ImmR = (RegSize - ShiftVal) % RegSize;
8900 ImmS = RegSize - 1 - ShiftVal;
8901 break;
8902 default:
8903 llvm_unreachable("Unexpected shift type");
8904 }
8905
8906 Register ShiftReg = MRI.createVirtualRegister(RC);
8907 MachineInstrBuilder MIB1 =
8908 BuildMI(MF, MIMetadata(Root), TII->get(BFMOpc), ShiftReg)
8909 .addReg(ShiftedReg)
8910 .addImm(ImmR)
8911 .addImm(ImmS);
8912 InstrIdxForVirtReg.insert(std::make_pair(ShiftReg, InsInstrs.size()));
8913 InsInstrs.push_back(MIB1);
8914
8915 uint32_t Flags = Root.getFlags() & MUL->getFlags() &
8917
8918 MachineInstrBuilder MIB2 =
8919 BuildMI(MF, MIMetadata(Root), TII->get(MaddOpc), ResultReg)
8920 .addReg(SrcReg0)
8921 .addReg(SrcReg1)
8922 .addReg(ShiftReg)
8923 .setMIFlags(Flags);
8924
8925 InsInstrs.push_back(MIB2);
8926 DelInstrs.push_back(MUL);
8927 DelInstrs.push_back(&Root);
8928}
8929
8930static MachineInstr *
8932 const TargetInstrInfo *TII, MachineInstr &Root,
8934 MachineInstr *MAD = MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
8935
8936 unsigned Opc = 0;
8937 const TargetRegisterClass *RC = MRI.getRegClass(MAD->getOperand(0).getReg());
8938 if (AArch64::FPR32RegClass.hasSubClassEq(RC))
8939 Opc = AArch64::FNMADDSrrr;
8940 else if (AArch64::FPR64RegClass.hasSubClassEq(RC))
8941 Opc = AArch64::FNMADDDrrr;
8942 else
8943 return nullptr;
8944
8945 Register ResultReg = Root.getOperand(0).getReg();
8946 Register SrcReg0 = MAD->getOperand(1).getReg();
8947 Register SrcReg1 = MAD->getOperand(2).getReg();
8948 Register SrcReg2 = MAD->getOperand(3).getReg();
8949 if (ResultReg.isVirtual())
8950 MRI.constrainRegClass(ResultReg, RC);
8951 if (SrcReg0.isVirtual())
8952 MRI.constrainRegClass(SrcReg0, RC);
8953 if (SrcReg1.isVirtual())
8954 MRI.constrainRegClass(SrcReg1, RC);
8955 if (SrcReg2.isVirtual())
8956 MRI.constrainRegClass(SrcReg2, RC);
8957
8959 BuildMI(MF, MIMetadata(Root), TII->get(Opc), ResultReg)
8960 .addReg(SrcReg0)
8961 .addReg(SrcReg1)
8962 .addReg(SrcReg2);
8963 InsInstrs.push_back(MIB);
8964
8965 return MAD;
8966}
8967
8968/// Fold (FMUL x (DUP y lane)) into (FMUL_indexed x y lane)
8969static MachineInstr *
8972 unsigned IdxDupOp, unsigned MulOpc,
8974 assert(((IdxDupOp == 1) || (IdxDupOp == 2)) &&
8975 "Invalid index of FMUL operand");
8976
8977 MachineFunction &MF = *Root.getMF();
8979
8980 MachineInstr *Dup =
8981 MF.getRegInfo().getUniqueVRegDef(Root.getOperand(IdxDupOp).getReg());
8982
8983 if (Dup->getOpcode() == TargetOpcode::COPY)
8984 Dup = MRI.getUniqueVRegDef(Dup->getOperand(1).getReg());
8985
8986 Register DupSrcReg = Dup->getOperand(1).getReg();
8987 MRI.clearKillFlags(DupSrcReg);
8988 MRI.constrainRegClass(DupSrcReg, RC);
8989
8990 unsigned DupSrcLane = Dup->getOperand(2).getImm();
8991
8992 unsigned IdxMulOp = IdxDupOp == 1 ? 2 : 1;
8993 MachineOperand &MulOp = Root.getOperand(IdxMulOp);
8994
8995 Register ResultReg = Root.getOperand(0).getReg();
8996
8998 MIB = BuildMI(MF, MIMetadata(Root), TII->get(MulOpc), ResultReg)
8999 .add(MulOp)
9000 .addReg(DupSrcReg)
9001 .addImm(DupSrcLane);
9002
9003 InsInstrs.push_back(MIB);
9004 return &Root;
9005}
9006
9007/// genFusedMultiplyAcc - Helper to generate fused multiply accumulate
9008/// instructions.
9009///
9010/// \see genFusedMultiply
9014 unsigned IdxMulOpd, unsigned MaddOpc, const TargetRegisterClass *RC) {
9015 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9017}
9018
9019/// genNeg - Helper to generate an intermediate negation of the second operand
9020/// of Root
9022 const TargetInstrInfo *TII, MachineInstr &Root,
9024 DenseMap<Register, unsigned> &InstrIdxForVirtReg,
9025 unsigned MnegOpc, const TargetRegisterClass *RC) {
9026 Register NewVR = MRI.createVirtualRegister(RC);
9028 BuildMI(MF, MIMetadata(Root), TII->get(MnegOpc), NewVR)
9029 .add(Root.getOperand(2));
9030 InsInstrs.push_back(MIB);
9031
9032 assert(InstrIdxForVirtReg.empty());
9033 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9034
9035 return NewVR;
9036}
9037
9038/// genFusedMultiplyAccNeg - Helper to generate fused multiply accumulate
9039/// instructions with an additional negation of the accumulator
9043 DenseMap<Register, unsigned> &InstrIdxForVirtReg, unsigned IdxMulOpd,
9044 unsigned MaddOpc, unsigned MnegOpc, const TargetRegisterClass *RC) {
9045 assert(IdxMulOpd == 1);
9046
9047 Register NewVR =
9048 genNeg(MF, MRI, TII, Root, InsInstrs, InstrIdxForVirtReg, MnegOpc, RC);
9049 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9050 FMAInstKind::Accumulator, &NewVR);
9051}
9052
9053/// genFusedMultiplyIdx - Helper to generate fused multiply accumulate
9054/// instructions.
9055///
9056/// \see genFusedMultiply
9060 unsigned IdxMulOpd, unsigned MaddOpc, const TargetRegisterClass *RC) {
9061 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9063}
9064
9065/// genFusedMultiplyAccNeg - Helper to generate fused multiply accumulate
9066/// instructions with an additional negation of the accumulator
9070 DenseMap<Register, unsigned> &InstrIdxForVirtReg, unsigned IdxMulOpd,
9071 unsigned MaddOpc, unsigned MnegOpc, const TargetRegisterClass *RC) {
9072 assert(IdxMulOpd == 1);
9073
9074 Register NewVR =
9075 genNeg(MF, MRI, TII, Root, InsInstrs, InstrIdxForVirtReg, MnegOpc, RC);
9076
9077 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9078 FMAInstKind::Indexed, &NewVR);
9079}
9080
9081/// genMaddR - Generate madd instruction and combine mul and add using
9082/// an extra virtual register
9083/// Example - an ADD intermediate needs to be stored in a register:
9084/// MUL I=A,B,0
9085/// ADD R,I,Imm
9086/// ==> ORR V, ZR, Imm
9087/// ==> MADD R,A,B,V
9088/// \param MF Containing MachineFunction
9089/// \param MRI Register information
9090/// \param TII Target information
9091/// \param Root is the ADD instruction
9092/// \param [out] InsInstrs is a vector of machine instructions and will
9093/// contain the generated madd instruction
9094/// \param IdxMulOpd is index of operand in Root that is the result of
9095/// the MUL. In the example above IdxMulOpd is 1.
9096/// \param MaddOpc the opcode fo the madd instruction
9097/// \param VR is a virtual register that holds the value of an ADD operand
9098/// (V in the example above).
9099/// \param RC Register class of operands
9101 const TargetInstrInfo *TII, MachineInstr &Root,
9103 unsigned IdxMulOpd, unsigned MaddOpc, unsigned VR,
9104 const TargetRegisterClass *RC) {
9105 assert(IdxMulOpd == 1 || IdxMulOpd == 2);
9106
9107 MachineInstr *MUL = MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());
9108 Register ResultReg = Root.getOperand(0).getReg();
9109 Register SrcReg0 = MUL->getOperand(1).getReg();
9110 Register SrcReg1 = MUL->getOperand(2).getReg();
9111
9112 if (ResultReg.isVirtual())
9113 MRI.constrainRegClass(ResultReg, RC);
9114 if (SrcReg0.isVirtual())
9115 MRI.constrainRegClass(SrcReg0, RC);
9116 if (SrcReg1.isVirtual())
9117 MRI.constrainRegClass(SrcReg1, RC);
9119 MRI.constrainRegClass(VR, RC);
9120
9122 BuildMI(MF, MIMetadata(Root), TII->get(MaddOpc), ResultReg)
9123 .addReg(SrcReg0)
9124 .addReg(SrcReg1)
9125 .addReg(VR);
9126 // Insert the MADD
9127 InsInstrs.push_back(MIB);
9128 return MUL;
9129}
9130
9131/// Do the following transformation
9132/// A - (B + C) ==> (A - B) - C
9133/// A - (B + C) ==> (A - C) - B
9135 const TargetInstrInfo *TII, MachineInstr &Root,
9138 unsigned IdxOpd1,
9139 DenseMap<Register, unsigned> &InstrIdxForVirtReg) {
9140 assert(IdxOpd1 == 1 || IdxOpd1 == 2);
9141 unsigned IdxOtherOpd = IdxOpd1 == 1 ? 2 : 1;
9142 MachineInstr *AddMI = MRI.getUniqueVRegDef(Root.getOperand(2).getReg());
9143
9144 Register ResultReg = Root.getOperand(0).getReg();
9145 Register RegA = Root.getOperand(1).getReg();
9146 Register RegB = AddMI->getOperand(IdxOpd1).getReg();
9147 Register RegC = AddMI->getOperand(IdxOtherOpd).getReg();
9148 Register NewVR =
9149 MRI.createVirtualRegister(MRI.getRegClass(Root.getOperand(2).getReg()));
9150
9151 unsigned Opcode = Root.getOpcode();
9152 if (Opcode == AArch64::SUBSWrr)
9153 Opcode = AArch64::SUBWrr;
9154 else if (Opcode == AArch64::SUBSXrr)
9155 Opcode = AArch64::SUBXrr;
9156 else
9157 assert((Opcode == AArch64::SUBWrr || Opcode == AArch64::SUBXrr) &&
9158 "Unexpected instruction opcode.");
9159
9160 uint32_t Flags = Root.mergeFlagsWith(*AddMI);
9161 Flags &= ~MachineInstr::NoSWrap;
9162 Flags &= ~MachineInstr::NoUWrap;
9163
9164 MachineInstrBuilder MIB1 =
9165 BuildMI(MF, MIMetadata(Root), TII->get(Opcode), NewVR)
9166 .addReg(RegA)
9167 .addReg(RegB)
9168 .setMIFlags(Flags);
9169 MachineInstrBuilder MIB2 =
9170 BuildMI(MF, MIMetadata(Root), TII->get(Opcode), ResultReg)
9171 .addReg(NewVR)
9172 .addReg(RegC)
9173 .setMIFlags(Flags);
9174
9175 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9176 InsInstrs.push_back(MIB1);
9177 InsInstrs.push_back(MIB2);
9178 DelInstrs.push_back(AddMI);
9179 DelInstrs.push_back(&Root);
9180}
9181
9182unsigned AArch64InstrInfo::getReduceOpcodeForAccumulator(
9183 unsigned int AccumulatorOpCode) const {
9184 switch (AccumulatorOpCode) {
9185 case AArch64::UABALB_ZZZ_D:
9186 case AArch64::SABALB_ZZZ_D:
9187 case AArch64::UABALT_ZZZ_D:
9188 case AArch64::SABALT_ZZZ_D:
9189 return AArch64::ADD_ZZZ_D;
9190 case AArch64::UABALB_ZZZ_H:
9191 case AArch64::SABALB_ZZZ_H:
9192 case AArch64::UABALT_ZZZ_H:
9193 case AArch64::SABALT_ZZZ_H:
9194 return AArch64::ADD_ZZZ_H;
9195 case AArch64::UABALB_ZZZ_S:
9196 case AArch64::SABALB_ZZZ_S:
9197 case AArch64::UABALT_ZZZ_S:
9198 case AArch64::SABALT_ZZZ_S:
9199 return AArch64::ADD_ZZZ_S;
9200 case AArch64::UABALv16i8_v8i16:
9201 case AArch64::SABALv8i8_v8i16:
9202 case AArch64::SABAv8i16:
9203 case AArch64::UABAv8i16:
9204 return AArch64::ADDv8i16;
9205 case AArch64::SABALv2i32_v2i64:
9206 case AArch64::UABALv2i32_v2i64:
9207 case AArch64::SABALv4i32_v2i64:
9208 return AArch64::ADDv2i64;
9209 case AArch64::UABALv4i16_v4i32:
9210 case AArch64::SABALv4i16_v4i32:
9211 case AArch64::SABALv8i16_v4i32:
9212 case AArch64::SABAv4i32:
9213 case AArch64::UABAv4i32:
9214 return AArch64::ADDv4i32;
9215 case AArch64::UABALv4i32_v2i64:
9216 return AArch64::ADDv2i64;
9217 case AArch64::UABALv8i16_v4i32:
9218 return AArch64::ADDv4i32;
9219 case AArch64::UABALv8i8_v8i16:
9220 case AArch64::SABALv16i8_v8i16:
9221 return AArch64::ADDv8i16;
9222 case AArch64::UABAv16i8:
9223 case AArch64::SABAv16i8:
9224 return AArch64::ADDv16i8;
9225 case AArch64::UABAv4i16:
9226 case AArch64::SABAv4i16:
9227 return AArch64::ADDv4i16;
9228 case AArch64::UABAv2i32:
9229 case AArch64::SABAv2i32:
9230 return AArch64::ADDv2i32;
9231 case AArch64::UABAv8i8:
9232 case AArch64::SABAv8i8:
9233 return AArch64::ADDv8i8;
9234 default:
9235 llvm_unreachable("Unknown accumulator opcode");
9236 }
9237}
9238
9239/// When getMachineCombinerPatterns() finds potential patterns,
9240/// this function generates the instructions that could replace the
9241/// original code sequence
9242void AArch64InstrInfo::genAlternativeCodeSequence(
9243 MachineInstr &Root, unsigned Pattern,
9246 DenseMap<Register, unsigned> &InstrIdxForVirtReg) const {
9247 MachineBasicBlock &MBB = *Root.getParent();
9248 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
9249 MachineFunction &MF = *MBB.getParent();
9250 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
9251
9252 MachineInstr *MUL = nullptr;
9253 const TargetRegisterClass *RC;
9254 unsigned Opc;
9255 switch (Pattern) {
9256 default:
9257 // Reassociate instructions.
9258 TargetInstrInfo::genAlternativeCodeSequence(Root, Pattern, InsInstrs,
9259 DelInstrs, InstrIdxForVirtReg);
9260 return;
9262 // A - (B + C)
9263 // ==> (A - B) - C
9264 genSubAdd2SubSub(MF, MRI, TII, Root, InsInstrs, DelInstrs, 1,
9265 InstrIdxForVirtReg);
9266 return;
9268 // A - (B + C)
9269 // ==> (A - C) - B
9270 genSubAdd2SubSub(MF, MRI, TII, Root, InsInstrs, DelInstrs, 2,
9271 InstrIdxForVirtReg);
9272 return;
9275 // MUL I=A,B,0
9276 // ADD R,I,C
9277 // ==> MADD R,A,B,C
9278 // --- Create(MADD);
9280 Opc = AArch64::MADDWrrr;
9281 RC = &AArch64::GPR32RegClass;
9282 } else {
9283 Opc = AArch64::MADDXrrr;
9284 RC = &AArch64::GPR64RegClass;
9285 }
9286 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9287 break;
9290 // MUL I=A,B,0
9291 // ADD R,C,I
9292 // ==> MADD R,A,B,C
9293 // --- Create(MADD);
9295 Opc = AArch64::MADDWrrr;
9296 RC = &AArch64::GPR32RegClass;
9297 } else {
9298 Opc = AArch64::MADDXrrr;
9299 RC = &AArch64::GPR64RegClass;
9300 }
9301 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9302 break;
9307 // MUL I=A,B,0
9308 // ADD/SUB R,I,Imm
9309 // ==> MOV V, Imm/-Imm
9310 // ==> MADD R,A,B,V
9311 // --- Create(MADD);
9312 const TargetRegisterClass *RC;
9313 unsigned BitSize, MovImm;
9316 MovImm = AArch64::MOVi32imm;
9317 RC = &AArch64::GPR32spRegClass;
9318 BitSize = 32;
9319 Opc = AArch64::MADDWrrr;
9320 RC = &AArch64::GPR32RegClass;
9321 } else {
9322 MovImm = AArch64::MOVi64imm;
9323 RC = &AArch64::GPR64spRegClass;
9324 BitSize = 64;
9325 Opc = AArch64::MADDXrrr;
9326 RC = &AArch64::GPR64RegClass;
9327 }
9329 uint64_t Imm = Root.getOperand(2).getImm();
9330
9331 if (Root.getOperand(3).isImm()) {
9332 unsigned Val = Root.getOperand(3).getImm();
9333 Imm = Imm << Val;
9334 }
9335 bool IsSub = Pattern == AArch64MachineCombinerPattern::MULSUBWI_OP1 ||
9337 uint64_t UImm = SignExtend64(IsSub ? -Imm : Imm, BitSize);
9338 // Check that the immediate can be composed via a single instruction.
9340 AArch64_IMM::expandMOVImm(UImm, BitSize, Insn);
9341 if (Insn.size() != 1)
9342 return;
9343 MachineInstrBuilder MIB1 =
9344 BuildMI(MF, MIMetadata(Root), TII->get(MovImm), NewVR)
9345 .addImm(IsSub ? -Imm : Imm);
9346 InsInstrs.push_back(MIB1);
9347 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9348 MUL = genMaddR(MF, MRI, TII, Root, InsInstrs, 1, Opc, NewVR, RC);
9349 break;
9350 }
9353 // MUL I=A,B,0
9354 // SUB R,I, C
9355 // ==> SUB V, 0, C
9356 // ==> MADD R,A,B,V // = -C + A*B
9357 // --- Create(MADD);
9358 const TargetRegisterClass *SubRC;
9359 unsigned SubOpc, ZeroReg;
9361 SubOpc = AArch64::SUBWrr;
9362 SubRC = &AArch64::GPR32spRegClass;
9363 ZeroReg = AArch64::WZR;
9364 Opc = AArch64::MADDWrrr;
9365 RC = &AArch64::GPR32RegClass;
9366 } else {
9367 SubOpc = AArch64::SUBXrr;
9368 SubRC = &AArch64::GPR64spRegClass;
9369 ZeroReg = AArch64::XZR;
9370 Opc = AArch64::MADDXrrr;
9371 RC = &AArch64::GPR64RegClass;
9372 }
9373 Register NewVR = MRI.createVirtualRegister(SubRC);
9374 // SUB NewVR, 0, C
9375 MachineInstrBuilder MIB1 =
9376 BuildMI(MF, MIMetadata(Root), TII->get(SubOpc), NewVR)
9377 .addReg(ZeroReg)
9378 .add(Root.getOperand(2));
9379 InsInstrs.push_back(MIB1);
9380 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9381 MUL = genMaddR(MF, MRI, TII, Root, InsInstrs, 1, Opc, NewVR, RC);
9382 break;
9383 }
9386 // MUL I=A,B,0
9387 // SUB R,C,I
9388 // ==> MSUB R,A,B,C (computes C - A*B)
9389 // --- Create(MSUB);
9391 Opc = AArch64::MSUBWrrr;
9392 RC = &AArch64::GPR32RegClass;
9393 } else {
9394 Opc = AArch64::MSUBXrrr;
9395 RC = &AArch64::GPR64RegClass;
9396 }
9397 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9398 break;
9400 genMaddShf(MF, MRI, TII, Root, InsInstrs, DelInstrs, AArch64::MADDWrrr,
9401 false, InstrIdxForVirtReg);
9402 return;
9404 genMaddShf(MF, MRI, TII, Root, InsInstrs, DelInstrs, AArch64::MADDXrrr,
9405 true, InstrIdxForVirtReg);
9406 return;
9408 Opc = AArch64::MLAv8i8;
9409 RC = &AArch64::FPR64RegClass;
9410 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9411 break;
9413 Opc = AArch64::MLAv8i8;
9414 RC = &AArch64::FPR64RegClass;
9415 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9416 break;
9418 Opc = AArch64::MLAv16i8;
9419 RC = &AArch64::FPR128RegClass;
9420 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9421 break;
9423 Opc = AArch64::MLAv16i8;
9424 RC = &AArch64::FPR128RegClass;
9425 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9426 break;
9428 Opc = AArch64::MLAv4i16;
9429 RC = &AArch64::FPR64RegClass;
9430 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9431 break;
9433 Opc = AArch64::MLAv4i16;
9434 RC = &AArch64::FPR64RegClass;
9435 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9436 break;
9438 Opc = AArch64::MLAv8i16;
9439 RC = &AArch64::FPR128RegClass;
9440 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9441 break;
9443 Opc = AArch64::MLAv8i16;
9444 RC = &AArch64::FPR128RegClass;
9445 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9446 break;
9448 Opc = AArch64::MLAv2i32;
9449 RC = &AArch64::FPR64RegClass;
9450 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9451 break;
9453 Opc = AArch64::MLAv2i32;
9454 RC = &AArch64::FPR64RegClass;
9455 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9456 break;
9458 Opc = AArch64::MLAv4i32;
9459 RC = &AArch64::FPR128RegClass;
9460 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9461 break;
9463 Opc = AArch64::MLAv4i32;
9464 RC = &AArch64::FPR128RegClass;
9465 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9466 break;
9467
9469 Opc = AArch64::MLAv8i8;
9470 RC = &AArch64::FPR64RegClass;
9471 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9472 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv8i8,
9473 RC);
9474 break;
9476 Opc = AArch64::MLSv8i8;
9477 RC = &AArch64::FPR64RegClass;
9478 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9479 break;
9481 Opc = AArch64::MLAv16i8;
9482 RC = &AArch64::FPR128RegClass;
9483 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9484 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv16i8,
9485 RC);
9486 break;
9488 Opc = AArch64::MLSv16i8;
9489 RC = &AArch64::FPR128RegClass;
9490 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9491 break;
9493 Opc = AArch64::MLAv4i16;
9494 RC = &AArch64::FPR64RegClass;
9495 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9496 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i16,
9497 RC);
9498 break;
9500 Opc = AArch64::MLSv4i16;
9501 RC = &AArch64::FPR64RegClass;
9502 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9503 break;
9505 Opc = AArch64::MLAv8i16;
9506 RC = &AArch64::FPR128RegClass;
9507 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9508 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv8i16,
9509 RC);
9510 break;
9512 Opc = AArch64::MLSv8i16;
9513 RC = &AArch64::FPR128RegClass;
9514 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9515 break;
9517 Opc = AArch64::MLAv2i32;
9518 RC = &AArch64::FPR64RegClass;
9519 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9520 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv2i32,
9521 RC);
9522 break;
9524 Opc = AArch64::MLSv2i32;
9525 RC = &AArch64::FPR64RegClass;
9526 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9527 break;
9529 Opc = AArch64::MLAv4i32;
9530 RC = &AArch64::FPR128RegClass;
9531 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9532 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i32,
9533 RC);
9534 break;
9536 Opc = AArch64::MLSv4i32;
9537 RC = &AArch64::FPR128RegClass;
9538 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9539 break;
9540
9542 Opc = AArch64::MLAv4i16_indexed;
9543 RC = &AArch64::FPR64RegClass;
9544 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9545 break;
9547 Opc = AArch64::MLAv4i16_indexed;
9548 RC = &AArch64::FPR64RegClass;
9549 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9550 break;
9552 Opc = AArch64::MLAv8i16_indexed;
9553 RC = &AArch64::FPR128RegClass;
9554 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9555 break;
9557 Opc = AArch64::MLAv8i16_indexed;
9558 RC = &AArch64::FPR128RegClass;
9559 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9560 break;
9562 Opc = AArch64::MLAv2i32_indexed;
9563 RC = &AArch64::FPR64RegClass;
9564 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9565 break;
9567 Opc = AArch64::MLAv2i32_indexed;
9568 RC = &AArch64::FPR64RegClass;
9569 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9570 break;
9572 Opc = AArch64::MLAv4i32_indexed;
9573 RC = &AArch64::FPR128RegClass;
9574 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9575 break;
9577 Opc = AArch64::MLAv4i32_indexed;
9578 RC = &AArch64::FPR128RegClass;
9579 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9580 break;
9581
9583 Opc = AArch64::MLAv4i16_indexed;
9584 RC = &AArch64::FPR64RegClass;
9585 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9586 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i16,
9587 RC);
9588 break;
9590 Opc = AArch64::MLSv4i16_indexed;
9591 RC = &AArch64::FPR64RegClass;
9592 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9593 break;
9595 Opc = AArch64::MLAv8i16_indexed;
9596 RC = &AArch64::FPR128RegClass;
9597 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9598 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv8i16,
9599 RC);
9600 break;
9602 Opc = AArch64::MLSv8i16_indexed;
9603 RC = &AArch64::FPR128RegClass;
9604 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9605 break;
9607 Opc = AArch64::MLAv2i32_indexed;
9608 RC = &AArch64::FPR64RegClass;
9609 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9610 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv2i32,
9611 RC);
9612 break;
9614 Opc = AArch64::MLSv2i32_indexed;
9615 RC = &AArch64::FPR64RegClass;
9616 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9617 break;
9619 Opc = AArch64::MLAv4i32_indexed;
9620 RC = &AArch64::FPR128RegClass;
9621 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9622 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i32,
9623 RC);
9624 break;
9626 Opc = AArch64::MLSv4i32_indexed;
9627 RC = &AArch64::FPR128RegClass;
9628 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9629 break;
9630
9631 // Floating Point Support
9633 Opc = AArch64::FMADDHrrr;
9634 RC = &AArch64::FPR16RegClass;
9635 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9636 break;
9638 Opc = AArch64::FMADDSrrr;
9639 RC = &AArch64::FPR32RegClass;
9640 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9641 break;
9643 Opc = AArch64::FMADDDrrr;
9644 RC = &AArch64::FPR64RegClass;
9645 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9646 break;
9647
9649 Opc = AArch64::FMADDHrrr;
9650 RC = &AArch64::FPR16RegClass;
9651 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9652 break;
9654 Opc = AArch64::FMADDSrrr;
9655 RC = &AArch64::FPR32RegClass;
9656 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9657 break;
9659 Opc = AArch64::FMADDDrrr;
9660 RC = &AArch64::FPR64RegClass;
9661 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9662 break;
9663
9665 Opc = AArch64::FMLAv1i32_indexed;
9666 RC = &AArch64::FPR32RegClass;
9667 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9669 break;
9671 Opc = AArch64::FMLAv1i32_indexed;
9672 RC = &AArch64::FPR32RegClass;
9673 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9675 break;
9676
9678 Opc = AArch64::FMLAv1i64_indexed;
9679 RC = &AArch64::FPR64RegClass;
9680 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9682 break;
9684 Opc = AArch64::FMLAv1i64_indexed;
9685 RC = &AArch64::FPR64RegClass;
9686 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9688 break;
9689
9691 RC = &AArch64::FPR64RegClass;
9692 Opc = AArch64::FMLAv4i16_indexed;
9693 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9695 break;
9697 RC = &AArch64::FPR64RegClass;
9698 Opc = AArch64::FMLAv4f16;
9699 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9701 break;
9703 RC = &AArch64::FPR64RegClass;
9704 Opc = AArch64::FMLAv4i16_indexed;
9705 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9707 break;
9709 RC = &AArch64::FPR64RegClass;
9710 Opc = AArch64::FMLAv4f16;
9711 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9713 break;
9714
9717 RC = &AArch64::FPR64RegClass;
9719 Opc = AArch64::FMLAv2i32_indexed;
9720 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9722 } else {
9723 Opc = AArch64::FMLAv2f32;
9724 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9726 }
9727 break;
9730 RC = &AArch64::FPR64RegClass;
9732 Opc = AArch64::FMLAv2i32_indexed;
9733 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9735 } else {
9736 Opc = AArch64::FMLAv2f32;
9737 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9739 }
9740 break;
9741
9743 RC = &AArch64::FPR128RegClass;
9744 Opc = AArch64::FMLAv8i16_indexed;
9745 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9747 break;
9749 RC = &AArch64::FPR128RegClass;
9750 Opc = AArch64::FMLAv8f16;
9751 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9753 break;
9755 RC = &AArch64::FPR128RegClass;
9756 Opc = AArch64::FMLAv8i16_indexed;
9757 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9759 break;
9761 RC = &AArch64::FPR128RegClass;
9762 Opc = AArch64::FMLAv8f16;
9763 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9765 break;
9766
9769 RC = &AArch64::FPR128RegClass;
9771 Opc = AArch64::FMLAv2i64_indexed;
9772 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9774 } else {
9775 Opc = AArch64::FMLAv2f64;
9776 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9778 }
9779 break;
9782 RC = &AArch64::FPR128RegClass;
9784 Opc = AArch64::FMLAv2i64_indexed;
9785 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9787 } else {
9788 Opc = AArch64::FMLAv2f64;
9789 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9791 }
9792 break;
9793
9796 RC = &AArch64::FPR128RegClass;
9798 Opc = AArch64::FMLAv4i32_indexed;
9799 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9801 } else {
9802 Opc = AArch64::FMLAv4f32;
9803 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9805 }
9806 break;
9807
9810 RC = &AArch64::FPR128RegClass;
9812 Opc = AArch64::FMLAv4i32_indexed;
9813 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9815 } else {
9816 Opc = AArch64::FMLAv4f32;
9817 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9819 }
9820 break;
9821
9823 Opc = AArch64::FNMSUBHrrr;
9824 RC = &AArch64::FPR16RegClass;
9825 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9826 break;
9828 Opc = AArch64::FNMSUBSrrr;
9829 RC = &AArch64::FPR32RegClass;
9830 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9831 break;
9833 Opc = AArch64::FNMSUBDrrr;
9834 RC = &AArch64::FPR64RegClass;
9835 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9836 break;
9837
9839 Opc = AArch64::FNMADDHrrr;
9840 RC = &AArch64::FPR16RegClass;
9841 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9842 break;
9844 Opc = AArch64::FNMADDSrrr;
9845 RC = &AArch64::FPR32RegClass;
9846 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9847 break;
9849 Opc = AArch64::FNMADDDrrr;
9850 RC = &AArch64::FPR64RegClass;
9851 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9852 break;
9853
9855 Opc = AArch64::FMSUBHrrr;
9856 RC = &AArch64::FPR16RegClass;
9857 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9858 break;
9860 Opc = AArch64::FMSUBSrrr;
9861 RC = &AArch64::FPR32RegClass;
9862 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9863 break;
9865 Opc = AArch64::FMSUBDrrr;
9866 RC = &AArch64::FPR64RegClass;
9867 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9868 break;
9869
9871 Opc = AArch64::FMLSv1i32_indexed;
9872 RC = &AArch64::FPR32RegClass;
9873 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9875 break;
9876
9878 Opc = AArch64::FMLSv1i64_indexed;
9879 RC = &AArch64::FPR64RegClass;
9880 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9882 break;
9883
9886 RC = &AArch64::FPR64RegClass;
9888 MachineInstrBuilder MIB1 =
9889 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv4f16), NewVR)
9890 .add(Root.getOperand(2));
9891 InsInstrs.push_back(MIB1);
9892 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9894 Opc = AArch64::FMLAv4f16;
9895 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9896 FMAInstKind::Accumulator, &NewVR);
9897 } else {
9898 Opc = AArch64::FMLAv4i16_indexed;
9899 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9900 FMAInstKind::Indexed, &NewVR);
9901 }
9902 break;
9903 }
9905 RC = &AArch64::FPR64RegClass;
9906 Opc = AArch64::FMLSv4f16;
9907 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9909 break;
9911 RC = &AArch64::FPR64RegClass;
9912 Opc = AArch64::FMLSv4i16_indexed;
9913 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9915 break;
9916
9919 RC = &AArch64::FPR64RegClass;
9921 Opc = AArch64::FMLSv2i32_indexed;
9922 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9924 } else {
9925 Opc = AArch64::FMLSv2f32;
9926 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9928 }
9929 break;
9930
9933 RC = &AArch64::FPR128RegClass;
9935 MachineInstrBuilder MIB1 =
9936 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv8f16), NewVR)
9937 .add(Root.getOperand(2));
9938 InsInstrs.push_back(MIB1);
9939 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9941 Opc = AArch64::FMLAv8f16;
9942 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9943 FMAInstKind::Accumulator, &NewVR);
9944 } else {
9945 Opc = AArch64::FMLAv8i16_indexed;
9946 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9947 FMAInstKind::Indexed, &NewVR);
9948 }
9949 break;
9950 }
9952 RC = &AArch64::FPR128RegClass;
9953 Opc = AArch64::FMLSv8f16;
9954 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9956 break;
9958 RC = &AArch64::FPR128RegClass;
9959 Opc = AArch64::FMLSv8i16_indexed;
9960 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9962 break;
9963
9966 RC = &AArch64::FPR128RegClass;
9968 Opc = AArch64::FMLSv2i64_indexed;
9969 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9971 } else {
9972 Opc = AArch64::FMLSv2f64;
9973 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9975 }
9976 break;
9977
9980 RC = &AArch64::FPR128RegClass;
9982 Opc = AArch64::FMLSv4i32_indexed;
9983 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9985 } else {
9986 Opc = AArch64::FMLSv4f32;
9987 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9989 }
9990 break;
9993 RC = &AArch64::FPR64RegClass;
9995 MachineInstrBuilder MIB1 =
9996 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv2f32), NewVR)
9997 .add(Root.getOperand(2));
9998 InsInstrs.push_back(MIB1);
9999 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
10001 Opc = AArch64::FMLAv2i32_indexed;
10002 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10003 FMAInstKind::Indexed, &NewVR);
10004 } else {
10005 Opc = AArch64::FMLAv2f32;
10006 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10007 FMAInstKind::Accumulator, &NewVR);
10008 }
10009 break;
10010 }
10013 RC = &AArch64::FPR128RegClass;
10015 MachineInstrBuilder MIB1 =
10016 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv4f32), NewVR)
10017 .add(Root.getOperand(2));
10018 InsInstrs.push_back(MIB1);
10019 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
10021 Opc = AArch64::FMLAv4i32_indexed;
10022 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10023 FMAInstKind::Indexed, &NewVR);
10024 } else {
10025 Opc = AArch64::FMLAv4f32;
10026 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10027 FMAInstKind::Accumulator, &NewVR);
10028 }
10029 break;
10030 }
10033 RC = &AArch64::FPR128RegClass;
10035 MachineInstrBuilder MIB1 =
10036 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv2f64), NewVR)
10037 .add(Root.getOperand(2));
10038 InsInstrs.push_back(MIB1);
10039 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
10041 Opc = AArch64::FMLAv2i64_indexed;
10042 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10043 FMAInstKind::Indexed, &NewVR);
10044 } else {
10045 Opc = AArch64::FMLAv2f64;
10046 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10047 FMAInstKind::Accumulator, &NewVR);
10048 }
10049 break;
10050 }
10053 unsigned IdxDupOp =
10055 : 2;
10056 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv2i32_indexed,
10057 &AArch64::FPR128RegClass, MRI);
10058 break;
10059 }
10062 unsigned IdxDupOp =
10064 : 2;
10065 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv2i64_indexed,
10066 &AArch64::FPR128RegClass, MRI);
10067 break;
10068 }
10071 unsigned IdxDupOp =
10073 : 2;
10074 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv4i16_indexed,
10075 &AArch64::FPR128_loRegClass, MRI);
10076 break;
10077 }
10080 unsigned IdxDupOp =
10082 : 2;
10083 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv4i32_indexed,
10084 &AArch64::FPR128RegClass, MRI);
10085 break;
10086 }
10089 unsigned IdxDupOp =
10091 : 2;
10092 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv8i16_indexed,
10093 &AArch64::FPR128_loRegClass, MRI);
10094 break;
10095 }
10097 MUL = genFNegatedMAD(MF, MRI, TII, Root, InsInstrs);
10098 break;
10099 }
10101 generateGatherLanePattern(Root, InsInstrs, DelInstrs, InstrIdxForVirtReg,
10102 Pattern, 4);
10103 break;
10104 }
10106 generateGatherLanePattern(Root, InsInstrs, DelInstrs, InstrIdxForVirtReg,
10107 Pattern, 8);
10108 break;
10109 }
10111 generateGatherLanePattern(Root, InsInstrs, DelInstrs, InstrIdxForVirtReg,
10112 Pattern, 16);
10113 break;
10114 }
10115
10116 } // end switch (Pattern)
10117 // Record MUL and ADD/SUB for deletion
10118 if (MUL)
10119 DelInstrs.push_back(MUL);
10120 DelInstrs.push_back(&Root);
10121
10122 // Set the flags on the inserted instructions to be the merged flags of the
10123 // instructions that we have combined.
10124 uint32_t Flags = Root.getFlags();
10125 if (MUL)
10126 Flags = Root.mergeFlagsWith(*MUL);
10127 for (auto *MI : InsInstrs)
10128 MI->setFlags(Flags);
10129}
10130
10131/// Replace csincr-branch sequence by simple conditional branch
10132///
10133/// Examples:
10134/// 1. \code
10135/// csinc w9, wzr, wzr, <condition code>
10136/// tbnz w9, #0, 0x44
10137/// \endcode
10138/// to
10139/// \code
10140/// b.<inverted condition code>
10141/// \endcode
10142///
10143/// 2. \code
10144/// csinc w9, wzr, wzr, <condition code>
10145/// tbz w9, #0, 0x44
10146/// \endcode
10147/// to
10148/// \code
10149/// b.<condition code>
10150/// \endcode
10151///
10152/// Replace compare and branch sequence by TBZ/TBNZ instruction when the
10153/// compare's constant operand is power of 2.
10154///
10155/// Examples:
10156/// \code
10157/// and w8, w8, #0x400
10158/// cbnz w8, L1
10159/// \endcode
10160/// to
10161/// \code
10162/// tbnz w8, #10, L1
10163/// \endcode
10164///
10165/// \param MI Conditional Branch
10166/// \return True when the simple conditional branch is generated
10167///
10169 bool IsNegativeBranch = false;
10170 bool IsTestAndBranch = false;
10171 unsigned TargetBBInMI = 0;
10172 switch (MI.getOpcode()) {
10173 default:
10174 llvm_unreachable("Unknown branch instruction?");
10175 case AArch64::Bcc:
10176 case AArch64::CBWPri:
10177 case AArch64::CBXPri:
10178 case AArch64::CBBAssertExt:
10179 case AArch64::CBHAssertExt:
10180 case AArch64::CBWPrr:
10181 case AArch64::CBXPrr:
10182 return false;
10183 case AArch64::CBZW:
10184 case AArch64::CBZX:
10185 TargetBBInMI = 1;
10186 break;
10187 case AArch64::CBNZW:
10188 case AArch64::CBNZX:
10189 TargetBBInMI = 1;
10190 IsNegativeBranch = true;
10191 break;
10192 case AArch64::TBZW:
10193 case AArch64::TBZX:
10194 TargetBBInMI = 2;
10195 IsTestAndBranch = true;
10196 break;
10197 case AArch64::TBNZW:
10198 case AArch64::TBNZX:
10199 TargetBBInMI = 2;
10200 IsNegativeBranch = true;
10201 IsTestAndBranch = true;
10202 break;
10203 }
10204 // So we increment a zero register and test for bits other
10205 // than bit 0? Conservatively bail out in case the verifier
10206 // missed this case.
10207 if (IsTestAndBranch && MI.getOperand(1).getImm())
10208 return false;
10209
10210 // Find Definition.
10211 assert(MI.getParent() && "Incomplete machine instruction\n");
10212 MachineBasicBlock *MBB = MI.getParent();
10213 MachineFunction *MF = MBB->getParent();
10215 Register VReg = MI.getOperand(0).getReg();
10216 if (!VReg.isVirtual())
10217 return false;
10218
10219 MachineInstr *DefMI = MRI->getVRegDef(VReg);
10220 if (!DefMI)
10221 return false;
10222
10223 // Look through COPY instructions to find definition.
10224 while (DefMI->isCopy()) {
10225 Register CopyVReg = DefMI->getOperand(1).getReg();
10226 if (!CopyVReg.isVirtual())
10227 return false;
10228 if (!MRI->hasOneNonDBGUse(CopyVReg))
10229 return false;
10230 DefMI = MRI->getVRegDef(CopyVReg);
10231 if (!DefMI)
10232 return false;
10233 }
10234
10235 switch (DefMI->getOpcode()) {
10236 default:
10237 return false;
10238 // Fold AND into a TBZ/TBNZ if constant operand is power of 2.
10239 case AArch64::ANDWri:
10240 case AArch64::ANDXri: {
10241 if (IsTestAndBranch)
10242 return false;
10243 if (DefMI->getParent() != MBB)
10244 return false;
10245 if (!MRI->hasOneNonDBGUse(VReg))
10246 return false;
10247
10248 bool Is32Bit = (DefMI->getOpcode() == AArch64::ANDWri);
10249 uint64_t Mask = AArch64_AM::decodeLogicalImmediate(
10250 DefMI->getOperand(2).getImm(), Is32Bit ? 32 : 64);
10251 if (!isPowerOf2_64(Mask))
10252 return false;
10253
10254 MachineOperand &MO = DefMI->getOperand(1);
10255 Register NewReg = MO.getReg();
10256 if (!NewReg.isVirtual())
10257 return false;
10258
10259 if (!MRI->getVRegDef(NewReg))
10260 return false;
10261
10262 MachineBasicBlock &RefToMBB = *MBB;
10263 MachineBasicBlock *TBB = MI.getOperand(1).getMBB();
10264 DebugLoc DL = MI.getDebugLoc();
10265 unsigned Imm = Log2_64(Mask);
10266 unsigned Opc = (Imm < 32)
10267 ? (IsNegativeBranch ? AArch64::TBNZW : AArch64::TBZW)
10268 : (IsNegativeBranch ? AArch64::TBNZX : AArch64::TBZX);
10269 MachineInstr *NewMI = BuildMI(RefToMBB, MI, DL, get(Opc))
10270 .addReg(NewReg)
10271 .addImm(Imm)
10272 .addMBB(TBB);
10273 // Register lives on to the CBZ now.
10274 MO.setIsKill(false);
10275
10276 // For immediate smaller than 32, we need to use the 32-bit
10277 // variant (W) in all cases. Indeed the 64-bit variant does not
10278 // allow to encode them.
10279 // Therefore, if the input register is 64-bit, we need to take the
10280 // 32-bit sub-part.
10281 if (!Is32Bit && Imm < 32)
10282 NewMI->getOperand(0).setSubReg(AArch64::sub_32);
10283 MI.eraseFromParent();
10284 return true;
10285 }
10286 // Look for CSINC
10287 case AArch64::CSINCWr:
10288 case AArch64::CSINCXr: {
10289 if (!(DefMI->getOperand(1).getReg() == AArch64::WZR &&
10290 DefMI->getOperand(2).getReg() == AArch64::WZR) &&
10291 !(DefMI->getOperand(1).getReg() == AArch64::XZR &&
10292 DefMI->getOperand(2).getReg() == AArch64::XZR))
10293 return false;
10294
10295 if (DefMI->findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr,
10296 true) != -1)
10297 return false;
10298
10299 AArch64CC::CondCode CC = (AArch64CC::CondCode)DefMI->getOperand(3).getImm();
10300 // Convert only when the condition code is not modified between
10301 // the CSINC and the branch. The CC may be used by other
10302 // instructions in between.
10304 return false;
10305 MachineBasicBlock &RefToMBB = *MBB;
10306 MachineBasicBlock *TBB = MI.getOperand(TargetBBInMI).getMBB();
10307 DebugLoc DL = MI.getDebugLoc();
10308 if (IsNegativeBranch)
10310 BuildMI(RefToMBB, MI, DL, get(AArch64::Bcc)).addImm(CC).addMBB(TBB);
10311 MI.eraseFromParent();
10312 return true;
10313 }
10314 }
10315}
10316
10317std::pair<unsigned, unsigned>
10318AArch64InstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
10319 const unsigned Mask = AArch64II::MO_FRAGMENT;
10320 return std::make_pair(TF & Mask, TF & ~Mask);
10321}
10322
10324AArch64InstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
10325 using namespace AArch64II;
10326
10327 static const std::pair<unsigned, const char *> TargetFlags[] = {
10328 {MO_PAGE, "aarch64-page"}, {MO_PAGEOFF, "aarch64-pageoff"},
10329 {MO_G3, "aarch64-g3"}, {MO_G2, "aarch64-g2"},
10330 {MO_G1, "aarch64-g1"}, {MO_G0, "aarch64-g0"},
10331 {MO_HI12, "aarch64-hi12"}};
10332 return ArrayRef(TargetFlags);
10333}
10334
10336AArch64InstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
10337 using namespace AArch64II;
10338
10339 static const std::pair<unsigned, const char *> TargetFlags[] = {
10340 {MO_COFFSTUB, "aarch64-coffstub"},
10341 {MO_GOT, "aarch64-got"},
10342 {MO_NC, "aarch64-nc"},
10343 {MO_S, "aarch64-s"},
10344 {MO_TLS, "aarch64-tls"},
10345 {MO_DLLIMPORT, "aarch64-dllimport"},
10346 {MO_PREL, "aarch64-prel"},
10347 {MO_TAGGED, "aarch64-tagged"},
10348 {MO_ARM64EC_CALLMANGLE, "aarch64-arm64ec-callmangle"},
10349 };
10350 return ArrayRef(TargetFlags);
10351}
10352
10354AArch64InstrInfo::getSerializableMachineMemOperandTargetFlags() const {
10355 static const std::pair<MachineMemOperand::Flags, const char *> TargetFlags[] =
10356 {{MOSuppressPair, "aarch64-suppress-pair"},
10357 {MOStridedAccess, "aarch64-strided-access"}};
10358 return ArrayRef(TargetFlags);
10359}
10360
10361/// Constants defining how certain sequences should be outlined.
10362/// This encompasses how an outlined function should be called, and what kind of
10363/// frame should be emitted for that outlined function.
10364///
10365/// \p MachineOutlinerDefault implies that the function should be called with
10366/// a save and restore of LR to the stack.
10367///
10368/// That is,
10369///
10370/// I1 Save LR OUTLINED_FUNCTION:
10371/// I2 --> BL OUTLINED_FUNCTION I1
10372/// I3 Restore LR I2
10373/// I3
10374/// RET
10375///
10376/// * Call construction overhead: 3 (save + BL + restore)
10377/// * Frame construction overhead: 1 (ret)
10378/// * Requires stack fixups? Yes
10379///
10380/// \p MachineOutlinerTailCall implies that the function is being created from
10381/// a sequence of instructions ending in a return.
10382///
10383/// That is,
10384///
10385/// I1 OUTLINED_FUNCTION:
10386/// I2 --> B OUTLINED_FUNCTION I1
10387/// RET I2
10388/// RET
10389///
10390/// * Call construction overhead: 1 (B)
10391/// * Frame construction overhead: 0 (Return included in sequence)
10392/// * Requires stack fixups? No
10393///
10394/// \p MachineOutlinerNoLRSave implies that the function should be called using
10395/// a BL instruction, but doesn't require LR to be saved and restored. This
10396/// happens when LR is known to be dead.
10397///
10398/// That is,
10399///
10400/// I1 OUTLINED_FUNCTION:
10401/// I2 --> BL OUTLINED_FUNCTION I1
10402/// I3 I2
10403/// I3
10404/// RET
10405///
10406/// * Call construction overhead: 1 (BL)
10407/// * Frame construction overhead: 1 (RET)
10408/// * Requires stack fixups? No
10409///
10410/// \p MachineOutlinerThunk implies that the function is being created from
10411/// a sequence of instructions ending in a call. The outlined function is
10412/// called with a BL instruction, and the outlined function tail-calls the
10413/// original call destination.
10414///
10415/// That is,
10416///
10417/// I1 OUTLINED_FUNCTION:
10418/// I2 --> BL OUTLINED_FUNCTION I1
10419/// BL f I2
10420/// B f
10421/// * Call construction overhead: 1 (BL)
10422/// * Frame construction overhead: 0
10423/// * Requires stack fixups? No
10424///
10425/// \p MachineOutlinerRegSave implies that the function should be called with a
10426/// save and restore of LR to an available register. This allows us to avoid
10427/// stack fixups. Note that this outlining variant is compatible with the
10428/// NoLRSave case.
10429///
10430/// That is,
10431///
10432/// I1 Save LR OUTLINED_FUNCTION:
10433/// I2 --> BL OUTLINED_FUNCTION I1
10434/// I3 Restore LR I2
10435/// I3
10436/// RET
10437///
10438/// * Call construction overhead: 3 (save + BL + restore)
10439/// * Frame construction overhead: 1 (ret)
10440/// * Requires stack fixups? No
10442 MachineOutlinerDefault, /// Emit a save, restore, call, and return.
10443 MachineOutlinerTailCall, /// Only emit a branch.
10444 MachineOutlinerNoLRSave, /// Emit a call and return.
10445 MachineOutlinerThunk, /// Emit a call and tail-call.
10446 MachineOutlinerRegSave /// Same as default, but save to a register.
10447};
10448
10454
10455/// Return true if the frame-record form of the outlined prologue is enabled for
10456/// the target of \p MF.
10457///
10458/// A non-leaf outlined function must save LR. On MachO, saving LR alone
10459/// (str x30) has no compact unwind encoding, so we get a large DWARF FDE
10460/// instead. Saving FP and LR as a frame record (stp x29, x30 ; mov x29, sp)
10461/// gets the small FRAME encoding, and costs one extra instruction.
10463 return MF.getSubtarget<AArch64Subtarget>()
10464 .getCLOpts()
10465 .outliner_compact_unwind_frame &&
10467}
10468
10469/// Return true if the outlined function in \p MBB should save FP and LR as a
10470/// frame record instead of saving LR alone.
10472 const MachineBasicBlock &MBB) {
10473 const MachineFunction &MF = *MBB.getParent();
10474
10475 // Only worth it if the function has unwind info to shrink.
10478 return false;
10479
10480 // Only safe if the outlined code never touches FP, since we overwrite it.
10482 for (const MachineInstr &MI : MBB.instrs())
10483 LRU.accumulate(MI);
10484 return LRU.available(AArch64::FP);
10485}
10486
10487/// Predict what the above will answer, for use while costing candidates. The
10488/// outlined function does not exist yet, so answer from \p RepeatedSequenceLocs
10489/// instead. This is only an estimate; buildOutlinedFrame() makes the call.
10491 std::vector<outliner::Candidate> &RepeatedSequenceLocs,
10492 const TargetRegisterInfo &TRI) {
10493 if (!isCompactUnwindFrameRecordEnabled(*RepeatedSequenceLocs.front().getMF()))
10494 return false;
10495
10496 // The outlined function is nounwind only if every candidate is, so it has
10497 // unwind info if any candidate does.
10498 if (llvm::none_of(RepeatedSequenceLocs, [](outliner::Candidate &C) {
10499 const MachineFunction &MF = *C.getMF();
10500 return MF.getInfo<AArch64FunctionInfo>()->needsDwarfUnwindInfo(MF);
10501 }))
10502 return false;
10503
10504 // FP is free in the outlined function only if it is free in every candidate.
10505 return llvm::all_of(RepeatedSequenceLocs, [&TRI](outliner::Candidate &C) {
10506 return C.isAvailableInsideSeq(AArch64::FP, TRI);
10507 });
10508}
10509
10511AArch64InstrInfo::findRegisterToSaveLRTo(outliner::Candidate &C) const {
10512 MachineFunction *MF = C.getMF();
10513 const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
10514 const AArch64RegisterInfo *ARI =
10515 static_cast<const AArch64RegisterInfo *>(&TRI);
10516 // Check if there is an available register across the sequence that we can
10517 // use.
10518 for (unsigned Reg : AArch64::GPR64RegClass) {
10519 if (!ARI->isReservedReg(*MF, Reg) &&
10520 Reg != AArch64::LR && // LR is not reserved, but don't use it.
10521 Reg != AArch64::X16 && // X16 is not guaranteed to be preserved.
10522 Reg != AArch64::X17 && // Ditto for X17.
10523 C.isAvailableAcrossAndOutOfSeq(Reg, TRI) &&
10524 C.isAvailableInsideSeq(Reg, TRI))
10525 return Reg;
10526 }
10527 return Register();
10528}
10529
10530static bool
10532 const outliner::Candidate &b) {
10533 const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
10534 const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
10535
10536 return MFIa->getSignReturnAddressCondition() ==
10538}
10539
10540static bool
10542 const outliner::Candidate &b) {
10543 const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
10544 const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
10545
10546 return MFIa->shouldSignWithBKey() == MFIb->shouldSignWithBKey();
10547}
10548
10550 const outliner::Candidate &b) {
10551 const AArch64Subtarget &SubtargetA =
10553 const AArch64Subtarget &SubtargetB =
10554 b.getMF()->getSubtarget<AArch64Subtarget>();
10555 return SubtargetA.hasV8_3aOps() == SubtargetB.hasV8_3aOps();
10556}
10557
10558namespace {
10559struct SPAddSubImmEncoding {
10560 unsigned Opcode;
10561 int64_t Imm;
10562 int64_t Shift;
10563};
10564} // namespace
10565
10566/// Returns true if \p MI is an ADD/SUBXri with an immediate offset that reads
10567/// SP but does not write SP (e.g. "add x0, sp, #48").
10568static bool isSPAddSubImm(const MachineInstr &MI) {
10569 if (MI.getOpcode() != AArch64::ADDXri && MI.getOpcode() != AArch64::SUBXri)
10570 return false;
10571
10572 assert(MI.getNumExplicitOperands() == 4 && "Wrong number of operands");
10573 assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() &&
10574 MI.getOperand(3).isImm() && "Unexpected add/sub immediate operands");
10575
10576 if (MI.getOperand(0).getReg() == AArch64::SP)
10577 return false;
10578 if (MI.getOperand(1).getReg() != AArch64::SP)
10579 return false;
10580
10581 return MI.getOperand(2).isImm();
10582}
10583
10584/// Adjust the signed byte offset of \p MI, which must satisfy isSPAddSubImm,
10585/// by \p Delta and re-encode the result. Returns std::nullopt if the adjusted
10586/// offset is not encodable.
10587static std::optional<SPAddSubImmEncoding>
10588adjustSPAddSubImm(const MachineInstr &MI, int64_t Delta) {
10589 assert(isSPAddSubImm(MI) && "Expected an SP-based add/sub immediate");
10590 bool IsSub = MI.getOpcode() == AArch64::SUBXri;
10591
10592 // ADD/SUBXri encode a 12-bit unsigned immediate with an optional left shift
10593 // which can only be 12.
10594 int64_t ShiftImm = MI.getOperand(3).getImm();
10596 "Unexpected add/sub immediate shift type");
10597 unsigned Shift = AArch64_AM::getShiftValue(ShiftImm);
10598 assert((Shift == 0 || Shift == 12) && "Unexpected add/sub immediate shift");
10599
10600 int64_t Offset = MI.getOperand(2).getImm() << Shift;
10601 if (IsSub)
10602 Offset = -Offset;
10603
10604 // Apply the adjustment and try to re-encode.
10605 int64_t NewOffset = Offset + Delta;
10606 int64_t AbsOffset = std::abs(NewOffset);
10607
10608 SPAddSubImmEncoding Enc;
10609 Enc.Opcode = NewOffset < 0 ? AArch64::SUBXri : AArch64::ADDXri;
10610
10611 // Try to encode as a 12-bit immediate with shift=0 first.
10612 if (AbsOffset <= 0xfff) {
10613 Enc.Imm = AbsOffset;
10615 } else if ((AbsOffset & 0xfff) == 0 && (AbsOffset >> 12) <= 0xfff) {
10616 Enc.Imm = AbsOffset >> 12;
10618 } else {
10619 return std::nullopt;
10620 }
10621
10622 return Enc;
10623}
10624
10625std::optional<std::unique_ptr<outliner::OutlinedFunction>>
10626AArch64InstrInfo::getOutliningCandidateInfo(
10627 const MachineModuleInfo &MMI,
10628 std::vector<outliner::Candidate> &RepeatedSequenceLocs,
10629 unsigned MinRepeats) const {
10630 unsigned SequenceSize = 0;
10631 for (auto &MI : RepeatedSequenceLocs[0])
10632 SequenceSize += getInstSizeInBytes(MI);
10633
10634 unsigned NumBytesToCreateFrame = 0;
10635
10636 // Avoid splitting ADRP ADD/LDR pair into outlined functions.
10637 // These instructions are fused together by the scheduler.
10638 // Any candidate where ADRP is the last instruction should be rejected
10639 // as that will lead to splitting ADRP pair.
10640 MachineInstr &LastMI = RepeatedSequenceLocs[0].back();
10641 MachineInstr &FirstMI = RepeatedSequenceLocs[0].front();
10642 if (LastMI.getOpcode() == AArch64::ADRP &&
10643 (LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_PAGE) != 0 &&
10644 (LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_GOT) != 0) {
10645 return std::nullopt;
10646 }
10647
10648 // Similarly any candidate where the first instruction is ADD/LDR with a
10649 // page offset should be rejected to avoid ADRP splitting.
10650 if ((FirstMI.getOpcode() == AArch64::ADDXri ||
10651 FirstMI.getOpcode() == AArch64::LDRXui) &&
10652 (FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_PAGEOFF) != 0 &&
10653 (FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) != 0) {
10654 return std::nullopt;
10655 }
10656
10657 // We only allow outlining for functions having exactly matching return
10658 // address signing attributes, i.e., all share the same value for the
10659 // attribute "sign-return-address" and all share the same type of key they
10660 // are signed with.
10661 // Additionally we require all functions to simultaneously either support
10662 // v8.3a features or not. Otherwise an outlined function could get signed
10663 // using dedicated v8.3 instructions and a call from a function that doesn't
10664 // support v8.3 instructions would therefore be invalid.
10665 if (std::adjacent_find(
10666 RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
10667 [](const outliner::Candidate &a, const outliner::Candidate &b) {
10668 // Return true if a and b are non-equal w.r.t. return address
10669 // signing or support of v8.3a features
10670 if (outliningCandidatesSigningScopeConsensus(a, b) &&
10671 outliningCandidatesSigningKeyConsensus(a, b) &&
10672 outliningCandidatesV8_3OpsConsensus(a, b)) {
10673 return false;
10674 }
10675 return true;
10676 }) != RepeatedSequenceLocs.end()) {
10677 return std::nullopt;
10678 }
10679
10680 // Since at this point all candidates agree on their return address signing
10681 // picking just one is fine. If the candidate functions potentially sign their
10682 // return addresses, the outlined function should do the same. Note that in
10683 // the case of "sign-return-address"="non-leaf" this is an assumption: It is
10684 // not certainly true that the outlined function will have to sign its return
10685 // address but this decision is made later, when the decision to outline
10686 // has already been made.
10687 // The same holds for the number of additional instructions we need: On
10688 // v8.3a RET can be replaced by RETAA/RETAB and no AUT instruction is
10689 // necessary. However, at this point we don't know if the outlined function
10690 // will have a RET instruction so we assume the worst.
10691 const TargetRegisterInfo &TRI = getRegisterInfo();
10692 // Performing a tail call may require extra checks when PAuth is enabled.
10693 // If PAuth is disabled, set it to zero for uniformity.
10694 unsigned NumBytesToCheckLRInTCEpilogue = 0;
10695 const auto RASignCondition = RepeatedSequenceLocs[0]
10696 .getMF()
10697 ->getInfo<AArch64FunctionInfo>()
10698 ->getSignReturnAddressCondition();
10699 if (RASignCondition != SignReturnAddress::None) {
10700 // Candidates that have Return Address Authentication Hardening enabled are
10701 // discarded.
10702 //
10703 // In its current form, the machine outliner does not preserve X16/X17
10704 // across outlined function calls, even though it should as they are
10705 // caller-saved registers. And since the hardening based on load from the
10706 // return address may clobber one of these registers, if they are alive
10707 // across a call their value would be lost due to the hardening mechanism.
10708 llvm::erase_if(RepeatedSequenceLocs, [](outliner::Candidate &C) {
10709 return C.getMF()
10710 ->getInfo<AArch64FunctionInfo>()
10711 ->shouldHardenSignReturnAddress();
10712 });
10713 // If the sequence doesn't have enough candidates left, then we're done.
10714 if (RepeatedSequenceLocs.size() < MinRepeats)
10715 return std::nullopt;
10716
10717 // One PAC and one AUT instructions
10718 NumBytesToCreateFrame += 8;
10719
10720 // PAuth is enabled - set extra tail call cost, if any.
10721 auto LRCheckMethod = Subtarget.getAuthenticatedLRCheckMethod(
10722 *RepeatedSequenceLocs[0].getMF());
10723 NumBytesToCheckLRInTCEpilogue =
10725 // Checking the authenticated LR value may significantly impact
10726 // SequenceSize, so account for it for more precise results.
10727 if (isTailCallReturnInst(RepeatedSequenceLocs[0].back()))
10728 SequenceSize += NumBytesToCheckLRInTCEpilogue;
10729
10730 // We have to check if sp modifying instructions would get outlined.
10731 // If so we only allow outlining if sp is unchanged overall, so matching
10732 // sub and add instructions are okay to outline, all other sp modifications
10733 // are not
10734 auto hasIllegalSPModification = [&TRI](outliner::Candidate &C) {
10735 int SPValue = 0;
10736 for (auto &MI : C) {
10737 if (MI.modifiesRegister(AArch64::SP, &TRI)) {
10738 switch (MI.getOpcode()) {
10739 case AArch64::ADDXri:
10740 case AArch64::ADDWri:
10741 assert(MI.getNumOperands() == 4 && "Wrong number of operands");
10742 assert(MI.getOperand(2).isImm() &&
10743 "Expected operand to be immediate");
10744 assert(MI.getOperand(1).isReg() &&
10745 "Expected operand to be a register");
10746 // Check if the add just increments sp. If so, we search for
10747 // matching sub instructions that decrement sp. If not, the
10748 // modification is illegal
10749 if (MI.getOperand(1).getReg() == AArch64::SP)
10750 SPValue += MI.getOperand(2).getImm();
10751 else
10752 return true;
10753 break;
10754 case AArch64::SUBXri:
10755 case AArch64::SUBWri:
10756 assert(MI.getNumOperands() == 4 && "Wrong number of operands");
10757 assert(MI.getOperand(2).isImm() &&
10758 "Expected operand to be immediate");
10759 assert(MI.getOperand(1).isReg() &&
10760 "Expected operand to be a register");
10761 // Check if the sub just decrements sp. If so, we search for
10762 // matching add instructions that increment sp. If not, the
10763 // modification is illegal
10764 if (MI.getOperand(1).getReg() == AArch64::SP)
10765 SPValue -= MI.getOperand(2).getImm();
10766 else
10767 return true;
10768 break;
10769 default:
10770 return true;
10771 }
10772 }
10773 }
10774 if (SPValue)
10775 return true;
10776 return false;
10777 };
10778 // Remove candidates with illegal stack modifying instructions
10779 llvm::erase_if(RepeatedSequenceLocs, hasIllegalSPModification);
10780
10781 // If the sequence doesn't have enough candidates left, then we're done.
10782 if (RepeatedSequenceLocs.size() < MinRepeats)
10783 return std::nullopt;
10784 }
10785
10786 // Properties about candidate MBBs that hold for all of them.
10787 unsigned FlagsSetInAll = 0xF;
10788
10789 // Compute liveness information for each candidate, and set FlagsSetInAll.
10790 for (outliner::Candidate &C : RepeatedSequenceLocs)
10791 FlagsSetInAll &= C.Flags;
10792
10793 unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back().getOpcode();
10794
10795 // Helper lambda which sets call information for every candidate.
10796 auto SetCandidateCallInfo =
10797 [&RepeatedSequenceLocs](unsigned CallID, unsigned NumBytesForCall) {
10798 for (outliner::Candidate &C : RepeatedSequenceLocs)
10799 C.setCallInfo(CallID, NumBytesForCall);
10800 };
10801
10802 unsigned FrameID = MachineOutlinerDefault;
10803 NumBytesToCreateFrame += 4;
10804
10805 bool HasBTI = any_of(RepeatedSequenceLocs, [](outliner::Candidate &C) {
10806 return C.getMF()->getInfo<AArch64FunctionInfo>()->branchTargetEnforcement();
10807 });
10808
10809 // We check to see if CFI Instructions are present, and if they are
10810 // we find the number of CFI Instructions in the candidates.
10811 unsigned CFICount = 0;
10812 for (auto &I : RepeatedSequenceLocs[0]) {
10813 if (I.isCFIInstruction())
10814 CFICount++;
10815 }
10816
10817 // We compare the number of found CFI Instructions to the number of CFI
10818 // instructions in the parent function for each candidate. We must check this
10819 // since if we outline one of the CFI instructions in a function, we have to
10820 // outline them all for correctness. If we do not, the address offsets will be
10821 // incorrect between the two sections of the program.
10822 for (outliner::Candidate &C : RepeatedSequenceLocs) {
10823 std::vector<MCCFIInstruction> CFIInstructions =
10824 C.getMF()->getFrameInstructions();
10825
10826 if (CFICount > 0 && CFICount != CFIInstructions.size())
10827 return std::nullopt;
10828 }
10829
10830 // Returns true if an instructions is safe to fix up, false otherwise.
10831 auto IsSafeToFixup = [this, &TRI](MachineInstr &MI) {
10832 if (MI.isCall())
10833 return true;
10834
10835 if (!MI.modifiesRegister(AArch64::SP, &TRI) &&
10836 !MI.readsRegister(AArch64::SP, &TRI))
10837 return true;
10838
10839 // Any modification of SP will break our code to save/restore LR.
10840 // FIXME: We could handle some instructions which add a constant
10841 // offset to SP, with a bit more work.
10842 if (MI.modifiesRegister(AArch64::SP, &TRI))
10843 return false;
10844
10845 // At this point, we have a stack instruction that we might need to
10846 // fix up. We'll handle it if it's a load or store.
10847 if (MI.mayLoadOrStore()) {
10848 const MachineOperand *Base; // Filled with the base operand of MI.
10849 int64_t Offset; // Filled with the offset of MI.
10850 bool OffsetIsScalable;
10851
10852 // Does it allow us to offset the base operand and is the base the
10853 // register SP?
10854 if (!getMemOperandWithOffset(MI, Base, Offset, OffsetIsScalable) ||
10855 !Base->isReg() || Base->getReg() != AArch64::SP)
10856 return false;
10857
10858 // Fixe-up code below assumes bytes.
10859 if (OffsetIsScalable)
10860 return false;
10861
10862 // Find the minimum/maximum offset for this instruction and check
10863 // if fixing it up would be in range.
10864 int64_t MinOffset,
10865 MaxOffset; // Unscaled offsets for the instruction.
10866 // The scale to multiply the offsets by.
10867 TypeSize Scale(0U, false), DummyWidth(0U, false);
10868 getMemOpInfo(MI.getOpcode(), Scale, DummyWidth, MinOffset, MaxOffset);
10869
10870 Offset += 16; // Update the offset to what it would be if we outlined.
10871 if (Offset < MinOffset * (int64_t)Scale.getFixedValue() ||
10872 Offset > MaxOffset * (int64_t)Scale.getFixedValue())
10873 return false;
10874
10875 // It's in range, so we can outline it.
10876 return true;
10877 }
10878
10879 if (isSPAddSubImm(MI))
10880 return adjustSPAddSubImm(MI, 16).has_value();
10881
10882 // FIXME: Add handling for other SP-based address calculations that can be
10883 // adjusted after outlining.
10884 return false;
10885 };
10886
10887 // True if it's possible to fix up each stack instruction in this sequence.
10888 // Important for frames/call variants that modify the stack.
10889 bool AllStackInstrsSafe =
10890 llvm::all_of(RepeatedSequenceLocs[0], IsSafeToFixup);
10891
10892 // If the last instruction in any candidate is a terminator, then we should
10893 // tail call all of the candidates.
10894 if (RepeatedSequenceLocs[0].back().isTerminator()) {
10895 FrameID = MachineOutlinerTailCall;
10896 NumBytesToCreateFrame = 0;
10897 unsigned NumBytesForCall = 4 + NumBytesToCheckLRInTCEpilogue;
10898 SetCandidateCallInfo(MachineOutlinerTailCall, NumBytesForCall);
10899 }
10900
10901 else if (LastInstrOpcode == AArch64::BL ||
10902 ((LastInstrOpcode == AArch64::BLR ||
10903 LastInstrOpcode == AArch64::BLRNoIP) &&
10904 !HasBTI)) {
10905 // FIXME: Do we need to check if the code after this uses the value of LR?
10906 FrameID = MachineOutlinerThunk;
10907 NumBytesToCreateFrame = NumBytesToCheckLRInTCEpilogue;
10908 SetCandidateCallInfo(MachineOutlinerThunk, 4);
10909 }
10910
10911 else {
10912 // We need to decide how to emit calls + frames. We can always emit the same
10913 // frame if we don't need to save to the stack. If we have to save to the
10914 // stack, then we need a different frame.
10915 unsigned NumBytesNoStackCalls = 0;
10916 std::vector<outliner::Candidate> CandidatesWithoutStackFixups;
10917
10918 // Check if we have to save LR.
10919 for (outliner::Candidate &C : RepeatedSequenceLocs) {
10920 bool LRAvailable =
10922 ? C.isAvailableAcrossAndOutOfSeq(AArch64::LR, TRI)
10923 : true;
10924 // If we have a noreturn caller, then we're going to be conservative and
10925 // say that we have to save LR. If we don't have a ret at the end of the
10926 // block, then we can't reason about liveness accurately.
10927 //
10928 // FIXME: We can probably do better than always disabling this in
10929 // noreturn functions by fixing up the liveness info.
10930 bool IsNoReturn =
10931 C.getMF()->getFunction().hasFnAttribute(Attribute::NoReturn);
10932
10933 // Is LR available? If so, we don't need a save.
10934 if (LRAvailable && !IsNoReturn) {
10935 NumBytesNoStackCalls += 4;
10936 C.setCallInfo(MachineOutlinerNoLRSave, 4);
10937 CandidatesWithoutStackFixups.push_back(C);
10938 }
10939
10940 // Is an unused register available? If so, we won't modify the stack, so
10941 // we can outline with the same frame type as those that don't save LR.
10942 else if (findRegisterToSaveLRTo(C)) {
10943 NumBytesNoStackCalls += 12;
10944 C.setCallInfo(MachineOutlinerRegSave, 12);
10945 CandidatesWithoutStackFixups.push_back(C);
10946 }
10947
10948 // Is SP used in the sequence at all? If not, we don't have to modify
10949 // the stack, so we are guaranteed to get the same frame.
10950 else if (C.isAvailableInsideSeq(AArch64::SP, TRI)) {
10951 NumBytesNoStackCalls += 12;
10952 C.setCallInfo(MachineOutlinerDefault, 12);
10953 CandidatesWithoutStackFixups.push_back(C);
10954 }
10955
10956 // If we outline this, we need to modify the stack. Pretend we don't
10957 // outline this by saving all of its bytes.
10958 else {
10959 NumBytesNoStackCalls += SequenceSize;
10960 }
10961 }
10962
10963 // If there are no places where we have to save LR, then note that we
10964 // don't have to update the stack. Otherwise, give every candidate the
10965 // default call type, as long as it's safe to do so.
10966 if (!AllStackInstrsSafe ||
10967 NumBytesNoStackCalls <= RepeatedSequenceLocs.size() * 12) {
10968 RepeatedSequenceLocs = CandidatesWithoutStackFixups;
10969 FrameID = MachineOutlinerNoLRSave;
10970 if (RepeatedSequenceLocs.size() < MinRepeats)
10971 return std::nullopt;
10972 } else {
10973 SetCandidateCallInfo(MachineOutlinerDefault, 12);
10974
10975 // Bugzilla ID: 46767
10976 // TODO: Check if fixing up the stack more than once is safe so we can
10977 // outline these.
10978 //
10979 // An outline resulting in a caller that requires stack fixups at the
10980 // callsite to a callee that also requires stack fixups can happen when
10981 // there are no available registers at the candidate callsite for a
10982 // candidate that itself also has calls.
10983 //
10984 // In other words if function_containing_sequence in the following pseudo
10985 // assembly requires that we save LR at the point of the call, but there
10986 // are no available registers: in this case we save using SP and as a
10987 // result the SP offsets requires stack fixups by multiples of 16.
10988 //
10989 // function_containing_sequence:
10990 // ...
10991 // save LR to SP <- Requires stack instr fixups in OUTLINED_FUNCTION_N
10992 // call OUTLINED_FUNCTION_N
10993 // restore LR from SP
10994 // ...
10995 //
10996 // OUTLINED_FUNCTION_N:
10997 // save LR to SP <- Requires stack instr fixups in OUTLINED_FUNCTION_N
10998 // ...
10999 // bl foo
11000 // restore LR from SP
11001 // ret
11002 //
11003 // Because the code to handle more than one stack fixup does not
11004 // currently have the proper checks for legality, these cases will assert
11005 // in the AArch64 MachineOutliner. This is because the code to do this
11006 // needs more hardening, testing, better checks that generated code is
11007 // legal, etc and because it is only verified to handle a single pass of
11008 // stack fixup.
11009 //
11010 // The assert happens in AArch64InstrInfo::buildOutlinedFrame to catch
11011 // these cases until they are known to be handled. Bugzilla 46767 is
11012 // referenced in comments at the assert site.
11013 //
11014 // To avoid asserting (or generating non-legal code on noassert builds)
11015 // we remove all candidates which would need more than one stack fixup by
11016 // pruning the cases where the candidate has calls while also having no
11017 // available LR and having no available general purpose registers to copy
11018 // LR to (ie one extra stack save/restore).
11019 //
11020 if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) {
11021 erase_if(RepeatedSequenceLocs, [this, &TRI](outliner::Candidate &C) {
11022 auto IsCall = [](const MachineInstr &MI) { return MI.isCall(); };
11023 return (llvm::any_of(C, IsCall)) &&
11024 (!C.isAvailableAcrossAndOutOfSeq(AArch64::LR, TRI) ||
11025 !findRegisterToSaveLRTo(C));
11026 });
11027 }
11028 }
11029
11030 // If we dropped all of the candidates, bail out here.
11031 if (RepeatedSequenceLocs.size() < MinRepeats)
11032 return std::nullopt;
11033 }
11034
11035 // Does every candidate's MBB contain a call? If so, then we might have a call
11036 // in the range.
11037 if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) {
11038 // Check if the range contains a call. These require a save + restore of the
11039 // link register.
11040 outliner::Candidate &FirstCand = RepeatedSequenceLocs[0];
11041 bool ModStackToSaveLR = false;
11042 if (any_of(drop_end(FirstCand),
11043 [](const MachineInstr &MI) { return MI.isCall(); }))
11044 ModStackToSaveLR = true;
11045
11046 // Handle the last instruction separately. If this is a tail call, then the
11047 // last instruction is a call. We don't want to save + restore in this case.
11048 // However, it could be possible that the last instruction is a call without
11049 // it being valid to tail call this sequence. We should consider this as
11050 // well.
11051 else if (FrameID != MachineOutlinerThunk &&
11052 FrameID != MachineOutlinerTailCall && FirstCand.back().isCall())
11053 ModStackToSaveLR = true;
11054
11055 if (ModStackToSaveLR) {
11056 // We can't fix up the stack. Bail out.
11057 if (!AllStackInstrsSafe)
11058 return std::nullopt;
11059
11060 // Save + restore LR.
11061 NumBytesToCreateFrame += 8;
11062
11063 // Add the extra mov if we will save a frame record instead of just LR.
11065 RepeatedSequenceLocs, TRI))
11066 NumBytesToCreateFrame += 4;
11067 }
11068 }
11069
11070 // If we have CFI instructions, we can only outline if the outlined section
11071 // can be a tail call
11072 if (FrameID != MachineOutlinerTailCall && CFICount > 0)
11073 return std::nullopt;
11074
11075 return std::make_unique<outliner::OutlinedFunction>(
11076 RepeatedSequenceLocs, SequenceSize, NumBytesToCreateFrame, FrameID);
11077}
11078
11079void AArch64InstrInfo::mergeOutliningCandidateAttributes(
11080 Function &F, std::vector<outliner::Candidate> &Candidates) const {
11081 // If a bunch of candidates reach this point they must agree on their return
11082 // address signing. It is therefore enough to just consider the signing
11083 // behaviour of one of them
11084 const auto &CFn = Candidates.front().getMF()->getFunction();
11085
11086 if (CFn.hasFnAttribute("ptrauth-returns"))
11087 F.addFnAttr(CFn.getFnAttribute("ptrauth-returns"));
11088 if (CFn.hasFnAttribute("ptrauth-auth-traps"))
11089 F.addFnAttr(CFn.getFnAttribute("ptrauth-auth-traps"));
11090 // Since all candidates belong to the same module, just copy the
11091 // function-level attributes of an arbitrary function.
11092 if (CFn.hasFnAttribute("sign-return-address"))
11093 F.addFnAttr(CFn.getFnAttribute("sign-return-address"));
11094 if (CFn.hasFnAttribute("sign-return-address-key"))
11095 F.addFnAttr(CFn.getFnAttribute("sign-return-address-key"));
11096 // The "sign-return-address-harden" attribute is not included because no
11097 // candidate is supposed to have hardening enabled.
11098 assert(llvm::none_of(Candidates, [](const outliner::Candidate &C) {
11099 return C.getMF()
11100 ->getInfo<AArch64FunctionInfo>()
11101 ->shouldHardenSignReturnAddress();
11102 }));
11103
11104 AArch64GenInstrInfo::mergeOutliningCandidateAttributes(F, Candidates);
11105}
11106
11107bool AArch64InstrInfo::isFunctionSafeToOutlineFrom(
11108 MachineFunction &MF, bool OutlineFromLinkOnceODRs) const {
11110 OutlineFromLinkOnceODRs))
11111 return false;
11112
11113 // Outlining from functions with redzones is unsafe since the outliner may
11114 // modify the stack. Check if hasRedZone is true or unknown; if yes, don't
11115 // outline from it.
11116 AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
11117 if (!AFI || AFI->hasRedZone().value_or(true))
11118 return false;
11119
11120 // FIXME: Determine whether it is safe to outline from functions which contain
11121 // streaming-mode changes. We may need to ensure any smstart/smstop pairs are
11122 // outlined together and ensure it is safe to outline with async unwind info,
11123 // required for saving & restoring VG around calls.
11124 if (AFI->hasStreamingModeChanges())
11125 return false;
11126
11127 // FIXME: Teach the outliner to generate/handle Windows unwind info.
11128 if (MF.usesWindowsUnwindInfo())
11129 return false;
11130
11131 // It's safe to outline from MF.
11132 return true;
11133}
11134
11136AArch64InstrInfo::getOutlinableRanges(MachineBasicBlock &MBB,
11137 unsigned &Flags) const {
11139 "Must track liveness!");
11141 std::pair<MachineBasicBlock::iterator, MachineBasicBlock::iterator>>
11142 Ranges;
11143 // According to the AArch64 Procedure Call Standard, the following are
11144 // undefined on entry/exit from a function call:
11145 //
11146 // * Registers x16, x17, (and thus w16, w17)
11147 // * Condition codes (and thus the NZCV register)
11148 //
11149 // If any of these registers are used inside or live across an outlined
11150 // function, then they may be modified later, either by the compiler or
11151 // some other tool (like the linker).
11152 //
11153 // To avoid outlining in these situations, partition each block into ranges
11154 // where these registers are dead. We will only outline from those ranges.
11155 LiveRegUnits LRU(getRegisterInfo());
11156 auto AreAllUnsafeRegsDead = [&LRU]() {
11157 return LRU.available(AArch64::W16) && LRU.available(AArch64::W17) &&
11158 LRU.available(AArch64::NZCV);
11159 };
11160
11161 // We need to know if LR is live across an outlining boundary later on in
11162 // order to decide how we'll create the outlined call, frame, etc.
11163 //
11164 // It's pretty expensive to check this for *every candidate* within a block.
11165 // That's some potentially n^2 behaviour, since in the worst case, we'd need
11166 // to compute liveness from the end of the block for O(n) candidates within
11167 // the block.
11168 //
11169 // So, to improve the average case, let's keep track of liveness from the end
11170 // of the block to the beginning of *every outlinable range*. If we know that
11171 // LR is available in every range we could outline from, then we know that
11172 // we don't need to check liveness for any candidate within that range.
11173 bool LRAvailableEverywhere = true;
11174 // Compute liveness bottom-up.
11175 LRU.addLiveOuts(MBB);
11176 // Update flags that require info about the entire MBB.
11177 auto UpdateWholeMBBFlags = [&Flags](const MachineInstr &MI) {
11178 if (MI.isCall() && !MI.isTerminator())
11180 };
11181 // Range: [RangeBegin, RangeEnd)
11182 MachineBasicBlock::instr_iterator RangeBegin, RangeEnd;
11183 unsigned RangeLen;
11184 auto CreateNewRangeStartingAt =
11185 [&RangeBegin, &RangeEnd,
11186 &RangeLen](MachineBasicBlock::instr_iterator NewBegin) {
11187 RangeBegin = NewBegin;
11188 RangeEnd = std::next(RangeBegin);
11189 RangeLen = 0;
11190 };
11191 auto SaveRangeIfNonEmpty = [&RangeLen, &Ranges, &RangeBegin, &RangeEnd]() {
11192 // At least one unsafe register is not dead. We do not want to outline at
11193 // this point. If it is long enough to outline from and does not cross a
11194 // bundle boundary, save the range [RangeBegin, RangeEnd).
11195 if (RangeLen <= 1)
11196 return;
11197 if (!RangeBegin.isEnd() && RangeBegin->isBundledWithPred())
11198 return;
11199 if (!RangeEnd.isEnd() && RangeEnd->isBundledWithPred())
11200 return;
11201 Ranges.emplace_back(RangeBegin, RangeEnd);
11202 };
11203 // Find the first point where all unsafe registers are dead.
11204 // FIND: <safe instr> <-- end of first potential range
11205 // SKIP: <unsafe def>
11206 // SKIP: ... everything between ...
11207 // SKIP: <unsafe use>
11208 auto FirstPossibleEndPt = MBB.instr_rbegin();
11209 for (; FirstPossibleEndPt != MBB.instr_rend(); ++FirstPossibleEndPt) {
11210 if (!FirstPossibleEndPt->isDebugInstr())
11211 LRU.stepBackward(*FirstPossibleEndPt);
11212 // Update flags that impact how we outline across the entire block,
11213 // regardless of safety.
11214 UpdateWholeMBBFlags(*FirstPossibleEndPt);
11215 if (AreAllUnsafeRegsDead())
11216 break;
11217 }
11218 // If we exhausted the entire block, we have no safe ranges to outline.
11219 if (FirstPossibleEndPt == MBB.instr_rend())
11220 return Ranges;
11221 // Current range.
11222 CreateNewRangeStartingAt(FirstPossibleEndPt->getIterator());
11223 // StartPt points to the first place where all unsafe registers
11224 // are dead (if there is any such point). Begin partitioning the MBB into
11225 // ranges.
11226 // Pseudo probes are ordinary instructions to the mapper, so only skip debug
11227 // instructions here.
11228 for (auto &MI : instructionsWithoutDebug(FirstPossibleEndPt, MBB.instr_rend(),
11229 /*SkipPseudoOp=*/false)) {
11230 LRU.stepBackward(MI);
11231 UpdateWholeMBBFlags(MI);
11232 if (!AreAllUnsafeRegsDead()) {
11233 SaveRangeIfNonEmpty();
11234 CreateNewRangeStartingAt(MI.getIterator());
11235 continue;
11236 }
11237 LRAvailableEverywhere &= LRU.available(AArch64::LR);
11238 // Pseudo probes count because the mapper treats them as ordinary
11239 // instructions.
11240 RangeBegin = MI.getIterator();
11241 ++RangeLen;
11242 }
11243 // Above loop misses the last (or only) range. If we are still safe, then
11244 // let's save the range.
11245 if (AreAllUnsafeRegsDead())
11246 SaveRangeIfNonEmpty();
11247 if (Ranges.empty())
11248 return Ranges;
11249 // We found the ranges bottom-up. Mapping expects the top-down. Reverse
11250 // the order.
11251 std::reverse(Ranges.begin(), Ranges.end());
11252 // If there is at least one outlinable range where LR is unavailable
11253 // somewhere, remember that.
11254 if (!LRAvailableEverywhere)
11256 return Ranges;
11257}
11258
11260AArch64InstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
11262 unsigned Flags) const {
11263 MachineInstr &MI = *MIT;
11264
11265 // Don't outline anything used for return address signing. The outlined
11266 // function will get signed later if needed
11267 switch (MI.getOpcode()) {
11268 case AArch64::PACM:
11269 case AArch64::PACIASP:
11270 case AArch64::PACIBSP:
11271 case AArch64::PACIASPPC:
11272 case AArch64::PACIBSPPC:
11273 case AArch64::AUTIASP:
11274 case AArch64::AUTIBSP:
11275 case AArch64::AUTIASPPCi:
11276 case AArch64::AUTIASPPCr:
11277 case AArch64::AUTIBSPPCi:
11278 case AArch64::AUTIBSPPCr:
11279 case AArch64::RETAA:
11280 case AArch64::RETAB:
11281 case AArch64::RETAASPPCi:
11282 case AArch64::RETAASPPCr:
11283 case AArch64::RETABSPPCi:
11284 case AArch64::RETABSPPCr:
11285 case AArch64::EMITBKEY:
11286 case AArch64::PAUTH_PROLOGUE:
11287 case AArch64::PAUTH_EPILOGUE:
11288 case AArch64::PAUTH_EPILOGUE_ENTRY_SP:
11290 }
11291
11292 // We can only outline these if we will tail call the outlined function, or
11293 // fix up the CFI offsets. Currently, CFI instructions are outlined only if
11294 // in a tail call.
11295 //
11296 // FIXME: If the proper fixups for the offset are implemented, this should be
11297 // possible.
11298 if (MI.isCFIInstruction())
11300
11301 // Is this a terminator for a basic block?
11302 if (MI.isTerminator())
11303 // TargetInstrInfo::getOutliningType has already filtered out anything
11304 // that would break this, so we can allow it here.
11306
11307 // Make sure none of the operands are un-outlinable.
11308 for (const MachineOperand &MOP : MI.operands()) {
11309 // A check preventing CFI indices was here before, but only CFI
11310 // instructions should have those.
11311 assert(!MOP.isCFIIndex());
11312
11313 // If it uses LR or W30 explicitly, then don't touch it.
11314 if (MOP.isReg() && !MOP.isImplicit() &&
11315 (MOP.getReg() == AArch64::LR || MOP.getReg() == AArch64::W30))
11317 }
11318
11319 // Special cases for instructions that can always be outlined, but will fail
11320 // the later tests. e.g, ADRPs, which are PC-relative use LR, but can always
11321 // be outlined because they don't require a *specific* value to be in LR.
11322 if (MI.getOpcode() == AArch64::ADRP)
11324
11325 // If MI is a call we might be able to outline it. We don't want to outline
11326 // any calls that rely on the position of items on the stack. When we outline
11327 // something containing a call, we have to emit a save and restore of LR in
11328 // the outlined function. Currently, this always happens by saving LR to the
11329 // stack. Thus, if we outline, say, half the parameters for a function call
11330 // plus the call, then we'll break the callee's expectations for the layout
11331 // of the stack.
11332 //
11333 // FIXME: Allow calls to functions which construct a stack frame, as long
11334 // as they don't access arguments on the stack.
11335 // FIXME: Figure out some way to analyze functions defined in other modules.
11336 // We should be able to compute the memory usage based on the IR calling
11337 // convention, even if we can't see the definition.
11338 if (MI.isCall()) {
11339 // Get the function associated with the call. Look at each operand and find
11340 // the one that represents the callee and get its name.
11341 const Function *Callee = nullptr;
11342 for (const MachineOperand &MOP : MI.operands()) {
11343 if (MOP.isGlobal()) {
11344 Callee = dyn_cast<Function>(MOP.getGlobal());
11345 break;
11346 }
11347 }
11348
11349 // Never outline calls to mcount. There isn't any rule that would require
11350 // this, but the Linux kernel's "ftrace" feature depends on it.
11351 if (Callee && Callee->getName() == "\01_mcount")
11353
11354 // If we don't know anything about the callee, assume it depends on the
11355 // stack layout of the caller. In that case, it's only legal to outline
11356 // as a tail-call. Explicitly list the call instructions we know about so we
11357 // don't get unexpected results with call pseudo-instructions.
11358 auto UnknownCallOutlineType = outliner::InstrType::Illegal;
11359 if (MI.getOpcode() == AArch64::BLR ||
11360 MI.getOpcode() == AArch64::BLRNoIP || MI.getOpcode() == AArch64::BL)
11361 UnknownCallOutlineType = outliner::InstrType::LegalTerminator;
11362
11363 if (!Callee)
11364 return UnknownCallOutlineType;
11365
11366 // We have a function we have information about. Check it if it's something
11367 // can safely outline.
11368 MachineFunction *CalleeMF = MMI.getMachineFunction(*Callee);
11369
11370 // We don't know what's going on with the callee at all. Don't touch it.
11371 if (!CalleeMF)
11372 return UnknownCallOutlineType;
11373
11374 // Check if we know anything about the callee saves on the function. If we
11375 // don't, then don't touch it, since that implies that we haven't
11376 // computed anything about its stack frame yet.
11377 MachineFrameInfo &MFI = CalleeMF->getFrameInfo();
11378 if (!MFI.isCalleeSavedInfoValid() || MFI.getStackSize() > 0 ||
11379 MFI.getNumObjects() > 0)
11380 return UnknownCallOutlineType;
11381
11382 // At this point, we can say that CalleeMF ought to not pass anything on the
11383 // stack. Therefore, we can outline it.
11385 }
11386
11387 // Don't touch the link register or W30.
11388 if (MI.readsRegister(AArch64::W30, &getRegisterInfo()) ||
11389 MI.modifiesRegister(AArch64::W30, &getRegisterInfo()))
11391
11392 // Don't outline BTI instructions, because that will prevent the outlining
11393 // site from being indirectly callable.
11394 if (hasBTISemantics(MI))
11396
11398}
11399
11400void AArch64InstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const {
11401 for (MachineInstr &MI : MBB) {
11402 const MachineOperand *Base;
11403 TypeSize Width(0, false);
11404 int64_t Offset;
11405 bool OffsetIsScalable;
11406
11407 // Is this a load or store with an immediate offset with SP as the base?
11408 if (MI.mayLoadOrStore() &&
11409 getMemOperandWithOffsetWidth(MI, Base, Offset, OffsetIsScalable,
11410 Width) &&
11411 Base->isReg() && Base->getReg() == AArch64::SP) {
11412 TypeSize Scale(0U, false);
11413 int64_t Dummy1, Dummy2;
11414
11415 MachineOperand &StackOffsetOperand =
11417 assert(StackOffsetOperand.isImm() && "Stack offset wasn't immediate!");
11418 getMemOpInfo(MI.getOpcode(), Scale, Width, Dummy1, Dummy2);
11419 assert(Scale != 0 && "Unexpected opcode!");
11420 assert(!OffsetIsScalable && "Expected offset to be a byte offset");
11421
11422 // We've pushed the return address to the stack, so add 16 to the offset.
11423 // This is safe, since we already checked if it would overflow when we
11424 // checked if this instruction was legal to outline.
11425 int64_t NewImm = (Offset + 16) / (int64_t)Scale.getFixedValue();
11426 StackOffsetOperand.setImm(NewImm);
11427 continue;
11428 }
11429
11430 if (isSPAddSubImm(MI)) {
11431 auto Enc = adjustSPAddSubImm(MI, 16);
11432 assert(Enc && "Unencodable SP add/sub should not have been outlined");
11433 MI.setDesc(get(Enc->Opcode));
11434 MI.getOperand(2).setImm(Enc->Imm);
11435 MI.getOperand(3).setImm(Enc->Shift);
11436 }
11437 }
11438}
11439
11441 const AArch64InstrInfo *TII,
11442 bool ShouldSignReturnAddr) {
11443 if (!ShouldSignReturnAddr)
11444 return;
11445
11446 BuildMI(MBB, MBB.begin(), DebugLoc(), TII->get(AArch64::PAUTH_PROLOGUE))
11448 TII->createPauthEpilogueInstr(MBB, DebugLoc());
11449}
11450
11451void AArch64InstrInfo::buildOutlinedFrame(
11453 const outliner::OutlinedFunction &OF) const {
11454
11455 AArch64FunctionInfo *FI = MF.getInfo<AArch64FunctionInfo>();
11456
11457 if (OF.FrameConstructionID == MachineOutlinerTailCall)
11458 FI->setOutliningStyle("Tail Call");
11459 else if (OF.FrameConstructionID == MachineOutlinerThunk) {
11460 // For thunk outlining, rewrite the last instruction from a call to a
11461 // tail-call.
11462 MachineInstr *Call = &*--MBB.instr_end();
11463 unsigned TailOpcode;
11464 if (Call->getOpcode() == AArch64::BL) {
11465 TailOpcode = AArch64::TCRETURNdi;
11466 } else {
11467 assert(Call->getOpcode() == AArch64::BLR ||
11468 Call->getOpcode() == AArch64::BLRNoIP);
11469 TailOpcode = AArch64::TCRETURNriALL;
11470 }
11471 MachineInstr *TC = BuildMI(MF, DebugLoc(), get(TailOpcode))
11472 .add(Call->getOperand(0))
11473 .addImm(0);
11474 MBB.insert(MBB.end(), TC);
11476
11477 FI->setOutliningStyle("Thunk");
11478 }
11479
11480 bool IsLeafFunction = true;
11481
11482 // Is there a call in the outlined range?
11483 auto IsNonTailCall = [](const MachineInstr &MI) {
11484 return MI.isCall() && !MI.isReturn();
11485 };
11486
11487 if (llvm::any_of(MBB.instrs(), IsNonTailCall)) {
11488 // Fix up the instructions in the range, since we're going to modify the
11489 // stack.
11490
11491 // Bugzilla ID: 46767
11492 // TODO: Check if fixing up twice is safe so we can outline these.
11493 assert(OF.FrameConstructionID != MachineOutlinerDefault &&
11494 "Can only fix up stack references once");
11495 fixupPostOutline(MBB);
11496
11497 IsLeafFunction = false;
11498
11499 // LR has to be a live in so that we can save it.
11500 if (!MBB.isLiveIn(AArch64::LR))
11501 MBB.addLiveIn(AArch64::LR);
11502
11505
11506 if (OF.FrameConstructionID == MachineOutlinerTailCall ||
11507 OF.FrameConstructionID == MachineOutlinerThunk)
11508 Et = std::prev(MBB.end());
11509
11510 // There is a call in the range, so we must save LR. Save it as part of a
11511 // frame record when that gives us a smaller compact unwind encoding.
11513 // FP is saved here, so it must be live-in.
11514 if (!MBB.isLiveIn(AArch64::FP))
11515 MBB.addLiveIn(AArch64::FP);
11516
11517 // stp x29, x30, [sp, #-16]! (the pre-index imm is scaled by 8: -2 * 8)
11518 MachineInstr *STPXpre = BuildMI(MF, DebugLoc(), get(AArch64::STPXpre))
11519 .addReg(AArch64::SP, RegState::Define)
11520 .addReg(AArch64::FP)
11521 .addReg(AArch64::LR)
11522 .addReg(AArch64::SP)
11523 .addImm(-2);
11524 It = MBB.insert(It, STPXpre);
11525
11526 // mov x29, sp (add x29, sp, #0), so x29 points at the frame record.
11527 MachineInstr *SetFP = BuildMI(MF, DebugLoc(), get(AArch64::ADDXri))
11528 .addReg(AArch64::FP, RegState::Define)
11529 .addReg(AArch64::SP)
11530 .addImm(0)
11531 .addImm(0);
11532 MBB.insertAfter(It, SetFP);
11533
11534 // Describe the frame record with FP as the CFA. The encoder needs all
11535 // three to pick FRAME. No need to check for unwind info here: we only
11536 // get here if the function has it.
11537 CFIInstBuilder CFIBuilder(MBB, std::next(SetFP->getIterator()),
11539 CFIBuilder.buildDefCFA(AArch64::FP, 16);
11540 CFIBuilder.buildOffset(AArch64::LR, -8);
11541 CFIBuilder.buildOffset(AArch64::FP, -16);
11542
11543 // ldp x29, x30, [sp], #16
11544 MachineInstr *LDPXpost = BuildMI(MF, DebugLoc(), get(AArch64::LDPXpost))
11545 .addReg(AArch64::SP, RegState::Define)
11546 .addReg(AArch64::FP, RegState::Define)
11547 .addReg(AArch64::LR, RegState::Define)
11548 .addReg(AArch64::SP)
11549 .addImm(2);
11550 Et = MBB.insert(Et, LDPXpost);
11551 } else {
11552 // Insert a save before the outlined region
11553 MachineInstr *STRXpre = BuildMI(MF, DebugLoc(), get(AArch64::STRXpre))
11554 .addReg(AArch64::SP, RegState::Define)
11555 .addReg(AArch64::LR)
11556 .addReg(AArch64::SP)
11557 .addImm(-16);
11558 It = MBB.insert(It, STRXpre);
11559
11560 if (MF.getInfo<AArch64FunctionInfo>()->needsDwarfUnwindInfo(MF)) {
11561 CFIInstBuilder CFIBuilder(MBB, It, MachineInstr::FrameSetup);
11562
11563 // Add a CFI saying the stack was moved 16 B down.
11564 CFIBuilder.buildDefCFAOffset(16);
11565
11566 // Add a CFI saying that the LR that we want to find is now 16 B higher
11567 // than before.
11568 CFIBuilder.buildOffset(AArch64::LR, -16);
11569 }
11570
11571 // Insert a restore before the terminator for the function.
11572 MachineInstr *LDRXpost = BuildMI(MF, DebugLoc(), get(AArch64::LDRXpost))
11573 .addReg(AArch64::SP, RegState::Define)
11574 .addReg(AArch64::LR, RegState::Define)
11575 .addReg(AArch64::SP)
11576 .addImm(16);
11577 Et = MBB.insert(Et, LDRXpost);
11578 }
11579 }
11580
11581 auto RASignCondition = FI->getSignReturnAddressCondition();
11582 bool ShouldSignReturnAddr = AArch64FunctionInfo::shouldSignReturnAddress(
11583 RASignCondition, !IsLeafFunction);
11584
11585 // If this is a tail call outlined function, then there's already a return.
11586 if (OF.FrameConstructionID == MachineOutlinerTailCall ||
11587 OF.FrameConstructionID == MachineOutlinerThunk) {
11588 signOutlinedFunction(MF, MBB, this, ShouldSignReturnAddr);
11589 return;
11590 }
11591
11592 // It's not a tail call, so we have to insert the return ourselves.
11593
11594 // LR has to be a live in so that we can return to it.
11595 if (!MBB.isLiveIn(AArch64::LR))
11596 MBB.addLiveIn(AArch64::LR);
11597
11598 MachineInstr *ret = BuildMI(MF, DebugLoc(), get(AArch64::RET))
11599 .addReg(AArch64::LR);
11600 MBB.insert(MBB.end(), ret);
11601
11602 signOutlinedFunction(MF, MBB, this, ShouldSignReturnAddr);
11603
11604 FI->setOutliningStyle("Function");
11605
11606 // Did we have to modify the stack by saving the link register?
11607 if (OF.FrameConstructionID != MachineOutlinerDefault)
11608 return;
11609
11610 // We modified the stack.
11611 // Walk over the basic block and fix up all the stack accesses.
11612 fixupPostOutline(MBB);
11613}
11614
11615MachineBasicBlock::iterator AArch64InstrInfo::insertOutlinedCall(
11618
11619 // Are we tail calling?
11620 if (C.CallConstructionID == MachineOutlinerTailCall) {
11621 // If yes, then we can just branch to the label.
11622 It = MBB.insert(It, BuildMI(MF, DebugLoc(), get(AArch64::TCRETURNdi))
11623 .addGlobalAddress(M.getNamedValue(MF.getName()))
11624 .addImm(0));
11625 return It;
11626 }
11627
11628 // Are we saving the link register?
11629 if (C.CallConstructionID == MachineOutlinerNoLRSave ||
11630 C.CallConstructionID == MachineOutlinerThunk) {
11631 // No, so just insert the call.
11632 It = MBB.insert(It, BuildMI(MF, DebugLoc(), get(AArch64::BL))
11633 .addGlobalAddress(M.getNamedValue(MF.getName())));
11634 return It;
11635 }
11636
11637 // We want to return the spot where we inserted the call.
11639
11640 // Instructions for saving and restoring LR around the call instruction we're
11641 // going to insert.
11642 MachineInstr *Save;
11643 MachineInstr *Restore;
11644 // Can we save to a register?
11645 if (C.CallConstructionID == MachineOutlinerRegSave) {
11646 // FIXME: This logic should be sunk into a target-specific interface so that
11647 // we don't have to recompute the register.
11648 Register Reg = findRegisterToSaveLRTo(C);
11649 assert(Reg && "No callee-saved register available?");
11650
11651 // LR has to be a live in so that we can save it.
11652 if (!MBB.isLiveIn(AArch64::LR))
11653 MBB.addLiveIn(AArch64::LR);
11654
11655 // Save and restore LR from Reg.
11656 Save = BuildMI(MF, DebugLoc(), get(AArch64::ORRXrs), Reg)
11657 .addReg(AArch64::XZR)
11658 .addReg(AArch64::LR)
11659 .addImm(0);
11660 Restore = BuildMI(MF, DebugLoc(), get(AArch64::ORRXrs), AArch64::LR)
11661 .addReg(AArch64::XZR)
11662 .addReg(Reg)
11663 .addImm(0);
11664 } else {
11665 // We have the default case. Save and restore from SP.
11666 Save = BuildMI(MF, DebugLoc(), get(AArch64::STRXpre))
11667 .addReg(AArch64::SP, RegState::Define)
11668 .addReg(AArch64::LR)
11669 .addReg(AArch64::SP)
11670 .addImm(-16);
11671 Restore = BuildMI(MF, DebugLoc(), get(AArch64::LDRXpost))
11672 .addReg(AArch64::SP, RegState::Define)
11673 .addReg(AArch64::LR, RegState::Define)
11674 .addReg(AArch64::SP)
11675 .addImm(16);
11676 }
11677
11678 It = MBB.insert(It, Save);
11679 It++;
11680
11681 // Insert the call.
11682 It = MBB.insert(It, BuildMI(MF, DebugLoc(), get(AArch64::BL))
11683 .addGlobalAddress(M.getNamedValue(MF.getName())));
11684 CallPt = It;
11685 It++;
11686
11687 It = MBB.insert(It, Restore);
11688 return CallPt;
11689}
11690
11691bool AArch64InstrInfo::shouldOutlineFromFunctionByDefault(
11692 MachineFunction &MF) const {
11693 return MF.getFunction().hasMinSize();
11694}
11695
11696void AArch64InstrInfo::buildClearRegister(Register Reg, MachineBasicBlock &MBB,
11698 DebugLoc &DL,
11699 bool AllowSideEffects) const {
11700 const MachineFunction &MF = *MBB.getParent();
11701 const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
11702 const AArch64RegisterInfo &TRI = *STI.getRegisterInfo();
11703
11704 if (TRI.isGeneralPurposeRegister(MF, Reg)) {
11705 BuildMI(MBB, Iter, DL, get(AArch64::MOVZXi), Reg).addImm(0).addImm(0);
11706 } else if (STI.isSVEorStreamingSVEAvailable()) {
11707 BuildMI(MBB, Iter, DL, get(AArch64::DUP_ZI_D), Reg)
11708 .addImm(0)
11709 .addImm(0);
11710 } else if (STI.isNeonAvailable()) {
11711 BuildMI(MBB, Iter, DL, get(AArch64::MOVIv2d_ns), Reg)
11712 .addImm(0);
11713 } else {
11714 // No Advanced SIMD (streaming-compatible without SVE, or +nosimd), so use
11715 // `fmov d...` instead of `movi v...`; writing `d` also clears the upper
11716 // 64 bits.
11717 assert(STI.hasFPARMv8() && "Expected FP to be available.");
11718 Register Reg64 = TRI.getSubReg(Reg, AArch64::dsub);
11719 BuildMI(MBB, Iter, DL, get(AArch64::FMOVD0), Reg64);
11720 }
11721}
11722
11723std::optional<DestSourcePair>
11725
11726 // AArch64::ORRWrs and AArch64::ORRXrs with WZR/XZR reg
11727 // and zero immediate operands used as an alias for mov instruction.
11728 if ((MI.getOpcode() == AArch64::ORRWrs &&
11729 MI.getOperand(1).getReg() == AArch64::WZR &&
11730 MI.getOperand(3).getImm() == 0x0) ||
11731 (MI.getOpcode() == AArch64::ORRWrr &&
11732 MI.getOperand(1).getReg() == AArch64::WZR)) {
11733 // Check that the w->w move is not a zero-extending w->x mov.
11734 if ((MI.getOperand(0).getReg().isPhysical() &&
11735 MI.findRegisterDefOperandIdx(
11736 getXRegFromWReg(MI.getOperand(0).getReg()),
11737 /*TRI=*/nullptr) == -1) ||
11738 (MI.getOperand(0).getReg().isVirtual() &&
11739 !MI.getOperand(0).getSubReg()))
11740 return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
11741 }
11742
11743 if (MI.getOpcode() == AArch64::ORRXrs &&
11744 MI.getOperand(1).getReg() == AArch64::XZR &&
11745 MI.getOperand(3).getImm() == 0x0)
11746 return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
11747
11748 return std::nullopt;
11749}
11750
11751std::optional<DestSourcePair>
11753 if ((MI.getOpcode() == AArch64::ORRWrs &&
11754 MI.getOperand(1).getReg() == AArch64::WZR &&
11755 MI.getOperand(3).getImm() == 0x0) ||
11756 (MI.getOpcode() == AArch64::ORRWrr &&
11757 MI.getOperand(1).getReg() == AArch64::WZR))
11758 return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
11759 return std::nullopt;
11760}
11761
11762std::optional<RegImmPair>
11763AArch64InstrInfo::isAddImmediate(const MachineInstr &MI, Register Reg) const {
11764 int Sign = 1;
11765 int64_t Offset = 0;
11766
11767 // TODO: Handle cases where Reg is a super- or sub-register of the
11768 // destination register.
11769 const MachineOperand &Op0 = MI.getOperand(0);
11770 if (!Op0.isReg() || Reg != Op0.getReg())
11771 return std::nullopt;
11772
11773 switch (MI.getOpcode()) {
11774 default:
11775 return std::nullopt;
11776 case AArch64::SUBWri:
11777 case AArch64::SUBXri:
11778 case AArch64::SUBSWri:
11779 case AArch64::SUBSXri:
11780 Sign *= -1;
11781 [[fallthrough]];
11782 case AArch64::ADDSWri:
11783 case AArch64::ADDSXri:
11784 case AArch64::ADDWri:
11785 case AArch64::ADDXri: {
11786 // TODO: Third operand can be global address (usually some string).
11787 if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg() ||
11788 !MI.getOperand(2).isImm())
11789 return std::nullopt;
11790 int Shift = MI.getOperand(3).getImm();
11791 assert((Shift == 0 || Shift == 12) && "Shift can be either 0 or 12");
11792 Offset = Sign * (MI.getOperand(2).getImm() << Shift);
11793 }
11794 }
11795 return RegImmPair{MI.getOperand(1).getReg(), Offset};
11796}
11797
11798/// If the given ORR instruction is a copy, and \p DescribedReg overlaps with
11799/// the destination register then, if possible, describe the value in terms of
11800/// the source register.
11801static std::optional<ParamLoadedValue>
11803 const TargetInstrInfo *TII,
11804 const TargetRegisterInfo *TRI) {
11805 auto DestSrc = TII->isCopyLikeInstr(MI);
11806 if (!DestSrc)
11807 return std::nullopt;
11808
11809 Register DestReg = DestSrc->Destination->getReg();
11810 Register SrcReg = DestSrc->Source->getReg();
11811
11812 if (!DestReg.isValid() || !SrcReg.isValid())
11813 return std::nullopt;
11814
11815 auto Expr = DIExpression::get(MI.getMF()->getFunction().getContext(), {});
11816
11817 // If the described register is the destination, just return the source.
11818 if (DestReg == DescribedReg)
11819 return ParamLoadedValue(MachineOperand::CreateReg(SrcReg, false), Expr);
11820
11821 // ORRWrs zero-extends to 64-bits, so we need to consider such cases.
11822 if (MI.getOpcode() == AArch64::ORRWrs &&
11823 TRI->isSuperRegister(DestReg, DescribedReg))
11824 return ParamLoadedValue(MachineOperand::CreateReg(SrcReg, false), Expr);
11825
11826 // We may need to describe the lower part of a ORRXrs move.
11827 if (MI.getOpcode() == AArch64::ORRXrs &&
11828 TRI->isSubRegister(DestReg, DescribedReg)) {
11829 Register SrcSubReg = TRI->getSubReg(SrcReg, AArch64::sub_32);
11830 return ParamLoadedValue(MachineOperand::CreateReg(SrcSubReg, false), Expr);
11831 }
11832
11833 assert(!TRI->isSuperOrSubRegisterEq(DestReg, DescribedReg) &&
11834 "Unhandled ORR[XW]rs copy case");
11835
11836 return std::nullopt;
11837}
11838
11839bool AArch64InstrInfo::isFunctionSafeToSplit(const MachineFunction &MF) const {
11840 // Functions cannot be split to different sections on AArch64 if they have
11841 // a red zone. This is because relaxing a cross-section branch may require
11842 // incrementing the stack pointer to spill a register, which would overwrite
11843 // the red zone.
11844 if (MF.getInfo<AArch64FunctionInfo>()->hasRedZone().value_or(true))
11845 return false;
11846
11848}
11849
11850bool AArch64InstrInfo::isMBBSafeToSplitToCold(
11851 const MachineBasicBlock &MBB) const {
11852 // Asm Goto blocks can contain conditional branches to goto labels, which can
11853 // get moved out of range of the branch instruction.
11854 auto isAsmGoto = [](const MachineInstr &MI) {
11855 return MI.getOpcode() == AArch64::INLINEASM_BR;
11856 };
11857 if (llvm::any_of(MBB, isAsmGoto) || MBB.isInlineAsmBrIndirectTarget())
11858 return false;
11859
11860 // Because jump tables are label-relative instead of table-relative, they all
11861 // must be in the same section or relocation fixup handling will fail.
11862
11863 // Check if MBB is a jump table target
11864 const MachineJumpTableInfo *MJTI = MBB.getParent()->getJumpTableInfo();
11865 auto containsMBB = [&MBB](const MachineJumpTableEntry &JTE) {
11866 return llvm::is_contained(JTE.MBBs, &MBB);
11867 };
11868 if (MJTI != nullptr && llvm::any_of(MJTI->getJumpTables(), containsMBB))
11869 return false;
11870
11871 // Check if MBB contains a jump table lookup
11872 for (const MachineInstr &MI : MBB) {
11873 switch (MI.getOpcode()) {
11874 case TargetOpcode::G_BRJT:
11875 case AArch64::JumpTableDest32:
11876 case AArch64::JumpTableDest16:
11877 case AArch64::JumpTableDest8:
11878 return false;
11879 default:
11880 continue;
11881 }
11882 }
11883
11884 // MBB isn't a special case, so it's safe to be split to the cold section.
11885 return true;
11886}
11887
11888std::optional<ParamLoadedValue>
11889AArch64InstrInfo::describeLoadedValue(const MachineInstr &MI,
11890 Register Reg) const {
11891 const MachineFunction *MF = MI.getMF();
11892 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
11893 switch (MI.getOpcode()) {
11894 case AArch64::MOVZWi:
11895 case AArch64::MOVZXi: {
11896 // MOVZWi may be used for producing zero-extended 32-bit immediates in
11897 // 64-bit parameters, so we need to consider super-registers.
11898 if (!TRI->isSuperRegisterEq(MI.getOperand(0).getReg(), Reg))
11899 return std::nullopt;
11900
11901 if (!MI.getOperand(1).isImm())
11902 return std::nullopt;
11903 int64_t Immediate = MI.getOperand(1).getImm();
11904 int Shift = MI.getOperand(2).getImm();
11905 return ParamLoadedValue(MachineOperand::CreateImm(Immediate << Shift),
11906 nullptr);
11907 }
11908 case AArch64::ORRWrs:
11909 case AArch64::ORRXrs:
11910 return describeORRLoadedValue(MI, Reg, this, TRI);
11911 }
11912
11914}
11915
11916bool AArch64InstrInfo::isExtendLikelyToBeFolded(
11917 MachineInstr &ExtMI, MachineRegisterInfo &MRI) const {
11918 assert(ExtMI.getOpcode() == TargetOpcode::G_SEXT ||
11919 ExtMI.getOpcode() == TargetOpcode::G_ZEXT ||
11920 ExtMI.getOpcode() == TargetOpcode::G_ANYEXT);
11921
11922 // Anyexts are nops.
11923 if (ExtMI.getOpcode() == TargetOpcode::G_ANYEXT)
11924 return true;
11925
11926 Register DefReg = ExtMI.getOperand(0).getReg();
11927 if (!MRI.hasOneNonDBGUse(DefReg))
11928 return false;
11929
11930 // It's likely that a sext/zext as a G_PTR_ADD offset will be folded into an
11931 // addressing mode.
11932 auto *UserMI = &*MRI.use_instr_nodbg_begin(DefReg);
11933 return UserMI->getOpcode() == TargetOpcode::G_PTR_ADD;
11934}
11935
11936uint64_t AArch64InstrInfo::getElementSizeForOpcode(unsigned Opc) const {
11937 return get(Opc).TSFlags & AArch64::ElementSizeMask;
11938}
11939
11940bool AArch64InstrInfo::isPTestLikeOpcode(unsigned Opc) const {
11941 return get(Opc).TSFlags & AArch64::InstrFlagIsPTestLike;
11942}
11943
11944bool AArch64InstrInfo::isWhileOpcode(unsigned Opc) const {
11945 return get(Opc).TSFlags & AArch64::InstrFlagIsWhile;
11946}
11947
11948unsigned int
11949AArch64InstrInfo::getTailDuplicateSize(CodeGenOptLevel OptLevel) const {
11950 return OptLevel >= CodeGenOptLevel::Aggressive ? 6 : 2;
11951}
11952
11953bool AArch64InstrInfo::isLegalAddressingMode(unsigned NumBytes, int64_t Offset,
11954 unsigned Scale) const {
11955 if (Offset && Scale)
11956 return false;
11957
11958 // Check Reg + Imm
11959 if (!Scale) {
11960 // 9-bit signed offset
11961 if (isInt<9>(Offset))
11962 return true;
11963
11964 // 12-bit unsigned offset
11965 unsigned Shift = Log2_64(NumBytes);
11966 if (NumBytes && Offset > 0 && (Offset / NumBytes) <= (1LL << 12) - 1 &&
11967 // Must be a multiple of NumBytes (NumBytes is a power of 2)
11968 (Offset >> Shift) << Shift == Offset)
11969 return true;
11970 return false;
11971 }
11972
11973 // Check reg1 + SIZE_IN_BYTES * reg2 and reg1 + reg2
11974 return Scale == 1 || (Scale > 0 && Scale == NumBytes);
11975}
11976
11978 if (MF.getSubtarget<AArch64Subtarget>().hardenSlsBlr())
11979 return AArch64::BLRNoIP;
11980 else
11981 return AArch64::BLR;
11982}
11983
11985 DebugLoc DL) const {
11986 MachineBasicBlock::iterator InsertPt = MBB.getFirstTerminator();
11987 auto Builder = BuildMI(MBB, InsertPt, DL, get(AArch64::PAUTH_EPILOGUE))
11989
11990 MachineFunction &MF = *MBB.getParent();
11991 const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
11992 auto &AFL = *static_cast<const AArch64FrameLowering *>(
11993 MF.getSubtarget().getFrameLowering());
11994 if (AFL.getArgumentStackToRestore(MF, MBB)) {
11995 Builder.addReg(AArch64::X17, RegState::ImplicitDefine);
11996 Builder.addReg(AArch64::X16, RegState::ImplicitDefine);
11997 if (AFI->branchProtectionPAuthLR())
11998 Builder.addReg(AArch64::X15, RegState::ImplicitDefine);
11999 return;
12000 }
12001
12002 if (AFI->branchProtectionPAuthLR() && !Subtarget.hasPAuthLR())
12003 Builder.addReg(AArch64::X16, RegState::ImplicitDefine);
12004}
12005
12007AArch64InstrInfo::probedStackAlloc(MachineBasicBlock::iterator MBBI,
12008 Register TargetReg, bool FrameSetup) const {
12009 assert(TargetReg != AArch64::SP && "New top of stack cannot already be in SP");
12010
12011 MachineBasicBlock &MBB = *MBBI->getParent();
12012 MachineFunction &MF = *MBB.getParent();
12013 const AArch64InstrInfo *TII =
12014 MF.getSubtarget<AArch64Subtarget>().getInstrInfo();
12015 int64_t ProbeSize = MF.getInfo<AArch64FunctionInfo>()->getStackProbeSize();
12016 DebugLoc DL = MBB.findDebugLoc(MBBI);
12017
12018 MachineFunction::iterator MBBInsertPoint = std::next(MBB.getIterator());
12019 MachineBasicBlock *LoopTestMBB =
12020 MF.CreateMachineBasicBlock(MBB.getBasicBlock());
12021 MF.insert(MBBInsertPoint, LoopTestMBB);
12022 MachineBasicBlock *LoopBodyMBB =
12023 MF.CreateMachineBasicBlock(MBB.getBasicBlock());
12024 MF.insert(MBBInsertPoint, LoopBodyMBB);
12025 MachineBasicBlock *ExitMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
12026 MF.insert(MBBInsertPoint, ExitMBB);
12027 MachineInstr::MIFlag Flags =
12029
12030 // LoopTest:
12031 // SUB SP, SP, #ProbeSize
12032 emitFrameOffset(*LoopTestMBB, LoopTestMBB->end(), DL, AArch64::SP,
12033 AArch64::SP, StackOffset::getFixed(-ProbeSize), TII, Flags);
12034
12035 // CMP SP, TargetReg
12036 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(AArch64::SUBSXrx64),
12037 AArch64::XZR)
12038 .addReg(AArch64::SP)
12039 .addReg(TargetReg)
12041 .setMIFlags(Flags);
12042
12043 // B.<Cond> LoopExit
12044 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(AArch64::Bcc))
12046 .addMBB(ExitMBB)
12047 .setMIFlags(Flags);
12048
12049 // LDR XZR, [SP]
12050 BuildMI(*LoopBodyMBB, LoopBodyMBB->end(), DL, TII->get(AArch64::LDRXui))
12051 .addDef(AArch64::XZR)
12052 .addReg(AArch64::SP)
12053 .addImm(0)
12057 Align(8)))
12058 .setMIFlags(Flags);
12059
12060 // B loop
12061 BuildMI(*LoopBodyMBB, LoopBodyMBB->end(), DL, TII->get(AArch64::B))
12062 .addMBB(LoopTestMBB)
12063 .setMIFlags(Flags);
12064
12065 // LoopExit:
12066 // MOV SP, TargetReg
12067 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(AArch64::ADDXri), AArch64::SP)
12068 .addReg(TargetReg)
12069 .addImm(0)
12071 .setMIFlags(Flags);
12072
12073 // LDR XZR, [SP]
12074 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(AArch64::LDRXui))
12075 .addReg(AArch64::XZR, RegState::Define)
12076 .addReg(AArch64::SP)
12077 .addImm(0)
12078 .setMIFlags(Flags);
12079
12080 ExitMBB->splice(ExitMBB->end(), &MBB, std::next(MBBI), MBB.end());
12082
12083 LoopTestMBB->addSuccessor(ExitMBB);
12084 LoopTestMBB->addSuccessor(LoopBodyMBB);
12085 LoopBodyMBB->addSuccessor(LoopTestMBB);
12086 MBB.addSuccessor(LoopTestMBB);
12087
12088 // Update liveins.
12089 if (MF.getRegInfo().reservedRegsFrozen())
12090 fullyRecomputeLiveIns({ExitMBB, LoopBodyMBB, LoopTestMBB});
12091
12092 return ExitMBB->begin();
12093}
12094
12095namespace {
12096class AArch64PipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo {
12097 MachineFunction *MF;
12098 const TargetInstrInfo *TII;
12099 const TargetRegisterInfo *TRI;
12100 MachineRegisterInfo &MRI;
12101
12102 /// The block of the loop
12103 MachineBasicBlock *LoopBB;
12104 /// The conditional branch of the loop
12105 MachineInstr *CondBranch;
12106 /// The compare instruction for loop control
12107 MachineInstr *Comp;
12108 /// The number of the operand of the loop counter value in Comp
12109 unsigned CompCounterOprNum;
12110 /// The instruction that updates the loop counter value
12111 MachineInstr *Update;
12112 /// The number of the operand of the loop counter value in Update
12113 unsigned UpdateCounterOprNum;
12114 /// The initial value of the loop counter
12115 Register Init;
12116 /// True iff Update is a predecessor of Comp
12117 bool IsUpdatePriorComp;
12118
12119 /// The normalized condition used by createTripCountGreaterCondition()
12120 SmallVector<MachineOperand, 4> Cond;
12121
12122public:
12123 AArch64PipelinerLoopInfo(MachineBasicBlock *LoopBB, MachineInstr *CondBranch,
12124 MachineInstr *Comp, unsigned CompCounterOprNum,
12125 MachineInstr *Update, unsigned UpdateCounterOprNum,
12126 Register Init, bool IsUpdatePriorComp,
12127 const SmallVectorImpl<MachineOperand> &Cond)
12128 : MF(Comp->getParent()->getParent()),
12129 TII(MF->getSubtarget().getInstrInfo()),
12130 TRI(MF->getSubtarget().getRegisterInfo()), MRI(MF->getRegInfo()),
12131 LoopBB(LoopBB), CondBranch(CondBranch), Comp(Comp),
12132 CompCounterOprNum(CompCounterOprNum), Update(Update),
12133 UpdateCounterOprNum(UpdateCounterOprNum), Init(Init),
12134 IsUpdatePriorComp(IsUpdatePriorComp), Cond(Cond.begin(), Cond.end()) {}
12135
12136 bool shouldIgnoreForPipelining(const MachineInstr *MI) const override {
12137 // Make the instructions for loop control be placed in stage 0.
12138 // The predecessors of Comp are considered by the caller.
12139 return MI == Comp;
12140 }
12141
12142 std::optional<bool> createTripCountGreaterCondition(
12143 int TC, MachineBasicBlock &MBB,
12144 SmallVectorImpl<MachineOperand> &CondParam) override {
12145 // A branch instruction will be inserted as "if (Cond) goto epilogue".
12146 // Cond is normalized for such use.
12147 // The predecessors of the branch are assumed to have already been inserted.
12148 CondParam = Cond;
12149 return {};
12150 }
12151
12152 void createRemainingIterationsGreaterCondition(
12153 int TC, MachineBasicBlock &MBB, SmallVectorImpl<MachineOperand> &Cond,
12154 DenseMap<MachineInstr *, MachineInstr *> &LastStage0Insts) override;
12155
12156 void setPreheader(MachineBasicBlock *NewPreheader) override {}
12157
12158 void adjustTripCount(int TripCountAdjust) override {}
12159
12160 bool isMVEExpanderSupported() override { return true; }
12161};
12162} // namespace
12163
12164/// Clone an instruction from MI. The register of ReplaceOprNum-th operand
12165/// is replaced by ReplaceReg. The output register is newly created.
12166/// The other operands are unchanged from MI.
12167static Register cloneInstr(const MachineInstr *MI, unsigned ReplaceOprNum,
12168 Register ReplaceReg, MachineBasicBlock &MBB,
12169 MachineBasicBlock::iterator InsertTo) {
12170 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
12171 const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo();
12172 MachineInstr *NewMI = MBB.getParent()->CloneMachineInstr(MI);
12173 Register Result = 0;
12174 for (unsigned I = 0; I < NewMI->getNumOperands(); ++I) {
12175 if (I == 0 && NewMI->getOperand(0).getReg().isVirtual()) {
12176 Result = MRI.createVirtualRegister(
12177 MRI.getRegClass(NewMI->getOperand(0).getReg()));
12178 NewMI->getOperand(I).setReg(Result);
12179 } else if (I == ReplaceOprNum) {
12180 MRI.constrainRegClass(ReplaceReg, TII->getRegClass(NewMI->getDesc(), I));
12181 NewMI->getOperand(I).setReg(ReplaceReg);
12182 }
12183 }
12184 MBB.insert(InsertTo, NewMI);
12185 return Result;
12186}
12187
12188void AArch64PipelinerLoopInfo::createRemainingIterationsGreaterCondition(
12191 // Create and accumulate conditions for next TC iterations.
12192 // Example:
12193 // SUBSXrr N, counter, implicit-def $nzcv # compare instruction for the last
12194 // # iteration of the kernel
12195 //
12196 // # insert the following instructions
12197 // cond = CSINCXr 0, 0, C, implicit $nzcv
12198 // counter = ADDXri counter, 1 # clone from this->Update
12199 // SUBSXrr n, counter, implicit-def $nzcv # clone from this->Comp
12200 // cond = CSINCXr cond, cond, C, implicit $nzcv
12201 // ... (repeat TC times)
12202 // SUBSXri cond, 0, implicit-def $nzcv
12203
12204 assert(CondBranch->getOpcode() == AArch64::Bcc);
12205 // CondCode to exit the loop
12207 (AArch64CC::CondCode)CondBranch->getOperand(0).getImm();
12208 if (CondBranch->getOperand(1).getMBB() == LoopBB)
12210
12211 // Accumulate conditions to exit the loop
12212 Register AccCond = AArch64::XZR;
12213
12214 // If CC holds, CurCond+1 is returned; otherwise CurCond is returned.
12215 auto AccumulateCond = [&](Register CurCond,
12217 Register NewCond = MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
12218 BuildMI(MBB, MBB.end(), Comp->getDebugLoc(), TII->get(AArch64::CSINCXr))
12219 .addReg(NewCond, RegState::Define)
12220 .addReg(CurCond)
12221 .addReg(CurCond)
12223 return NewCond;
12224 };
12225
12226 if (!LastStage0Insts.empty() && LastStage0Insts[Comp]->getParent() == &MBB) {
12227 // Update and Comp for I==0 are already exists in MBB
12228 // (MBB is an unrolled kernel)
12229 Register Counter;
12230 for (int I = 0; I <= TC; ++I) {
12231 Register NextCounter;
12232 if (I != 0)
12233 NextCounter =
12234 cloneInstr(Comp, CompCounterOprNum, Counter, MBB, MBB.end());
12235
12236 AccCond = AccumulateCond(AccCond, CC);
12237
12238 if (I != TC) {
12239 if (I == 0) {
12240 if (Update != Comp && IsUpdatePriorComp) {
12241 Counter =
12242 LastStage0Insts[Comp]->getOperand(CompCounterOprNum).getReg();
12243 NextCounter = cloneInstr(Update, UpdateCounterOprNum, Counter, MBB,
12244 MBB.end());
12245 } else {
12246 // can use already calculated value
12247 NextCounter = LastStage0Insts[Update]->getOperand(0).getReg();
12248 }
12249 } else if (Update != Comp) {
12250 NextCounter =
12251 cloneInstr(Update, UpdateCounterOprNum, Counter, MBB, MBB.end());
12252 }
12253 }
12254 Counter = NextCounter;
12255 }
12256 } else {
12257 Register Counter;
12258 if (LastStage0Insts.empty()) {
12259 // use initial counter value (testing if the trip count is sufficient to
12260 // be executed by pipelined code)
12261 Counter = Init;
12262 if (IsUpdatePriorComp)
12263 Counter =
12264 cloneInstr(Update, UpdateCounterOprNum, Counter, MBB, MBB.end());
12265 } else {
12266 // MBB is an epilogue block. LastStage0Insts[Comp] is in the kernel block.
12267 Counter = LastStage0Insts[Comp]->getOperand(CompCounterOprNum).getReg();
12268 }
12269
12270 for (int I = 0; I <= TC; ++I) {
12271 Register NextCounter;
12272 NextCounter =
12273 cloneInstr(Comp, CompCounterOprNum, Counter, MBB, MBB.end());
12274 AccCond = AccumulateCond(AccCond, CC);
12275 if (I != TC && Update != Comp)
12276 NextCounter =
12277 cloneInstr(Update, UpdateCounterOprNum, Counter, MBB, MBB.end());
12278 Counter = NextCounter;
12279 }
12280 }
12281
12282 // If AccCond == 0, the remainder is greater than TC.
12283 BuildMI(MBB, MBB.end(), Comp->getDebugLoc(), TII->get(AArch64::SUBSXri))
12284 .addReg(AArch64::XZR, RegState::Define | RegState::Dead)
12285 .addReg(AccCond)
12286 .addImm(0)
12287 .addImm(0);
12288 Cond.clear();
12290}
12291
12292static void extractPhiReg(const MachineInstr &Phi, const MachineBasicBlock *MBB,
12293 Register &RegMBB, Register &RegOther) {
12294 assert(Phi.getNumOperands() == 5);
12295 if (Phi.getOperand(2).getMBB() == MBB) {
12296 RegMBB = Phi.getOperand(1).getReg();
12297 RegOther = Phi.getOperand(3).getReg();
12298 } else {
12299 assert(Phi.getOperand(4).getMBB() == MBB);
12300 RegMBB = Phi.getOperand(3).getReg();
12301 RegOther = Phi.getOperand(1).getReg();
12302 }
12303}
12304
12306 if (!Reg.isVirtual())
12307 return false;
12308 const MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
12309 return MRI.getDefBlock(Reg) != BB;
12310}
12311
12312/// If Reg is an induction variable, return true and set some parameters
12313static bool getIndVarInfo(Register Reg, const MachineBasicBlock *LoopBB,
12314 MachineInstr *&UpdateInst,
12315 unsigned &UpdateCounterOprNum, Register &InitReg,
12316 bool &IsUpdatePriorComp) {
12317 // Example:
12318 //
12319 // Preheader:
12320 // InitReg = ...
12321 // LoopBB:
12322 // Reg0 = PHI (InitReg, Preheader), (Reg1, LoopBB)
12323 // Reg = COPY Reg0 ; COPY is ignored.
12324 // Reg1 = ADD Reg, #1; UpdateInst. Incremented by a loop invariant value.
12325 // ; Reg is the value calculated in the previous
12326 // ; iteration, so IsUpdatePriorComp == false.
12327
12328 if (LoopBB->pred_size() != 2)
12329 return false;
12330 if (!Reg.isVirtual())
12331 return false;
12332 const MachineRegisterInfo &MRI = LoopBB->getParent()->getRegInfo();
12333 UpdateInst = nullptr;
12334 UpdateCounterOprNum = 0;
12335 InitReg = 0;
12336 IsUpdatePriorComp = true;
12337 Register CurReg = Reg;
12338 while (true) {
12339 MachineInstr *Def = MRI.getVRegDef(CurReg);
12340 if (Def->getParent() != LoopBB)
12341 return false;
12342 if (Def->isCopy()) {
12343 // Ignore copy instructions unless they contain subregisters
12344 if (Def->getOperand(0).getSubReg() || Def->getOperand(1).getSubReg())
12345 return false;
12346 CurReg = Def->getOperand(1).getReg();
12347 } else if (Def->isPHI()) {
12348 if (InitReg != 0)
12349 return false;
12350 if (!UpdateInst)
12351 IsUpdatePriorComp = false;
12352 extractPhiReg(*Def, LoopBB, CurReg, InitReg);
12353 } else {
12354 if (UpdateInst)
12355 return false;
12356 switch (Def->getOpcode()) {
12357 case AArch64::ADDSXri:
12358 case AArch64::ADDSWri:
12359 case AArch64::SUBSXri:
12360 case AArch64::SUBSWri:
12361 case AArch64::ADDXri:
12362 case AArch64::ADDWri:
12363 case AArch64::SUBXri:
12364 case AArch64::SUBWri:
12365 UpdateInst = Def;
12366 UpdateCounterOprNum = 1;
12367 break;
12368 case AArch64::ADDSXrr:
12369 case AArch64::ADDSWrr:
12370 case AArch64::SUBSXrr:
12371 case AArch64::SUBSWrr:
12372 case AArch64::ADDXrr:
12373 case AArch64::ADDWrr:
12374 case AArch64::SUBXrr:
12375 case AArch64::SUBWrr:
12376 UpdateInst = Def;
12377 if (isDefinedOutside(Def->getOperand(2).getReg(), LoopBB))
12378 UpdateCounterOprNum = 1;
12379 else if (isDefinedOutside(Def->getOperand(1).getReg(), LoopBB))
12380 UpdateCounterOprNum = 2;
12381 else
12382 return false;
12383 break;
12384 default:
12385 return false;
12386 }
12387 CurReg = Def->getOperand(UpdateCounterOprNum).getReg();
12388 }
12389
12390 if (!CurReg.isVirtual())
12391 return false;
12392 if (Reg == CurReg)
12393 break;
12394 }
12395
12396 if (!UpdateInst)
12397 return false;
12398
12399 return true;
12400}
12401
12402std::unique_ptr<TargetInstrInfo::PipelinerLoopInfo>
12404 // Accept loops that meet the following conditions
12405 // * The conditional branch is BCC
12406 // * The compare instruction is ADDS/SUBS/WHILEXX
12407 // * One operand of the compare is an induction variable and the other is a
12408 // loop invariant value
12409 // * The induction variable is incremented/decremented by a single instruction
12410 // * Does not contain CALL or instructions which have unmodeled side effects
12411
12412 for (MachineInstr &MI : *LoopBB)
12413 if (MI.isCall() || MI.hasUnmodeledSideEffects())
12414 // This instruction may use NZCV, which interferes with the instruction to
12415 // be inserted for loop control.
12416 return nullptr;
12417
12418 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
12420 if (analyzeBranch(*LoopBB, TBB, FBB, Cond))
12421 return nullptr;
12422
12423 // Infinite loops are not supported
12424 if (TBB == LoopBB && FBB == LoopBB)
12425 return nullptr;
12426
12427 // Must be conditional branch
12428 if (TBB != LoopBB && FBB == nullptr)
12429 return nullptr;
12430
12431 assert((TBB == LoopBB || FBB == LoopBB) &&
12432 "The Loop must be a single-basic-block loop");
12433
12434 MachineInstr *CondBranch = &*LoopBB->getFirstTerminator();
12436
12437 if (CondBranch->getOpcode() != AArch64::Bcc)
12438 return nullptr;
12439
12440 // Normalization for createTripCountGreaterCondition()
12441 if (TBB == LoopBB)
12443
12444 MachineInstr *Comp = nullptr;
12445 unsigned CompCounterOprNum = 0;
12446 for (MachineInstr &MI : reverse(*LoopBB)) {
12447 if (MI.modifiesRegister(AArch64::NZCV, &TRI)) {
12448 // Guarantee that the compare is SUBS/ADDS/WHILEXX and that one of the
12449 // operands is a loop invariant value
12450
12451 switch (MI.getOpcode()) {
12452 case AArch64::SUBSXri:
12453 case AArch64::SUBSWri:
12454 case AArch64::ADDSXri:
12455 case AArch64::ADDSWri:
12456 Comp = &MI;
12457 CompCounterOprNum = 1;
12458 break;
12459 case AArch64::ADDSWrr:
12460 case AArch64::ADDSXrr:
12461 case AArch64::SUBSWrr:
12462 case AArch64::SUBSXrr:
12463 Comp = &MI;
12464 break;
12465 default:
12466 if (isWhileOpcode(MI.getOpcode())) {
12467 Comp = &MI;
12468 break;
12469 }
12470 return nullptr;
12471 }
12472
12473 if (CompCounterOprNum == 0) {
12474 if (isDefinedOutside(Comp->getOperand(1).getReg(), LoopBB))
12475 CompCounterOprNum = 2;
12476 else if (isDefinedOutside(Comp->getOperand(2).getReg(), LoopBB))
12477 CompCounterOprNum = 1;
12478 else
12479 return nullptr;
12480 }
12481 break;
12482 }
12483 }
12484 if (!Comp)
12485 return nullptr;
12486
12487 MachineInstr *Update = nullptr;
12488 Register Init;
12489 bool IsUpdatePriorComp;
12490 unsigned UpdateCounterOprNum;
12491 if (!getIndVarInfo(Comp->getOperand(CompCounterOprNum).getReg(), LoopBB,
12492 Update, UpdateCounterOprNum, Init, IsUpdatePriorComp))
12493 return nullptr;
12494
12495 return std::make_unique<AArch64PipelinerLoopInfo>(
12496 LoopBB, CondBranch, Comp, CompCounterOprNum, Update, UpdateCounterOprNum,
12497 Init, IsUpdatePriorComp, Cond);
12498}
12499
12500/// verifyInstruction - Perform target specific instruction verification.
12501bool AArch64InstrInfo::verifyInstruction(const MachineInstr &MI,
12502 StringRef &ErrInfo) const {
12503 // Verify that immediate offsets on load/store instructions are within range.
12504 // Stack objects with an FI operand are excluded as they can be fixed up
12505 // during PEI.
12506 TypeSize Scale(0U, false), Width(0U, false);
12507 int64_t MinOffset, MaxOffset;
12508 if (getMemOpInfo(MI.getOpcode(), Scale, Width, MinOffset, MaxOffset)) {
12509 unsigned ImmIdx = getLoadStoreImmIdx(MI.getOpcode());
12510 if (MI.getOperand(ImmIdx).isImm() && !MI.getOperand(ImmIdx - 1).isFI()) {
12511 int64_t Imm = MI.getOperand(ImmIdx).getImm();
12512 if (Imm < MinOffset || Imm > MaxOffset) {
12513 ErrInfo = "Unexpected immediate on load/store instruction";
12514 return false;
12515 }
12516 }
12517 }
12518
12519 const MCInstrDesc &MCID = MI.getDesc();
12520 for (unsigned Op = 0; Op < MCID.getNumOperands(); Op++) {
12521 const MachineOperand &MO = MI.getOperand(Op);
12522 switch (MCID.operands()[Op].OperandType) {
12524 if (!MO.isImm() || MO.getImm() != 0) {
12525 ErrInfo = "OPERAND_IMPLICIT_IMM_0 should be 0";
12526 return false;
12527 }
12528 break;
12530 if (!MO.isImm() ||
12532 (AArch64_AM::getShiftValue(MO.getImm()) != 8 &&
12533 AArch64_AM::getShiftValue(MO.getImm()) != 16)) {
12534 ErrInfo = "OPERAND_SHIFT_MSL should be msl shift of 8 or 16";
12535 return false;
12536 }
12537 break;
12539 if (!MO.isImm() || (MO.getImm() != 0 && MO.getImm() != 1)) {
12540 ErrInfo = "OPERAND_IMM_UINT1 should be 0 or 1";
12541 return false;
12542 }
12543 break;
12545 if (!MO.isImm() || MO.getImm() <= 0 || MO.getImm() > 16) {
12546 ErrInfo = "OPERAND_IMM_UINT4plus1 should be in the range 1 to 16";
12547 return false;
12548 }
12549 break;
12551 if (!MO.isImm() || !isUInt<5>(MO.getImm())) {
12552 ErrInfo = "OPERAND_IMM_UINT5 should be in the range 0 to 31";
12553 return false;
12554 }
12555 break;
12557 if (!MO.isImm() || !isUInt<8>(MO.getImm())) {
12558 ErrInfo = "OPERAND_IMM_UINT8 should be in the range 0 to 255";
12559 return false;
12560 }
12561 break;
12562 default:
12563 break;
12564 }
12565 }
12566 return true;
12567}
12568
12569#define GET_INSTRINFO_HELPERS
12570#define GET_INSTRMAP_INFO
12571#include "AArch64GenInstrInfo.inc"
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
static Register genNeg(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, DenseMap< Register, unsigned > &InstrIdxForVirtReg, unsigned MnegOpc, const TargetRegisterClass *RC)
genNeg - Helper to generate an intermediate negation of the second operand of Root
static bool isFrameStoreOpcode(int Opcode)
static bool getMaddPatterns(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns)
Find instructions that can be turned into madd.
static AArch64CC::CondCode findCondCodeUsedByInstr(const MachineInstr &Instr)
Find a condition code used by the instruction.
static void updateOperandRegClass(MachineInstr &Instr)
static MachineInstr * genFusedMultiplyAcc(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, unsigned IdxMulOpd, unsigned MaddOpc, const TargetRegisterClass *RC)
genFusedMultiplyAcc - Helper to generate fused multiply accumulate instructions.
static MachineInstr * genFusedMultiplyAccNeg(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, DenseMap< Register, unsigned > &InstrIdxForVirtReg, unsigned IdxMulOpd, unsigned MaddOpc, unsigned MnegOpc, const TargetRegisterClass *RC)
genFusedMultiplyAccNeg - Helper to generate fused multiply accumulate instructions with an additional...
static bool isCombineInstrCandidate64(unsigned Opc)
static bool isFrameLoadOpcode(int Opcode)
static unsigned removeCopies(const MachineRegisterInfo &MRI, unsigned VReg)
static bool areCFlagsAccessedBetweenInstrs(MachineBasicBlock::iterator From, MachineBasicBlock::iterator To, const TargetRegisterInfo *TRI, const AccessKind AccessToCheck=AK_All)
True when condition flags are accessed (either by writing or reading) on the instruction trace starti...
static std::optional< SPAddSubImmEncoding > adjustSPAddSubImm(const MachineInstr &MI, int64_t Delta)
Adjust the signed byte offset of MI, which must satisfy isSPAddSubImm, by Delta and re-encode the res...
static bool getFMAPatterns(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns)
Floating-Point Support.
static bool isADDSRegImm(unsigned Opcode)
static bool isCheapCopy(const MachineInstr &MI, const AArch64RegisterInfo &RI)
static bool isANDOpcode(MachineInstr &MI)
static bool predictCompactUnwindFrameRecordForOutlinedFunction(std::vector< outliner::Candidate > &RepeatedSequenceLocs, const TargetRegisterInfo &TRI)
Predict what the above will answer, for use while costing candidates.
static void appendOffsetComment(int NumBytes, llvm::raw_string_ostream &Comment, StringRef RegScale={})
static unsigned sForm(MachineInstr &Instr)
Get opcode of S version of Instr.
static unsigned getBranchDisplacementBits(const AArch64Options &CLOpts, unsigned Opc)
static bool isCombineInstrSettingFlag(unsigned Opc)
static bool getFNEGPatterns(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns)
static bool getIndVarInfo(Register Reg, const MachineBasicBlock *LoopBB, MachineInstr *&UpdateInst, unsigned &UpdateCounterOprNum, Register &InitReg, bool &IsUpdatePriorComp)
If Reg is an induction variable, return true and set some parameters.
static bool canPairLdStOpc(unsigned FirstOpc, unsigned SecondOpc)
static bool mustAvoidNeonAtMBBI(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB, MachineBasicBlock::iterator I)
Returns true if in a streaming call site region without SME-FA64.
static bool isPostIndexLdStOpcode(unsigned Opcode)
Return true if the opcode is a post-index ld/st instruction, which really loads from base+0.
static std::optional< unsigned > getLFIInstSizeInBytes(const MachineInstr &MI)
Return the maximum number of bytes of code the specified instruction may be after LFI rewriting.
static std::optional< ParamLoadedValue > describeORRLoadedValue(const MachineInstr &MI, Register DescribedReg, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI)
If the given ORR instruction is a copy, and DescribedReg overlaps with the destination register then,...
static bool getFMULPatterns(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns)
static void genMaddShf(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, SmallVectorImpl< MachineInstr * > &DelInstrs, unsigned MaddOpc, bool Is64Bit, DenseMap< Register, unsigned > &InstrIdxForVirtReg)
MUL I=A,B,0 ADDrs R,I,C,shift ==> SBFM/UBFM J=C,shift MADD R,A,B,J.
static void appendReadRegExpr(SmallVectorImpl< char > &Expr, unsigned RegNum)
static MachineInstr * genMaddR(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, unsigned IdxMulOpd, unsigned MaddOpc, unsigned VR, const TargetRegisterClass *RC)
genMaddR - Generate madd instruction and combine mul and add using an extra virtual register Example ...
static Register cloneInstr(const MachineInstr *MI, unsigned ReplaceOprNum, Register ReplaceReg, MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertTo)
Clone an instruction from MI.
static bool scaleOffset(unsigned Opc, int64_t &Offset)
static bool canCombineWithFMUL(MachineBasicBlock &MBB, MachineOperand &MO, unsigned MulOpc)
unsigned scaledOffsetOpcode(unsigned Opcode, unsigned &Scale)
static MachineInstr * genFusedMultiplyIdx(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, unsigned IdxMulOpd, unsigned MaddOpc, const TargetRegisterClass *RC)
genFusedMultiplyIdx - Helper to generate fused multiply accumulate instructions.
static MachineInstr * genIndexedMultiply(MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, unsigned IdxDupOp, unsigned MulOpc, const TargetRegisterClass *RC, MachineRegisterInfo &MRI)
Fold (FMUL x (DUP y lane)) into (FMUL_indexed x y lane)
static bool shouldUseCompactUnwindFrameRecordForOutlinedFunction(const MachineBasicBlock &MBB)
Return true if the outlined function in MBB should save FP and LR as a frame record instead of saving...
static bool isSUBSRegImm(unsigned Opcode)
static const TargetRegisterClass * getRegClass(const MachineInstr &MI, Register Reg)
static bool isInStreamingCallSiteRegion(MachineBasicBlock &MBB, MachineBasicBlock::iterator I)
Returns true if the instruction at I is in a streaming call site region, within a single basic block.
static bool canCmpInstrBeRemoved(MachineInstr &MI, MachineInstr &CmpInstr, int CmpValue, const TargetRegisterInfo &TRI, SmallVectorImpl< MachineInstr * > &CCUseInstrs, bool &IsInvertCC)
unsigned unscaledOffsetOpcode(unsigned Opcode)
static bool getLoadPatterns(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns)
Search for patterns of LD instructions we can optimize.
static bool canInstrSubstituteCmpInstr(MachineInstr &MI, MachineInstr &CmpInstr, const TargetRegisterInfo &TRI)
Check if CmpInstr can be substituted by MI.
static UsedNZCV getUsedNZCV(AArch64CC::CondCode CC)
static bool isCombineInstrCandidateFP(const MachineInstr &Inst)
static bool isCompactUnwindFrameRecordEnabled(const MachineFunction &MF)
Return true if the frame-record form of the outlined prologue is enabled for the target of MF.
static void appendLoadRegExpr(SmallVectorImpl< char > &Expr, int64_t OffsetFromDefCFA)
static void appendConstantExpr(SmallVectorImpl< char > &Expr, int64_t Constant, dwarf::LocationAtom Operation)
static unsigned convertToNonFlagSettingOpc(const MachineInstr &MI)
Return the opcode that does not set flags when possible - otherwise return the original opcode.
static bool outliningCandidatesV8_3OpsConsensus(const outliner::Candidate &a, const outliner::Candidate &b)
static bool isCombineInstrCandidate32(unsigned Opc)
static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target, SmallVectorImpl< MachineOperand > &Cond)
static unsigned offsetExtendOpcode(unsigned Opcode)
MachineOutlinerMBBFlags
@ LRUnavailableSomewhere
@ UnsafeRegsDead
static void loadRegPairFromStackSlot(const TargetRegisterInfo &TRI, MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, const MCInstrDesc &MCID, Register DestReg, unsigned SubIdx0, unsigned SubIdx1, int FI, MachineMemOperand *MMO)
static void generateGatherLanePattern(MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, SmallVectorImpl< MachineInstr * > &DelInstrs, DenseMap< Register, unsigned > &InstrIdxForVirtReg, unsigned Pattern, unsigned NumLanes)
Generate optimized instruction sequence for gather load patterns to improve Memory-Level Parallelism ...
static bool getMiscPatterns(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns)
Find other MI combine patterns.
static bool outliningCandidatesSigningKeyConsensus(const outliner::Candidate &a, const outliner::Candidate &b)
static const MachineInstrBuilder & AddSubReg(const MachineInstrBuilder &MIB, MCRegister Reg, unsigned SubIdx, RegState State, const TargetRegisterInfo *TRI)
static bool outliningCandidatesSigningScopeConsensus(const outliner::Candidate &a, const outliner::Candidate &b)
static bool shouldClusterFI(const MachineFrameInfo &MFI, int FI1, int64_t Offset1, unsigned Opcode1, int FI2, int64_t Offset2, unsigned Opcode2)
static bool isValidCBExtend(int64_t Opc, AArch64_AM::ShiftExtendType Ext)
static void extractPhiReg(const MachineInstr &Phi, const MachineBasicBlock *MBB, Register &RegMBB, Register &RegOther)
static MCCFIInstruction createDefCFAExpression(const TargetRegisterInfo &TRI, unsigned Reg, const StackOffset &Offset)
static bool isSPAddSubImm(const MachineInstr &MI)
Returns true if MI is an ADD/SUBXri with an immediate offset that reads SP but does not write SP (e....
static bool isDefinedOutside(Register Reg, const MachineBasicBlock *BB)
static MachineInstr * genFusedMultiply(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, unsigned IdxMulOpd, unsigned MaddOpc, const TargetRegisterClass *RC, FMAInstKind kind=FMAInstKind::Default, const Register *ReplacedAddend=nullptr)
genFusedMultiply - Generate fused multiply instructions.
static bool getGatherLanePattern(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns, unsigned LoadLaneOpCode, unsigned NumLanes)
Check if the given instruction forms a gather load pattern that can be optimized for better Memory-Le...
static MachineInstr * genFusedMultiplyIdxNeg(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, DenseMap< Register, unsigned > &InstrIdxForVirtReg, unsigned IdxMulOpd, unsigned MaddOpc, unsigned MnegOpc, const TargetRegisterClass *RC)
genFusedMultiplyAccNeg - Helper to generate fused multiply accumulate instructions with an additional...
static bool isCombineInstrCandidate(unsigned Opc)
static unsigned regOffsetOpcode(unsigned Opcode)
MachineOutlinerClass
Constants defining how certain sequences should be outlined.
@ MachineOutlinerTailCall
Emit a save, restore, call, and return.
@ MachineOutlinerRegSave
Emit a call and tail-call.
@ MachineOutlinerNoLRSave
Only emit a branch.
@ MachineOutlinerThunk
Emit a call and return.
@ MachineOutlinerDefault
static bool areCFlagsAliveInSuccessors(const MachineBasicBlock *MBB)
Check if AArch64::NZCV should be alive in successors of MBB.
static void emitFrameOffsetAdj(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, int64_t Offset, unsigned Opc, const TargetInstrInfo *TII, MachineInstr::MIFlag Flag, bool NeedsWinCFI, bool *HasWinCFI, bool EmitCFAOffset, StackOffset CFAOffset, unsigned FrameReg)
static bool isCheapImmediate(const MachineInstr &MI, unsigned BitSize)
static void genSubAdd2SubSub(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs, SmallVectorImpl< MachineInstr * > &DelInstrs, unsigned IdxOpd1, DenseMap< Register, unsigned > &InstrIdxForVirtReg)
Do the following transformation A - (B + C) ==> (A - B) - C A - (B + C) ==> (A - C) - B.
static unsigned canFoldIntoCSel(const MachineRegisterInfo &MRI, unsigned VReg, unsigned *NewReg=nullptr)
static void signOutlinedFunction(MachineFunction &MF, MachineBasicBlock &MBB, const AArch64InstrInfo *TII, bool ShouldSignReturnAddr)
static MachineInstr * genFNegatedMAD(MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII, MachineInstr &Root, SmallVectorImpl< MachineInstr * > &InsInstrs)
static bool canCombineWithMUL(MachineBasicBlock &MBB, MachineOperand &MO, unsigned MulOpc, unsigned ZeroReg)
static void storeRegPairToStackSlot(const TargetRegisterInfo &TRI, MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, const MCInstrDesc &MCID, Register SrcReg, bool IsKill, unsigned SubIdx0, unsigned SubIdx1, int FI, MachineMemOperand *MMO)
unsigned RegSize
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
DXIL Forward Handle Accesses
@ Default
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
A set of register units.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
PowerPC Reduce CR logical Operation
SmallVector< MachineOperand, 4 > Cond
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
This file declares the machine register scavenger class.
This file contains some templates that are useful if you are working with the STL at all.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:480
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
Definition Debug.h:72
static bool canCombine(MachineBasicBlock &MBB, MachineOperand &MO, unsigned CombineOpc=0)
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
SignReturnAddress getSignReturnAddressCondition() const
void setOutliningStyle(const std::string &Style)
bool needsDwarfUnwindInfo(const MachineFunction &MF) const
std::optional< bool > hasRedZone() const
static bool shouldSignReturnAddress(SignReturnAddress Condition, bool IsLRSpilled)
static bool isHForm(const MachineInstr &MI)
Returns whether the instruction is in H form (16 bit operands)
void insertSelect(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const DebugLoc &DL, Register DstReg, ArrayRef< MachineOperand > Cond, Register TrueReg, Register FalseReg) const override
static bool hasBTISemantics(const MachineInstr &MI)
Returns whether the instruction can be compatible with non-zero BTYPE.
static bool isQForm(const MachineInstr &MI)
Returns whether the instruction is in Q form (128 bit operands)
static bool getMemOpInfo(unsigned Opcode, TypeSize &Scale, TypeSize &Width, int64_t &MinOffset, int64_t &MaxOffset)
Returns true if opcode Opc is a memory operation.
static bool isTailCallReturnInst(const MachineInstr &MI)
Returns true if MI is one of the TCRETURN* instructions.
static bool isFPRCopy(const MachineInstr &MI)
Does this instruction rename an FPR without modifying bits?
MachineInstr * emitLdStWithAddr(MachineInstr &MemI, const ExtAddrMode &AM) const override
std::optional< DestSourcePair > isCopyInstrImpl(const MachineInstr &MI) const override
If the specific machine instruction is an instruction that moves/copies value from one register to an...
MachineBasicBlock * getBranchDestBlock(const MachineInstr &MI) const override
unsigned getInstSizeInBytes(const MachineInstr &MI) const override
GetInstSize - Return the number of bytes of code the specified instruction may be.
static bool isZExtLoad(const MachineInstr &MI)
Returns whether the instruction is a zero-extending load.
bool areMemAccessesTriviallyDisjoint(const MachineInstr &MIa, const MachineInstr &MIb) const override
void copyPhysRegImpl(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, Register DestReg, Register SrcReg, bool KillSrc, bool RenamableDest=false, bool RenamableSrc=false) const
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, Register DestReg, Register SrcReg, bool KillSrc, bool RenamableDest=false, bool RenamableSrc=false) const override
static bool isGPRCopy(const MachineInstr &MI)
Does this instruction rename a GPR without modifying bits?
static unsigned convertToFlagSettingOpc(unsigned Opc)
Return the opcode that set flags when possible.
void createPauthEpilogueInstr(MachineBasicBlock &MBB, DebugLoc DL) const
Return true when there is potentially a faster code sequence for an instruction chain ending in Root.
bool isBranchOffsetInRange(unsigned BranchOpc, int64_t BrOffset) const override
Register isLoadFromStackSlotPostFE(const MachineInstr &MI, int &FrameIndex) const override
Check for post-frame ptr elimination stack locations as well.
static const MachineOperand & getLdStOffsetOp(const MachineInstr &MI)
Returns the immediate offset operator of a load/store.
bool isCoalescableExtInstr(const MachineInstr &MI, Register &SrcReg, Register &DstReg, unsigned &SubIdx) const override
static std::optional< unsigned > getUnscaledLdSt(unsigned Opc)
Returns the unscaled load/store for the scaled load/store opcode, if there is a corresponding unscale...
static bool hasUnscaledLdStOffset(unsigned Opc)
Return true if it has an unscaled load/store offset.
static const MachineOperand & getLdStAmountOp(const MachineInstr &MI)
Returns the shift amount operator of a load/store.
static bool isPreLdSt(const MachineInstr &MI)
Returns whether the instruction is a pre-indexed load/store.
bool analyzeBranchPredicate(MachineBasicBlock &MBB, MachineBranchPredicate &MBP, bool AllowModify) const override
void insertIndirectBranch(MachineBasicBlock &MBB, MachineBasicBlock &NewDestBB, MachineBasicBlock &RestoreBB, const DebugLoc &DL, int64_t BrOffset, RegScavenger *RS) const override
void loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DestReg, int FrameIndex, const TargetRegisterClass *RC, Register VReg, unsigned SubReg=0, MachineInstr::MIFlag Flags=MachineInstr::NoFlags) const override
static bool isPairableLdStInst(const MachineInstr &MI)
Return true if pairing the given load or store may be paired with another.
void storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, bool isKill, int FrameIndex, const TargetRegisterClass *RC, Register VReg, MachineInstr::MIFlag Flags=MachineInstr::NoFlags) const override
static bool isSExtLoad(const MachineInstr &MI)
Returns whether the instruction is a sign-extending load.
const AArch64RegisterInfo & getRegisterInfo() const
getRegisterInfo - TargetInstrInfo is a superset of MRegister info.
static bool isPreSt(const MachineInstr &MI)
Returns whether the instruction is a pre-indexed store.
void insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const override
AArch64InstrInfo(const AArch64Subtarget &STI)
static bool isPairedLdSt(const MachineInstr &MI)
Returns whether the instruction is a paired load/store.
MachineInstr * foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI, ArrayRef< unsigned > Ops, int FrameIndex, MachineInstr *&CopyMI, LiveIntervals *LIS=nullptr, VirtRegMap *VRM=nullptr) const override
Register isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex) const override
bool reverseBranchCondition(SmallVectorImpl< MachineOperand > &Cond) const override
bool getMemOperandsWithOffsetWidth(const MachineInstr &MI, SmallVectorImpl< const MachineOperand * > &BaseOps, int64_t &Offset, bool &OffsetIsScalable, LocationSize &Width) const override
static bool isStridedAccess(const MachineInstr &MI)
Return true if the given load or store is a strided memory access.
bool shouldClusterMemOps(ArrayRef< const MachineOperand * > BaseOps1, int64_t Offset1, bool OffsetIsScalable1, ArrayRef< const MachineOperand * > BaseOps2, int64_t Offset2, bool OffsetIsScalable2, unsigned ClusterSize, unsigned NumBytes) const override
Detect opportunities for ldp/stp formation.
unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const override
bool isThroughputPattern(unsigned Pattern) const override
Return true when a code sequence can improve throughput.
bool canInsertSelect(const MachineBasicBlock &, ArrayRef< MachineOperand > Cond, Register, Register, Register, SelectExpansion &) const override
MachineOperand & getMemOpBaseRegImmOfsOffsetOperand(MachineInstr &LdSt) const
Return the immediate offset of the base register in a load/store LdSt.
std::optional< ExtAddrMode > getAddrModeFromMemoryOp(const MachineInstr &MemI) const override
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify=false) const override
bool canFoldIntoAddrMode(const MachineInstr &MemI, Register Reg, const MachineInstr &AddrI, ExtAddrMode &AM) const override
static bool isLdStPairSuppressed(const MachineInstr &MI)
Return true if pairing the given load or store is hinted to be unprofitable.
Register isStoreToStackSlotPostFE(const MachineInstr &MI, int &FrameIndex) const override
Check for post-frame ptr elimination stack locations as well.
std::unique_ptr< TargetInstrInfo::PipelinerLoopInfo > analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override
void copyPhysRegTuple(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, bool KillSrc, llvm::ArrayRef< unsigned > Indices) const
bool isSchedulingBoundary(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const override
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef< MachineOperand > Cond, const DebugLoc &DL, int *BytesAdded=nullptr) const override
AArch64CC::CondCode insertCmpForCondBr(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const DebugLoc &DL, ArrayRef< MachineOperand > Cond) const
Inserts the compare instruction needed to un-fuse a fused conditional branch instruction and returns ...
bool optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg, Register SrcReg2, int64_t CmpMask, int64_t CmpValue, const MachineRegisterInfo *MRI) const override
optimizeCompareInstr - Convert the instruction supplying the argument to the comparison into one that...
static unsigned getLoadStoreImmIdx(unsigned Opc)
Returns the index for the immediate for a given instruction.
static bool isGPRZero(const MachineInstr &MI)
Does this instruction set its full destination register to zero?
void copyGPRRegTuple(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, bool KillSrc, unsigned Opcode, unsigned ZeroReg, llvm::ArrayRef< unsigned > Indices) const
bool getMemOperandWithOffsetWidth(const MachineInstr &MI, const MachineOperand *&BaseOp, int64_t &Offset, bool &OffsetIsScalable, TypeSize &Width) const
If OffsetIsScalable is set to 'true', the offset is scaled by vscale.
bool analyzeCompare(const MachineInstr &MI, Register &SrcReg, Register &SrcReg2, int64_t &CmpMask, int64_t &CmpValue) const override
analyzeCompare - For a comparison instruction, return the source registers in SrcReg and SrcReg2,...
CombinerObjective getCombinerObjective(unsigned Pattern) const override
static bool isFpOrNEON(Register Reg)
Returns whether the physical register is FP or NEON.
bool isAsCheapAsAMove(const MachineInstr &MI) const override
std::optional< DestSourcePair > isCopyLikeInstrImpl(const MachineInstr &MI) const override
static void suppressLdStPair(MachineInstr &MI)
Hint that pairing the given load or store is unprofitable.
Register isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const override
static bool isPreLd(const MachineInstr &MI)
Returns whether the instruction is a pre-indexed load.
bool optimizeCondBranch(MachineInstr &MI) const override
Replace csincr-branch sequence by simple conditional branch.
static int getMemScale(unsigned Opc)
Scaling factor for (scaled or unscaled) load or store.
bool isCandidateToMergeOrPair(const MachineInstr &MI) const
Return true if this is a load/store that can be potentially paired/merged.
MCInst getNop() const override
static const MachineOperand & getLdStBaseOp(const MachineInstr &MI)
Returns the base register operator of a load/store.
bool isReservedReg(const MachineFunction &MF, MCRegister Reg) const
const AArch64RegisterInfo * getRegisterInfo() const override
bool isNeonAvailable() const
Returns true if the target has NEON and the function at runtime is known to have NEON enabled (e....
bool isSVEorStreamingSVEAvailable() const
Returns true if the target has access to either the full range of SVE instructions,...
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
This is an important base class in LLVM.
Definition Constant.h:44
A debug info location.
Definition DebugLoc.h:126
bool empty() const
Definition DenseMap.h:716
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:827
bool hasOptSize() const
Optimize this function for size (-Os) or minimum size (-Oz).
Definition Function.h:699
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
Definition Function.h:696
Module * getParent()
Get the module that this global value is contained inside of...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
A set of register units used to track register liveness.
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
LLVM_ABI void accumulate(const MachineInstr &MI)
Adds all register units used, defined or clobbered in MI.
static LocationSize precise(uint64_t Value)
This class is intended to be used as a base class for asm properties and features specific to the tar...
Definition MCAsmInfo.h:67
static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa defines a rule for computing CFA as: take address from Register and add Offset to it.
Definition MCDwarf.h:628
static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_offset Previous value of Register is saved at offset Offset from CFA.
Definition MCDwarf.h:670
static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa_offset modifies a rule for computing CFA.
Definition MCDwarf.h:643
static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals, SMLoc Loc={}, StringRef Comment="")
.cfi_escape Allows the user to add arbitrary bytes to the unwind info.
Definition MCDwarf.h:756
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Describe properties that are true of each instruction in the target description file.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
ArrayRef< MCOperandInfo > operands() const
bool hasSuperClassEq(const MCRegisterClass *RC) const
Returns true if RC is a super-class of or equal to this class.
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
constexpr bool isValid() const
Definition MCRegister.h:84
static constexpr unsigned NoRegister
Definition MCRegister.h:60
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1579
Set of metadata that should be preserved when using BuildMI().
bool isInlineAsmBrIndirectTarget() const
Returns true if this is the indirect dest of an INLINEASM_BR.
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
reverse_instr_iterator instr_rbegin()
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
reverse_instr_iterator instr_rend()
Instructions::iterator instr_iterator
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
void setMachineBlockAddressTaken()
Set this block to indicate that its address is used as something other than the target of a terminato...
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
void setStackID(int ObjectIdx, uint8_t ID)
bool isCalleeSavedInfoValid() const
Has the callee saved info been calculated yet?
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
unsigned getNumObjects() const
Return the number of objects.
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
bool isFixedObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a fixed stack object.
unsigned addFrameInst(const MCCFIInstruction &Inst)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
bool usesWindowsUnwindInfo() const
True if this function describes its unwind information with Windows SEH unwind opcodes (....
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addCFIIndex(unsigned CFIIndex) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
reverse_iterator getReverse() const
Get a reverse iterator to the same node.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
bool isCopy() const
const MachineBasicBlock * getParent() const
bool isCall(QueryType Type=AnyInBundle) const
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
LLVM_ABI uint32_t mergeFlagsWith(const MachineInstr &Other) const
Return the MIFlags which represent both MachineInstrs.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
LLVM_ABI bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by mayLoad / mayStore,...
bool registerDefIsDead(Register Reg, const TargetRegisterInfo *TRI) const
Returns true if the register is dead in this machine instruction.
bool definesRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr fully defines the specified register.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
LLVM_ABI bool hasOrderedMemoryRef() const
Return true if this instruction may have an ordered or volatile memory reference, or if the informati...
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
ArrayRef< MachineMemOperand * > memoperands() const
Access to memory operands of the instruction.
LLVM_ABI bool isLoadFoldBarrier() const
Returns true if it is illegal to fold a load across this instruction.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
LLVM_ABI void addRegisterDefined(Register Reg, const TargetRegisterInfo *RegInfo=nullptr)
We have determined MI defines a register.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const std::vector< MachineJumpTableEntry > & getJumpTables() const
A description of a memory reference used in the backend.
@ MOVolatile
The memory access is volatile.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
This class contains meta information specific to a module.
LLVM_ABI MachineFunction * getMachineFunction(const Function &F) const
Returns the MachineFunction associated to IR function F if there is one, otherwise nullptr.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
void setImm(int64_t immVal)
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
void setIsDead(bool Val=true)
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
unsigned getTargetFlags() const
static MachineOperand CreateImm(int64_t Val)
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
bool tracksLiveness() const
tracksLiveness - Returns true when tracking register liveness accurately.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
bool reservedRegsFrozen() const
reservedRegsFrozen - Returns true after freezeReservedRegs() was called to ensure the set of reserved...
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition Module.h:328
MI-level patchpoint operands.
Definition StackMaps.h:77
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given patchpoint should emit.
Definition StackMaps.h:105
Wrapper class representing virtual and physical registers.
Definition Register.h:20
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
Definition Register.h:107
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
static constexpr bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:66
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
Represents a location in source code.
Definition SMLoc.h:22
bool erase(PtrType Ptr)
Remove pointer from the set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
bool empty() const
Definition SmallSet.h:169
bool erase(const T &V)
Definition SmallSet.h:200
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
void append(StringRef RHS)
Append from a StringRef.
Definition SmallString.h:68
StringRef str() const
Explicit conversion to StringRef.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
MI-level stackmap operands.
Definition StackMaps.h:36
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given stackmap should emit.
Definition StackMaps.h:51
StackOffset holds a fixed and a scalable offset in bytes.
Definition TypeSize.h:31
int64_t getFixed() const
Returns the fixed component of the stack.
Definition TypeSize.h:47
int64_t getScalable() const
Returns the scalable component of the stack.
Definition TypeSize.h:50
static StackOffset get(int64_t Fixed, int64_t Scalable)
Definition TypeSize.h:42
static StackOffset getScalable(int64_t Scalable)
Definition TypeSize.h:41
static StackOffset getFixed(int64_t Fixed)
Definition TypeSize.h:40
MI-level Statepoint operands.
Definition StackMaps.h:159
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given statepoint should emit.
Definition StackMaps.h:208
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Object returned by analyzeLoopForPipelining.
TargetInstrInfo - Interface to description of machine instruction set.
virtual void genAlternativeCodeSequence(MachineInstr &Root, unsigned Pattern, SmallVectorImpl< MachineInstr * > &InsInstrs, SmallVectorImpl< MachineInstr * > &DelInstrs, DenseMap< Register, unsigned > &InstIdxForVirtReg) const
When getMachineCombinerPatterns() finds patterns, this function generates the instructions that could...
virtual std::optional< ParamLoadedValue > describeLoadedValue(const MachineInstr &MI, Register Reg) const
Produce the expression describing the MI loading a value into the physical register Reg.
virtual bool getMachineCombinerPatterns(MachineInstr &Root, SmallVectorImpl< unsigned > &Patterns, bool DoRegPressureReduce) const
Return true when there is potentially a faster code sequence for an instruction chain ending in Root.
virtual bool isFunctionSafeToOutlineFrom(MachineFunction &MF, bool OutlineFromLinkOnceODRs) const
Return true if the function can safely be outlined from.
virtual bool isSchedulingBoundary(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const
Test if the given instruction should be considered a scheduling boundary.
virtual CombinerObjective getCombinerObjective(unsigned Pattern) const
Return the objective of a combiner pattern.
virtual bool isFunctionSafeToSplit(const MachineFunction &MF) const
Return true if the function is a viable candidate for machine function splitting.
const MCAsmInfo & getMCAsmInfo() const
Return target specific asm information.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
Target - Wrapper for Target specific information.
bool isOSBinFormatMachO() const
Tests whether the environment is MachO.
Definition Triple.h:876
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:352
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Definition TypeSize.h:355
Value * getOperand(unsigned i) const
Definition User.h:207
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
Definition TypeSize.h:169
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
self_iterator getIterator()
Definition ilist_node.h:123
A raw_ostream that writes to an std::string.
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
@ MO_DLLIMPORT
MO_DLLIMPORT - On a symbol operand, this represents that the reference to the symbol is for an import...
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_S
MO_S - Indicates that the bits of the symbol operand represented by MO_G0 etc are signed.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_PREL
MO_PREL - Indicates that the bits of the symbol operand represented by MO_G0 etc are PC relative.
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_ARM64EC_CALLMANGLE
MO_ARM64EC_CALLMANGLE - Operand refers to the Arm64EC-mangled version of a symbol,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_HI12
MO_HI12 - This flag indicates that a symbol operand represents the bits 13-24 of a 64-bit address,...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_TAGGED
MO_TAGGED - With MO_PAGE, indicates that the page includes a memory tag in bits 56-63.
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
@ MO_COFFSTUB
MO_COFFSTUB - On a symbol operand "FOO", this indicates that the reference is actually to the "....
unsigned getCheckerSizeInBytes(AuthCheckMethod Method)
Returns the number of bytes added by checkAuthenticatedRegister.
static uint64_t decodeLogicalImmediate(uint64_t val, unsigned regSize)
decodeLogicalImmediate - Decode a logical immediate value in the form "N:immr:imms" (where the immr a...
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, unsigned Imm)
getArithExtendImm - Encode the extend type and shift amount for an arithmetic instruction: imm: 3-bit...
constexpr bool isLegalArithImmed(const uint64_t C)
isLegalArithImmed -
static unsigned getArithShiftValue(unsigned Imm)
getArithShiftValue - get the arithmetic shift value.
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static AArch64_AM::ShiftExtendType getExtendType(unsigned Imm)
getExtendType - Extract the extend type for operands of arithmetic ops.
static AArch64_AM::ShiftExtendType getArithExtendType(unsigned Imm)
static AArch64_AM::ShiftExtendType getShiftType(unsigned Imm)
getShiftType - Extract the shift type.
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
void expandMOVAddr(unsigned Opcode, unsigned TargetFlags, bool IsTargetMachO, SmallVectorImpl< AddrInsnModel > &Insn)
void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...
static const uint64_t InstrFlagIsWhile
static const uint64_t InstrFlagIsPTestLike
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
constexpr double e
InstrType
Represents how an instruction should be mapped by the outliner.
NodeAddr< InstrNode * > Instr
Definition RDFGraph.h:389
iterator end() const
Definition BasicBlock.h:89
LLVM_ABI Instruction & back() const
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
static bool isCondBranchOpcode(int Opc)
MCCFIInstruction createDefCFA(const TargetRegisterInfo &TRI, unsigned FrameReg, unsigned Reg, const StackOffset &Offset, bool LastAdjustmentWasScalable=true)
static bool isPTrueOpcode(unsigned Opc)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
int isAArch64FrameOffsetLegal(const MachineInstr &MI, StackOffset &Offset, bool *OutUseUnscaledOp=nullptr, unsigned *OutUnscaledOp=nullptr, int64_t *EmittableOffset=nullptr)
Check if the Offset is a valid frame offset for MI.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
RegState
Flags to represent properties of register accesses.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Dead
Unused definition.
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
@ Define
Register definition.
@ Renamable
Register that may be renamed.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
constexpr RegState getKillRegState(bool B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
static bool isIndirectBranchOpcode(int Opc)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
@ AArch64FrameOffsetIsLegal
Offset is legal.
@ AArch64FrameOffsetCanUpdate
Offset can apply, at least partly.
@ AArch64FrameOffsetCannotUpdate
Offset cannot apply.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
Op::Description Desc
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
static bool isSEHInstruction(const MachineInstr &MI)
bool isLFIPrePostMemAccess(unsigned Opcode)
Returns true if Opcode is a pre- or post-indexed memory access that the LFI rewriter expands with a b...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
AArch64MachineCombinerPattern
@ MULSUBv8i16_OP2
@ FMULv4i16_indexed_OP1
@ FMLSv1i32_indexed_OP2
@ MULSUBv2i32_indexed_OP1
@ FMLAv2i32_indexed_OP2
@ MULADDv4i16_indexed_OP2
@ FMLAv1i64_indexed_OP1
@ MULSUBv16i8_OP1
@ FMLAv8i16_indexed_OP2
@ FMULv2i32_indexed_OP1
@ MULSUBv8i16_indexed_OP2
@ FMLAv1i64_indexed_OP2
@ MULSUBv4i16_indexed_OP2
@ FMLAv1i32_indexed_OP1
@ FMLAv2i64_indexed_OP2
@ FMLSv8i16_indexed_OP1
@ MULSUBv2i32_OP1
@ FMULv4i16_indexed_OP2
@ MULSUBv4i32_indexed_OP2
@ FMULv2i64_indexed_OP2
@ FMLAv4i32_indexed_OP1
@ MULADDv4i16_OP2
@ FMULv8i16_indexed_OP2
@ MULSUBv4i16_OP1
@ MULADDv4i32_OP2
@ MULADDv2i32_OP2
@ MULADDv16i8_OP2
@ FMLSv4i16_indexed_OP1
@ MULADDv16i8_OP1
@ FMLAv2i64_indexed_OP1
@ FMLAv1i32_indexed_OP2
@ FMLSv2i64_indexed_OP2
@ MULADDv2i32_OP1
@ MULADDv4i32_OP1
@ MULADDv2i32_indexed_OP1
@ MULSUBv16i8_OP2
@ MULADDv4i32_indexed_OP1
@ MULADDv2i32_indexed_OP2
@ FMLAv4i16_indexed_OP2
@ MULSUBv8i16_OP1
@ FMULv2i32_indexed_OP2
@ FMLSv2i32_indexed_OP2
@ FMLSv4i32_indexed_OP1
@ FMULv2i64_indexed_OP1
@ MULSUBv4i16_OP2
@ FMLSv4i16_indexed_OP2
@ FMLAv2i32_indexed_OP1
@ FMLSv2i32_indexed_OP1
@ FMLAv8i16_indexed_OP1
@ MULSUBv4i16_indexed_OP1
@ FMLSv4i32_indexed_OP2
@ MULADDv4i32_indexed_OP2
@ MULSUBv4i32_OP2
@ MULSUBv8i16_indexed_OP1
@ MULADDv8i16_OP2
@ MULSUBv2i32_indexed_OP2
@ FMULv4i32_indexed_OP2
@ FMLSv2i64_indexed_OP1
@ MULADDv4i16_OP1
@ FMLAv4i32_indexed_OP2
@ MULADDv8i16_indexed_OP1
@ FMULv4i32_indexed_OP1
@ FMLAv4i16_indexed_OP1
@ FMULv8i16_indexed_OP1
@ MULADDv8i16_OP1
@ MULSUBv4i32_indexed_OP1
@ MULSUBv4i32_OP1
@ FMLSv8i16_indexed_OP2
@ MULADDv8i16_indexed_OP2
@ MULSUBv2i32_OP2
@ FMLSv1i64_indexed_OP2
@ MULADDv4i16_indexed_OP1
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, StackOffset Offset, const TargetInstrInfo *TII, MachineInstr::MIFlag=MachineInstr::NoFlags, bool SetNZCV=false, bool NeedsWinCFI=false, bool *HasWinCFI=nullptr, bool EmitCFAOffset=false, StackOffset InitialOffset={}, unsigned FrameReg=AArch64::SP)
emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg plus Offset.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1769
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr RegState getDefRegState(bool B)
CombinerObjective
The combiner's goal may differ based on which pattern it is attempting to optimize.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
std::optional< UsedNZCV > examineCFlagsUse(MachineInstr &MI, MachineInstr &CmpInstr, const TargetRegisterInfo &TRI, SmallVectorImpl< MachineInstr * > *CCUseInstrs=nullptr)
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:280
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
auto drop_end(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the last N elements excluded.
Definition STLExtras.h:323
static MCRegister getXRegFromWReg(MCRegister Reg)
MCCFIInstruction createCFAOffset(const TargetRegisterInfo &MRI, unsigned Reg, const StackOffset &OffsetFromDefCFA, std::optional< int64_t > IncomingVGOffsetFromDefCFA)
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
static bool isUncondBranchOpcode(int Opc)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Definition STLExtras.h:2208
constexpr bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
Definition MathExtras.h:249
bool rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx, unsigned FrameReg, StackOffset &Offset, const AArch64InstrInfo *TII)
rewriteAArch64FrameIndex - Rewrite MI to access 'Offset' bytes from the FP.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
static const MachineMemOperand::Flags MOSuppressPair
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
Definition MathExtras.h:572
void appendLEB128(SmallVectorImpl< U > &Buffer, T Value)
Definition LEB128.h:280
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
bool optimizeTerminators(MachineBasicBlock *MBB, const TargetInstrInfo &TII)
std::pair< MachineOperand, DIExpression * > ParamLoadedValue
bool isNZCVTouchedInInstructionRange(const MachineInstr &DefMI, const MachineInstr &UseMI, const TargetRegisterInfo *TRI)
Return true if there is an instruction /after/ DefMI and before UseMI which either reads or clobbers ...
static const MachineMemOperand::Flags MOStridedAccess
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
constexpr RegState getUndefRegState(bool B)
void fullyRecomputeLiveIns(ArrayRef< MachineBasicBlock * > MBBs)
Convenience function for recomputing live-in's for a set of MBBs until the computation converges.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
Used to describe addressing mode similar to ExtAddrMode in CodeGenPrepare.
LLVM_ABI static const MBBSectionID ColdSectionID
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
An individual sequence of instructions to be replaced with a call to an outlined function.
MachineFunction * getMF() const
The information necessary to create an outlined function for some class of candidate.