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 }
1337 }
1338
1339 // Pull all virtual register into the appropriate class.
1340 MRI.constrainRegClass(TrueReg, RC);
1341 // FalseReg might be WZR or XZR if the folded operand is a literal 1.
1342 assert(
1343 (FalseReg.isVirtual() || FalseReg == AArch64::WZR ||
1344 FalseReg == AArch64::XZR) &&
1345 "FalseReg was folded into a non-virtual register other than WZR or XZR");
1346 if (FalseReg.isVirtual())
1347 MRI.constrainRegClass(FalseReg, RC);
1348
1349 // Insert the csel.
1350 BuildMI(MBB, I, DL, get(Opc), DstReg)
1351 .addReg(TrueReg)
1352 .addReg(FalseReg)
1353 .addImm(CC);
1354}
1355
1356// Return true if Imm can be loaded into a register by a "cheap" sequence of
1357// instructions. For now, "cheap" means at most two instructions.
1358static bool isCheapImmediate(const MachineInstr &MI, unsigned BitSize) {
1359 if (BitSize == 32)
1360 return true;
1361
1362 assert(BitSize == 64 && "Only bit sizes of 32 or 64 allowed");
1363 uint64_t Imm = static_cast<uint64_t>(MI.getOperand(1).getImm());
1365 AArch64_IMM::expandMOVImm(Imm, BitSize, Is);
1366
1367 return Is.size() <= 2;
1368}
1369
1370// Check if a COPY instruction is cheap.
1371static bool isCheapCopy(const MachineInstr &MI, const AArch64RegisterInfo &RI) {
1372 assert(MI.isCopy() && "Expected COPY instruction");
1373 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1374
1375 // Cross-bank copies (e.g., between GPR and FPR) are expensive on AArch64,
1376 // typically requiring an FMOV instruction with a 2-6 cycle latency.
1377 auto GetRegClass = [&](Register Reg) -> const TargetRegisterClass * {
1378 if (Reg.isVirtual())
1379 return MRI.getRegClass(Reg);
1380 if (Reg.isPhysical())
1381 return RI.getMinimalPhysRegClass(Reg);
1382 return nullptr;
1383 };
1384 const TargetRegisterClass *DstRC = GetRegClass(MI.getOperand(0).getReg());
1385 const TargetRegisterClass *SrcRC = GetRegClass(MI.getOperand(1).getReg());
1386 if (DstRC && SrcRC && !RI.getCommonSubClass(DstRC, SrcRC))
1387 return false;
1388
1389 return MI.isAsCheapAsAMove();
1390}
1391
1392// FIXME: this implementation should be micro-architecture dependent, so a
1393// micro-architecture target hook should be introduced here in future.
1395 if (Subtarget.hasExynosCheapAsMoveHandling()) {
1396 if (isExynosCheapAsMove(MI))
1397 return true;
1398 return MI.isAsCheapAsAMove();
1399 }
1400
1401 switch (MI.getOpcode()) {
1402 default:
1403 return MI.isAsCheapAsAMove();
1404
1405 case TargetOpcode::COPY:
1406 return isCheapCopy(MI, RI);
1407
1408 case AArch64::ADDWrs:
1409 case AArch64::ADDXrs:
1410 case AArch64::SUBWrs:
1411 case AArch64::SUBXrs:
1412 return Subtarget.hasALULSLFast() && MI.getOperand(3).getImm() <= 4;
1413
1414 // If MOVi32imm or MOVi64imm can be expanded into ORRWri or
1415 // ORRXri, it is as cheap as MOV.
1416 // Likewise if it can be expanded to MOVZ/MOVN/MOVK.
1417 case AArch64::MOVi32imm:
1418 return isCheapImmediate(MI, 32);
1419 case AArch64::MOVi64imm:
1420 return isCheapImmediate(MI, 64);
1421 }
1422}
1423
1424bool AArch64InstrInfo::isFalkorShiftExtFast(const MachineInstr &MI) {
1425 switch (MI.getOpcode()) {
1426 default:
1427 return false;
1428
1429 case AArch64::ADDWrs:
1430 case AArch64::ADDXrs:
1431 case AArch64::ADDSWrs:
1432 case AArch64::ADDSXrs: {
1433 unsigned Imm = MI.getOperand(3).getImm();
1434 unsigned ShiftVal = AArch64_AM::getShiftValue(Imm);
1435 if (ShiftVal == 0)
1436 return true;
1437 return AArch64_AM::getShiftType(Imm) == AArch64_AM::LSL && ShiftVal <= 5;
1438 }
1439
1440 case AArch64::ADDWrx:
1441 case AArch64::ADDXrx:
1442 case AArch64::ADDXrx64:
1443 case AArch64::ADDSWrx:
1444 case AArch64::ADDSXrx:
1445 case AArch64::ADDSXrx64: {
1446 unsigned Imm = MI.getOperand(3).getImm();
1448 default:
1449 return false;
1450 case AArch64_AM::UXTB:
1451 case AArch64_AM::UXTH:
1452 case AArch64_AM::UXTW:
1453 case AArch64_AM::UXTX:
1455 }
1456 }
1457
1458 case AArch64::SUBWrs:
1459 case AArch64::SUBSWrs: {
1460 unsigned Imm = MI.getOperand(3).getImm();
1461 unsigned ShiftVal = AArch64_AM::getShiftValue(Imm);
1462 return ShiftVal == 0 ||
1463 (AArch64_AM::getShiftType(Imm) == AArch64_AM::ASR && ShiftVal == 31);
1464 }
1465
1466 case AArch64::SUBXrs:
1467 case AArch64::SUBSXrs: {
1468 unsigned Imm = MI.getOperand(3).getImm();
1469 unsigned ShiftVal = AArch64_AM::getShiftValue(Imm);
1470 return ShiftVal == 0 ||
1471 (AArch64_AM::getShiftType(Imm) == AArch64_AM::ASR && ShiftVal == 63);
1472 }
1473
1474 case AArch64::SUBWrx:
1475 case AArch64::SUBXrx:
1476 case AArch64::SUBXrx64:
1477 case AArch64::SUBSWrx:
1478 case AArch64::SUBSXrx:
1479 case AArch64::SUBSXrx64: {
1480 unsigned Imm = MI.getOperand(3).getImm();
1482 default:
1483 return false;
1484 case AArch64_AM::UXTB:
1485 case AArch64_AM::UXTH:
1486 case AArch64_AM::UXTW:
1487 case AArch64_AM::UXTX:
1489 }
1490 }
1491
1492 case AArch64::LDRBBroW:
1493 case AArch64::LDRBBroX:
1494 case AArch64::LDRBroW:
1495 case AArch64::LDRBroX:
1496 case AArch64::LDRDroW:
1497 case AArch64::LDRDroX:
1498 case AArch64::LDRHHroW:
1499 case AArch64::LDRHHroX:
1500 case AArch64::LDRHroW:
1501 case AArch64::LDRHroX:
1502 case AArch64::LDRQroW:
1503 case AArch64::LDRQroX:
1504 case AArch64::LDRSBWroW:
1505 case AArch64::LDRSBWroX:
1506 case AArch64::LDRSBXroW:
1507 case AArch64::LDRSBXroX:
1508 case AArch64::LDRSHWroW:
1509 case AArch64::LDRSHWroX:
1510 case AArch64::LDRSHXroW:
1511 case AArch64::LDRSHXroX:
1512 case AArch64::LDRSWroW:
1513 case AArch64::LDRSWroX:
1514 case AArch64::LDRSroW:
1515 case AArch64::LDRSroX:
1516 case AArch64::LDRWroW:
1517 case AArch64::LDRWroX:
1518 case AArch64::LDRXroW:
1519 case AArch64::LDRXroX:
1520 case AArch64::PRFMroW:
1521 case AArch64::PRFMroX:
1522 case AArch64::STRBBroW:
1523 case AArch64::STRBBroX:
1524 case AArch64::STRBroW:
1525 case AArch64::STRBroX:
1526 case AArch64::STRDroW:
1527 case AArch64::STRDroX:
1528 case AArch64::STRHHroW:
1529 case AArch64::STRHHroX:
1530 case AArch64::STRHroW:
1531 case AArch64::STRHroX:
1532 case AArch64::STRQroW:
1533 case AArch64::STRQroX:
1534 case AArch64::STRSroW:
1535 case AArch64::STRSroX:
1536 case AArch64::STRWroW:
1537 case AArch64::STRWroX:
1538 case AArch64::STRXroW:
1539 case AArch64::STRXroX: {
1540 unsigned IsSigned = MI.getOperand(3).getImm();
1541 return !IsSigned;
1542 }
1543 }
1544}
1545
1546bool AArch64InstrInfo::isSEHInstruction(const MachineInstr &MI) {
1547 unsigned Opc = MI.getOpcode();
1548 switch (Opc) {
1549 default:
1550 return false;
1551 case AArch64::SEH_EndC:
1552 case AArch64::SEH_StackAlloc:
1553 case AArch64::SEH_SaveFPLR:
1554 case AArch64::SEH_SaveFPLR_X:
1555 case AArch64::SEH_SaveReg:
1556 case AArch64::SEH_SaveReg_X:
1557 case AArch64::SEH_SaveRegP:
1558 case AArch64::SEH_SaveRegP_X:
1559 case AArch64::SEH_SaveFReg:
1560 case AArch64::SEH_SaveFReg_X:
1561 case AArch64::SEH_SaveFRegP:
1562 case AArch64::SEH_SaveFRegP_X:
1563 case AArch64::SEH_SetFP:
1564 case AArch64::SEH_AddFP:
1565 case AArch64::SEH_Nop:
1566 case AArch64::SEH_PrologEnd:
1567 case AArch64::SEH_EpilogStart:
1568 case AArch64::SEH_EpilogEnd:
1569 case AArch64::SEH_PACSignLR:
1570 case AArch64::SEH_SaveAnyRegI:
1571 case AArch64::SEH_SaveAnyRegIP:
1572 case AArch64::SEH_SaveAnyRegQ:
1573 case AArch64::SEH_SaveAnyRegQX:
1574 case AArch64::SEH_SaveAnyRegQP:
1575 case AArch64::SEH_SaveAnyRegQPX:
1576 case AArch64::SEH_AllocZ:
1577 case AArch64::SEH_SaveZReg:
1578 case AArch64::SEH_SavePReg:
1579 return true;
1580 }
1581}
1582
1584 Register &SrcReg, Register &DstReg,
1585 unsigned &SubIdx) const {
1586 switch (MI.getOpcode()) {
1587 default:
1588 return false;
1589 case AArch64::SBFMXri: // aka sxtw
1590 case AArch64::UBFMXri: // aka uxtw
1591 // Check for the 32 -> 64 bit extension case, these instructions can do
1592 // much more.
1593 if (MI.getOperand(2).getImm() != 0 || MI.getOperand(3).getImm() != 31)
1594 return false;
1595 // This is a signed or unsigned 32 -> 64 bit extension.
1596 SrcReg = MI.getOperand(1).getReg();
1597 DstReg = MI.getOperand(0).getReg();
1598 SubIdx = AArch64::sub_32;
1599 return true;
1600 }
1601}
1602
1604 const MachineInstr &MIa, const MachineInstr &MIb) const {
1605 const MachineOperand *BaseOpA = nullptr, *BaseOpB = nullptr;
1606 int64_t OffsetA = 0, OffsetB = 0;
1607 TypeSize WidthA(0, false), WidthB(0, false);
1608 bool OffsetAIsScalable = false, OffsetBIsScalable = false;
1609
1610 assert(MIa.mayLoadOrStore() && "MIa must be a load or store.");
1611 assert(MIb.mayLoadOrStore() && "MIb must be a load or store.");
1612
1615 return false;
1616
1617 // Retrieve the base, offset from the base and width. Width
1618 // is the size of memory that is being loaded/stored (e.g. 1, 2, 4, 8). If
1619 // base are identical, and the offset of a lower memory access +
1620 // the width doesn't overlap the offset of a higher memory access,
1621 // then the memory accesses are different.
1622 // If OffsetAIsScalable and OffsetBIsScalable are both true, they
1623 // are assumed to have the same scale (vscale).
1624 if (getMemOperandWithOffsetWidth(MIa, BaseOpA, OffsetA, OffsetAIsScalable,
1625 WidthA) &&
1626 getMemOperandWithOffsetWidth(MIb, BaseOpB, OffsetB, OffsetBIsScalable,
1627 WidthB)) {
1628 if (BaseOpA->isIdenticalTo(*BaseOpB) &&
1629 OffsetAIsScalable == OffsetBIsScalable) {
1630 int LowOffset = OffsetA < OffsetB ? OffsetA : OffsetB;
1631 int HighOffset = OffsetA < OffsetB ? OffsetB : OffsetA;
1632 TypeSize LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB;
1633 if (LowWidth.isScalable() == OffsetAIsScalable &&
1634 LowOffset + (int)LowWidth.getKnownMinValue() <= HighOffset)
1635 return true;
1636 }
1637 }
1638 return false;
1639}
1640
1642 const MachineBasicBlock *MBB,
1643 const MachineFunction &MF) const {
1645 return true;
1646
1647 // Do not move an instruction that can be recognized as a branch target.
1648 if (hasBTISemantics(MI))
1649 return true;
1650
1651 switch (MI.getOpcode()) {
1652 case AArch64::HINT:
1653 // CSDB hints are scheduling barriers.
1654 if (MI.getOperand(0).getImm() == 0x14)
1655 return true;
1656 break;
1657 case AArch64::DSB:
1658 case AArch64::ISB:
1659 // DSB and ISB also are scheduling barriers.
1660 return true;
1661 case AArch64::MSRpstatesvcrImm1:
1662 // SMSTART and SMSTOP are also scheduling barriers.
1663 return true;
1664 default:;
1665 }
1666 if (isSEHInstruction(MI))
1667 return true;
1668 // Skip debug instructions and pseudo probes so they do not change
1669 // scheduling regions.
1670 auto Next = next_nodbg(MI.getIterator(), MBB->instr_end());
1671 return Next != MBB->instr_end() && Next->isCFIInstruction();
1672}
1673
1674/// analyzeCompare - For a comparison instruction, return the source registers
1675/// in SrcReg and SrcReg2, and the value it compares against in CmpValue.
1676/// Return true if the comparison instruction can be analyzed.
1678 Register &SrcReg2, int64_t &CmpMask,
1679 int64_t &CmpValue) const {
1680 // The first operand can be a frame index where we'd normally expect a
1681 // register.
1682 // FIXME: Pass subregisters out of analyzeCompare
1683 assert(MI.getNumOperands() >= 2 && "All AArch64 cmps should have 2 operands");
1684 if (!MI.getOperand(1).isReg() || MI.getOperand(1).getSubReg())
1685 return false;
1686
1687 switch (MI.getOpcode()) {
1688 default:
1689 break;
1690 case AArch64::PTEST_PP:
1691 case AArch64::PTEST_PP_ANY:
1692 case AArch64::PTEST_PP_FIRST:
1693 SrcReg = MI.getOperand(0).getReg();
1694 SrcReg2 = MI.getOperand(1).getReg();
1695 if (MI.getOperand(2).getSubReg())
1696 return false;
1697
1698 // Not sure about the mask and value for now...
1699 CmpMask = ~0;
1700 CmpValue = 0;
1701 return true;
1702 case AArch64::SUBSWrr:
1703 case AArch64::SUBSWrs:
1704 case AArch64::SUBSWrx:
1705 case AArch64::SUBSXrr:
1706 case AArch64::SUBSXrs:
1707 case AArch64::SUBSXrx:
1708 case AArch64::ADDSWrr:
1709 case AArch64::ADDSWrs:
1710 case AArch64::ADDSWrx:
1711 case AArch64::ADDSXrr:
1712 case AArch64::ADDSXrs:
1713 case AArch64::ADDSXrx:
1714 // Replace SUBSWrr with SUBWrr if NZCV is not used.
1715 SrcReg = MI.getOperand(1).getReg();
1716 SrcReg2 = MI.getOperand(2).getReg();
1717
1718 // FIXME: Pass subregisters out of analyzeCompare
1719 if (MI.getOperand(2).getSubReg())
1720 return false;
1721
1722 CmpMask = ~0;
1723 CmpValue = 0;
1724 return true;
1725 case AArch64::SUBSWri:
1726 case AArch64::ADDSWri:
1727 case AArch64::SUBSXri:
1728 case AArch64::ADDSXri:
1729 SrcReg = MI.getOperand(1).getReg();
1730 SrcReg2 = 0;
1731 CmpMask = ~0;
1732 CmpValue = MI.getOperand(2).getImm();
1733 return true;
1734 case AArch64::ANDSWri:
1735 case AArch64::ANDSXri:
1736 // ANDS does not use the same encoding scheme as the others xxxS
1737 // instructions.
1738 SrcReg = MI.getOperand(1).getReg();
1739 SrcReg2 = 0;
1740 CmpMask = ~0;
1742 MI.getOperand(2).getImm(),
1743 MI.getOpcode() == AArch64::ANDSWri ? 32 : 64);
1744 return true;
1745 }
1746
1747 return false;
1748}
1749
1751 MachineBasicBlock *MBB = Instr.getParent();
1752 assert(MBB && "Can't get MachineBasicBlock here");
1753 MachineFunction *MF = MBB->getParent();
1754 assert(MF && "Can't get MachineFunction here");
1758
1759 for (const auto &[OpIdx, MO] : enumerate(Instr.operands())) {
1760 if (!MO.isReg() || !MO.getReg().isVirtual())
1761 continue;
1762
1763 Register Reg = MO.getReg();
1764 const TargetRegisterClass *NewRC = Instr.getRegClassConstraintEffect(
1765 OpIdx, MRI->getRegClass(Reg), TII, TRI);
1766 if (!NewRC || !MRI->constrainRegClass(Reg, NewRC))
1767 llvm_unreachable("Operand register classes are incompatible");
1768 }
1769}
1770
1771/// Return the opcode that does not set flags when possible - otherwise
1772/// return the original opcode. The caller is responsible to do the actual
1773/// substitution and legality checking.
1775 // Don't convert all compare instructions, because for some the zero register
1776 // encoding becomes the sp register.
1777 bool MIDefinesZeroReg = false;
1778 if (MI.definesRegister(AArch64::WZR, /*TRI=*/nullptr) ||
1779 MI.definesRegister(AArch64::XZR, /*TRI=*/nullptr))
1780 MIDefinesZeroReg = true;
1781
1782 switch (MI.getOpcode()) {
1783 default:
1784 return MI.getOpcode();
1785 case AArch64::ADDSWrr:
1786 return AArch64::ADDWrr;
1787 case AArch64::ADDSWri:
1788 return MIDefinesZeroReg ? AArch64::ADDSWri : AArch64::ADDWri;
1789 case AArch64::ADDSWrs:
1790 return MIDefinesZeroReg ? AArch64::ADDSWrs : AArch64::ADDWrs;
1791 case AArch64::ADDSWrx:
1792 return AArch64::ADDWrx;
1793 case AArch64::ADDSXrr:
1794 return AArch64::ADDXrr;
1795 case AArch64::ADDSXri:
1796 return MIDefinesZeroReg ? AArch64::ADDSXri : AArch64::ADDXri;
1797 case AArch64::ADDSXrs:
1798 return MIDefinesZeroReg ? AArch64::ADDSXrs : AArch64::ADDXrs;
1799 case AArch64::ADDSXrx:
1800 return AArch64::ADDXrx;
1801 case AArch64::SUBSWrr:
1802 return AArch64::SUBWrr;
1803 case AArch64::SUBSWri:
1804 return MIDefinesZeroReg ? AArch64::SUBSWri : AArch64::SUBWri;
1805 case AArch64::SUBSWrs:
1806 return MIDefinesZeroReg ? AArch64::SUBSWrs : AArch64::SUBWrs;
1807 case AArch64::SUBSWrx:
1808 return AArch64::SUBWrx;
1809 case AArch64::SUBSXrr:
1810 return AArch64::SUBXrr;
1811 case AArch64::SUBSXri:
1812 return MIDefinesZeroReg ? AArch64::SUBSXri : AArch64::SUBXri;
1813 case AArch64::SUBSXrs:
1814 return MIDefinesZeroReg ? AArch64::SUBSXrs : AArch64::SUBXrs;
1815 case AArch64::SUBSXrx:
1816 return AArch64::SUBXrx;
1817 }
1818}
1819
1820enum AccessKind { AK_Write = 0x01, AK_Read = 0x10, AK_All = 0x11 };
1821
1822/// True when condition flags are accessed (either by writing or reading)
1823/// on the instruction trace starting at From and ending at To.
1824///
1825/// Note: If From and To are from different blocks it's assumed CC are accessed
1826/// on the path.
1829 const TargetRegisterInfo *TRI, const AccessKind AccessToCheck = AK_All) {
1830 // Early exit if To is at the beginning of the BB.
1831 if (To == To->getParent()->begin())
1832 return true;
1833
1834 // Check whether the instructions are in the same basic block
1835 // If not, assume the condition flags might get modified somewhere.
1836 if (To->getParent() != From->getParent())
1837 return true;
1838
1839 // From must be above To.
1840 assert(std::any_of(
1841 ++To.getReverse(), To->getParent()->rend(),
1842 [From](MachineInstr &MI) { return MI.getIterator() == From; }));
1843
1844 // We iterate backward starting at \p To until we hit \p From.
1845 for (const MachineInstr &Instr :
1847 if (((AccessToCheck & AK_Write) &&
1848 Instr.modifiesRegister(AArch64::NZCV, TRI)) ||
1849 ((AccessToCheck & AK_Read) && Instr.readsRegister(AArch64::NZCV, TRI)))
1850 return true;
1851 }
1852 return false;
1853}
1854
1855std::optional<unsigned>
1856AArch64InstrInfo::canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
1858 const MachineRegisterInfo *MRI) const {
1859 unsigned MaskOpcode = Mask->getOpcode();
1860 unsigned PredOpcode = Pred->getOpcode();
1861 bool PredIsPTestLike = isPTestLikeOpcode(PredOpcode);
1862 bool PredIsWhileLike = isWhileOpcode(PredOpcode);
1863
1864 if (PredIsWhileLike) {
1865 // For PTEST(PG, PG), PTEST is redundant when PG is the result of a WHILEcc
1866 // instruction and the condition is "any" since WHILcc does an implicit
1867 // PTEST(ALL, PG) check and PG is always a subset of ALL.
1868 if ((Mask == Pred) && PTest->getOpcode() == AArch64::PTEST_PP_ANY)
1869 return PredOpcode;
1870
1871 // For PTEST(PTRUE_ALL, WHILE), if the element size matches, the PTEST is
1872 // redundant since WHILE performs an implicit PTEST with an all active
1873 // mask.
1874 if (isPTrueOpcode(MaskOpcode) && Mask->getOperand(1).getImm() == 31 &&
1875 getElementSizeForOpcode(MaskOpcode) ==
1876 getElementSizeForOpcode(PredOpcode))
1877 return PredOpcode;
1878
1879 // For PTEST_FIRST(PTRUE_ALL, WHILE), the PTEST_FIRST is redundant since
1880 // WHILEcc performs an implicit PTEST with an all active mask, setting
1881 // the N flag as the PTEST_FIRST would.
1882 if (PTest->getOpcode() == AArch64::PTEST_PP_FIRST &&
1883 isPTrueOpcode(MaskOpcode) && Mask->getOperand(1).getImm() == 31)
1884 return PredOpcode;
1885
1886 return {};
1887 }
1888
1889 if (PredIsPTestLike) {
1890 // For PTEST(PG, PG), PTEST is redundant when PG is the result of an
1891 // instruction that sets the flags as PTEST would and the condition is
1892 // "any" since PG is always a subset of the governing predicate of the
1893 // ptest-like instruction.
1894 if ((Mask == Pred) && PTest->getOpcode() == AArch64::PTEST_PP_ANY)
1895 return PredOpcode;
1896
1897 auto PTestLikeMask = MRI->getUniqueVRegDef(Pred->getOperand(1).getReg());
1898
1899 // If the PTEST like instruction's general predicate is not `Mask`, attempt
1900 // to look through a copy and try again. This is because some instructions
1901 // take a predicate whose register class is a subset of its result class.
1902 if (Mask != PTestLikeMask && PTestLikeMask->isFullCopy() &&
1903 PTestLikeMask->getOperand(1).getReg().isVirtual())
1904 PTestLikeMask =
1905 MRI->getUniqueVRegDef(PTestLikeMask->getOperand(1).getReg());
1906
1907 // For PTEST(PTRUE_ALL, PTEST_LIKE), the PTEST is redundant if the
1908 // the element size matches and either the PTEST_LIKE instruction uses
1909 // the same all active mask or the condition is "any".
1910 if (isPTrueOpcode(MaskOpcode) && Mask->getOperand(1).getImm() == 31 &&
1911 getElementSizeForOpcode(MaskOpcode) ==
1912 getElementSizeForOpcode(PredOpcode)) {
1913 if (Mask == PTestLikeMask || PTest->getOpcode() == AArch64::PTEST_PP_ANY)
1914 return PredOpcode;
1915 }
1916
1917 // For PTEST(PG, PTEST_LIKE(PG, ...)), the PTEST is redundant since the
1918 // flags are set based on the same mask 'PG', but PTEST_LIKE must operate
1919 // on 8-bit predicates like the PTEST. Otherwise, for instructions like
1920 // compare that also support 16/32/64-bit predicates, the implicit PTEST
1921 // performed by the compare could consider fewer lanes for these element
1922 // sizes.
1923 //
1924 // For example, consider
1925 //
1926 // ptrue p0.b ; P0=1111-1111-1111-1111
1927 // index z0.s, #0, #1 ; Z0=<0,1,2,3>
1928 // index z1.s, #1, #1 ; Z1=<1,2,3,4>
1929 // cmphi p1.s, p0/z, z1.s, z0.s ; P1=0001-0001-0001-0001
1930 // ; ^ last active
1931 // ptest p0, p1.b ; P1=0001-0001-0001-0001
1932 // ; ^ last active
1933 //
1934 // where the compare generates a canonical all active 32-bit predicate
1935 // (equivalent to 'ptrue p1.s, all'). The implicit PTEST sets the last
1936 // active flag, whereas the PTEST instruction with the same mask doesn't.
1937 // For PTEST_ANY this doesn't apply as the flags in this case would be
1938 // identical regardless of element size.
1939 uint64_t PredElementSize = getElementSizeForOpcode(PredOpcode);
1940 if (Mask == PTestLikeMask && (PredElementSize == AArch64::ElementSizeB ||
1941 PTest->getOpcode() == AArch64::PTEST_PP_ANY))
1942 return PredOpcode;
1943
1944 return {};
1945 }
1946
1947 // If OP in PTEST(PG, OP(PG, ...)) has a flag-setting variant change the
1948 // opcode so the PTEST becomes redundant.
1949 switch (PredOpcode) {
1950 case AArch64::AND_PPzPP:
1951 case AArch64::BIC_PPzPP:
1952 case AArch64::EOR_PPzPP:
1953 case AArch64::NAND_PPzPP:
1954 case AArch64::NOR_PPzPP:
1955 case AArch64::ORN_PPzPP:
1956 case AArch64::ORR_PPzPP:
1957 case AArch64::BRKA_PPzP:
1958 case AArch64::BRKPA_PPzPP:
1959 case AArch64::BRKB_PPzP:
1960 case AArch64::BRKPB_PPzPP:
1961 case AArch64::RDFFR_PPz: {
1962 // Check to see if our mask is the same. If not the resulting flag bits
1963 // may be different and we can't remove the ptest.
1964 auto *PredMask = MRI->getUniqueVRegDef(Pred->getOperand(1).getReg());
1965 if (Mask != PredMask)
1966 return {};
1967 break;
1968 }
1969 case AArch64::BRKN_PPzP: {
1970 // BRKN uses an all active implicit mask to set flags unlike the other
1971 // flag-setting instructions.
1972 // PTEST(PTRUE_B(31), BRKN(PG, A, B)) -> BRKNS(PG, A, B).
1973 if ((MaskOpcode != AArch64::PTRUE_B) ||
1974 (Mask->getOperand(1).getImm() != 31))
1975 return {};
1976 break;
1977 }
1978 case AArch64::PTRUE_B:
1979 // PTEST(OP=PTRUE_B(A), OP) -> PTRUES_B(A)
1980 break;
1981 default:
1982 // Bail out if we don't recognize the input
1983 return {};
1984 }
1985
1986 return convertToFlagSettingOpc(PredOpcode);
1987}
1988
1989/// optimizePTestInstr - Attempt to remove a ptest of a predicate-generating
1990/// operation which could set the flags in an identical manner
1991bool AArch64InstrInfo::optimizePTestInstr(
1992 MachineInstr *PTest, unsigned MaskReg, unsigned PredReg,
1993 const MachineRegisterInfo *MRI) const {
1994 auto *Mask = MRI->getUniqueVRegDef(MaskReg);
1995 auto *Pred = MRI->getUniqueVRegDef(PredReg);
1996
1997 if (Pred->isCopy() && PTest->getOpcode() == AArch64::PTEST_PP_FIRST) {
1998 // Instructions which return a multi-vector (e.g. WHILECC_x2) require copies
1999 // before the branch to extract each subregister.
2000 auto Op = Pred->getOperand(1);
2001 if (Op.isReg() && Op.getReg().isVirtual() &&
2002 Op.getSubReg() == AArch64::psub0)
2003 Pred = MRI->getUniqueVRegDef(Op.getReg());
2004 }
2005
2006 unsigned PredOpcode = Pred->getOpcode();
2007 auto NewOp = canRemovePTestInstr(PTest, Mask, Pred, MRI);
2008 if (!NewOp)
2009 return false;
2010
2011 const TargetRegisterInfo *TRI = &getRegisterInfo();
2012
2013 // If another instruction between Pred and PTest accesses flags, don't remove
2014 // the ptest or update the earlier instruction to modify them.
2016 return false;
2017
2018 // If we pass all the checks, it's safe to remove the PTEST and use the flags
2019 // as they are prior to PTEST. Sometimes this requires the tested PTEST
2020 // operand to be replaced with an equivalent instruction that also sets the
2021 // flags.
2022 PTest->eraseFromParent();
2023 if (*NewOp != PredOpcode) {
2024 Pred->setDesc(get(*NewOp));
2026 Pred->addRegisterDefined(AArch64::NZCV, TRI);
2027 }
2028
2029 // Ensure that the flags def is live.
2030 if (Pred->registerDefIsDead(AArch64::NZCV, TRI)) {
2031 unsigned i = 0, e = Pred->getNumOperands();
2032 for (; i != e; ++i) {
2033 MachineOperand &MO = Pred->getOperand(i);
2034 if (MO.isReg() && MO.isDef() && MO.getReg() == AArch64::NZCV) {
2035 MO.setIsDead(false);
2036 break;
2037 }
2038 }
2039 }
2040 return true;
2041}
2042
2043/// Try to optimize a compare instruction. A compare instruction is an
2044/// instruction which produces AArch64::NZCV. It can be truly compare
2045/// instruction
2046/// when there are no uses of its destination register.
2047///
2048/// The following steps are tried in order:
2049/// 1. Convert CmpInstr into an unconditional version.
2050/// 2. Remove CmpInstr if above there is an instruction producing a needed
2051/// condition code or an instruction which can be converted into such an
2052/// instruction.
2053/// Only comparison with zero is supported.
2055 MachineInstr &CmpInstr, Register SrcReg, Register SrcReg2, int64_t CmpMask,
2056 int64_t CmpValue, const MachineRegisterInfo *MRI) const {
2057 assert(CmpInstr.getParent());
2058 assert(MRI);
2059
2060 // Replace SUBSWrr with SUBWrr if NZCV is not used.
2061 int DeadNZCVIdx =
2062 CmpInstr.findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr, true);
2063 if (DeadNZCVIdx != -1) {
2064 if (CmpInstr.definesRegister(AArch64::WZR, /*TRI=*/nullptr) ||
2065 CmpInstr.definesRegister(AArch64::XZR, /*TRI=*/nullptr)) {
2066 CmpInstr.eraseFromParent();
2067 return true;
2068 }
2069 unsigned Opc = CmpInstr.getOpcode();
2070 unsigned NewOpc = convertToNonFlagSettingOpc(CmpInstr);
2071 if (NewOpc == Opc)
2072 return false;
2073 const MCInstrDesc &MCID = get(NewOpc);
2074 CmpInstr.setDesc(MCID);
2075 CmpInstr.removeOperand(DeadNZCVIdx);
2076 updateOperandRegClass(CmpInstr);
2077 return true;
2078 }
2079
2080 if (CmpInstr.getOpcode() == AArch64::PTEST_PP ||
2081 CmpInstr.getOpcode() == AArch64::PTEST_PP_ANY ||
2082 CmpInstr.getOpcode() == AArch64::PTEST_PP_FIRST)
2083 return optimizePTestInstr(&CmpInstr, SrcReg, SrcReg2, MRI);
2084
2085 if (SrcReg2 != 0)
2086 return false;
2087
2088 // CmpInstr is a Compare instruction if destination register is not used.
2089 if (!MRI->use_nodbg_empty(CmpInstr.getOperand(0).getReg()))
2090 return false;
2091
2092 if (CmpValue == 0 && substituteCmpToZero(CmpInstr, SrcReg, *MRI))
2093 return true;
2094 return (CmpValue == 0 || CmpValue == 1) &&
2095 removeCmpToZeroOrOne(CmpInstr, SrcReg, CmpValue, *MRI);
2096}
2097
2098/// Get opcode of S version of Instr.
2099/// If Instr is S version its opcode is returned.
2100/// AArch64::INSTRUCTION_LIST_END is returned if Instr does not have S version
2101/// or we are not interested in it.
2102static unsigned sForm(MachineInstr &Instr) {
2103 switch (Instr.getOpcode()) {
2104 default:
2105 return AArch64::INSTRUCTION_LIST_END;
2106
2107 case AArch64::ADDSWrr:
2108 case AArch64::ADDSWri:
2109 case AArch64::ADDSXrr:
2110 case AArch64::ADDSXri:
2111 case AArch64::ADDSWrx:
2112 case AArch64::ADDSXrx:
2113 case AArch64::ADDSWrs:
2114 case AArch64::ADDSXrs:
2115 case AArch64::SUBSWrr:
2116 case AArch64::SUBSWri:
2117 case AArch64::SUBSWrx:
2118 case AArch64::SUBSWrs:
2119 case AArch64::SUBSXrr:
2120 case AArch64::SUBSXri:
2121 case AArch64::SUBSXrx:
2122 case AArch64::SUBSXrs:
2123 case AArch64::ANDSWri:
2124 case AArch64::ANDSWrr:
2125 case AArch64::ANDSWrs:
2126 case AArch64::ANDSXri:
2127 case AArch64::ANDSXrr:
2128 case AArch64::ANDSXrs:
2129 case AArch64::BICSWrr:
2130 case AArch64::BICSXrr:
2131 case AArch64::BICSWrs:
2132 case AArch64::BICSXrs:
2133 case AArch64::ADCSWr:
2134 case AArch64::ADCSXr:
2135 case AArch64::SBCSWr:
2136 case AArch64::SBCSXr:
2137 return Instr.getOpcode();
2138
2139 case AArch64::ADDWrr:
2140 return AArch64::ADDSWrr;
2141 case AArch64::ADDWri:
2142 return AArch64::ADDSWri;
2143 case AArch64::ADDXrr:
2144 return AArch64::ADDSXrr;
2145 case AArch64::ADDXri:
2146 return AArch64::ADDSXri;
2147 case AArch64::ADDWrx:
2148 return AArch64::ADDSWrx;
2149 case AArch64::ADDXrx:
2150 return AArch64::ADDSXrx;
2151 case AArch64::ADDWrs:
2152 return AArch64::ADDSWrs;
2153 case AArch64::ADDXrs:
2154 return AArch64::ADDSXrs;
2155 case AArch64::ADCWr:
2156 return AArch64::ADCSWr;
2157 case AArch64::ADCXr:
2158 return AArch64::ADCSXr;
2159 case AArch64::SUBWrr:
2160 return AArch64::SUBSWrr;
2161 case AArch64::SUBWri:
2162 return AArch64::SUBSWri;
2163 case AArch64::SUBXrr:
2164 return AArch64::SUBSXrr;
2165 case AArch64::SUBXri:
2166 return AArch64::SUBSXri;
2167 case AArch64::SUBWrx:
2168 return AArch64::SUBSWrx;
2169 case AArch64::SUBXrx:
2170 return AArch64::SUBSXrx;
2171 case AArch64::SUBWrs:
2172 return AArch64::SUBSWrs;
2173 case AArch64::SUBXrs:
2174 return AArch64::SUBSXrs;
2175 case AArch64::SBCWr:
2176 return AArch64::SBCSWr;
2177 case AArch64::SBCXr:
2178 return AArch64::SBCSXr;
2179 case AArch64::ANDWri:
2180 return AArch64::ANDSWri;
2181 case AArch64::ANDXri:
2182 return AArch64::ANDSXri;
2183 case AArch64::ANDWrr:
2184 return AArch64::ANDSWrr;
2185 case AArch64::ANDWrs:
2186 return AArch64::ANDSWrs;
2187 case AArch64::ANDXrr:
2188 return AArch64::ANDSXrr;
2189 case AArch64::ANDXrs:
2190 return AArch64::ANDSXrs;
2191 case AArch64::BICWrr:
2192 return AArch64::BICSWrr;
2193 case AArch64::BICXrr:
2194 return AArch64::BICSXrr;
2195 case AArch64::BICWrs:
2196 return AArch64::BICSWrs;
2197 case AArch64::BICXrs:
2198 return AArch64::BICSXrs;
2199 }
2200}
2201
2202/// Check if AArch64::NZCV should be alive in successors of MBB.
2204 for (auto *BB : MBB->successors())
2205 if (BB->isLiveIn(AArch64::NZCV))
2206 return true;
2207 return false;
2208}
2209
2210/// \returns The condition code operand index for \p Instr if it is a branch
2211/// or select and -1 otherwise.
2212int AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(
2213 const MachineInstr &Instr) {
2214 switch (Instr.getOpcode()) {
2215 default:
2216 return -1;
2217
2218 case AArch64::Bcc: {
2219 int Idx = Instr.findRegisterUseOperandIdx(AArch64::NZCV, /*TRI=*/nullptr);
2220 assert(Idx >= 2);
2221 return Idx - 2;
2222 }
2223
2224 case AArch64::CSINVWr:
2225 case AArch64::CSINVXr:
2226 case AArch64::CSINCWr:
2227 case AArch64::CSINCXr:
2228 case AArch64::CSELWr:
2229 case AArch64::CSELXr:
2230 case AArch64::CSNEGWr:
2231 case AArch64::CSNEGXr:
2232 case AArch64::FCSELSrrr:
2233 case AArch64::FCSELDrrr: {
2234 int Idx = Instr.findRegisterUseOperandIdx(AArch64::NZCV, /*TRI=*/nullptr);
2235 assert(Idx >= 1);
2236 return Idx - 1;
2237 }
2238 }
2239}
2240
2241/// Find a condition code used by the instruction.
2242/// Returns AArch64CC::Invalid if either the instruction does not use condition
2243/// codes or we don't optimize CmpInstr in the presence of such instructions.
2245 int CCIdx =
2246 AArch64InstrInfo::findCondCodeUseOperandIdxForBranchOrSelect(Instr);
2247 return CCIdx >= 0 ? static_cast<AArch64CC::CondCode>(
2248 Instr.getOperand(CCIdx).getImm())
2250}
2251
2254 UsedNZCV UsedFlags;
2255 switch (CC) {
2256 default:
2257 break;
2258
2259 case AArch64CC::EQ: // Z set
2260 case AArch64CC::NE: // Z clear
2261 UsedFlags.Z = true;
2262 break;
2263
2264 case AArch64CC::HI: // Z clear and C set
2265 case AArch64CC::LS: // Z set or C clear
2266 UsedFlags.Z = true;
2267 [[fallthrough]];
2268 case AArch64CC::HS: // C set
2269 case AArch64CC::LO: // C clear
2270 UsedFlags.C = true;
2271 break;
2272
2273 case AArch64CC::MI: // N set
2274 case AArch64CC::PL: // N clear
2275 UsedFlags.N = true;
2276 break;
2277
2278 case AArch64CC::VS: // V set
2279 case AArch64CC::VC: // V clear
2280 UsedFlags.V = true;
2281 break;
2282
2283 case AArch64CC::GT: // Z clear, N and V the same
2284 case AArch64CC::LE: // Z set, N and V differ
2285 UsedFlags.Z = true;
2286 [[fallthrough]];
2287 case AArch64CC::GE: // N and V the same
2288 case AArch64CC::LT: // N and V differ
2289 UsedFlags.N = true;
2290 UsedFlags.V = true;
2291 break;
2292 }
2293 return UsedFlags;
2294}
2295
2296/// \returns Conditions flags used after \p CmpInstr in its MachineBB if NZCV
2297/// flags are not alive in successors of the same \p CmpInstr and \p MI parent.
2298/// \returns std::nullopt otherwise.
2299///
2300/// Collect instructions using that flags in \p CCUseInstrs if provided.
2301std::optional<UsedNZCV>
2303 const TargetRegisterInfo &TRI,
2304 SmallVectorImpl<MachineInstr *> *CCUseInstrs) {
2305 MachineBasicBlock *CmpParent = CmpInstr.getParent();
2306 if (MI.getParent() != CmpParent)
2307 return std::nullopt;
2308
2309 if (areCFlagsAliveInSuccessors(CmpParent))
2310 return std::nullopt;
2311
2312 UsedNZCV NZCVUsedAfterCmp;
2314 std::next(CmpInstr.getIterator()), CmpParent->instr_end())) {
2315 if (Instr.readsRegister(AArch64::NZCV, &TRI)) {
2317 if (CC == AArch64CC::Invalid) // Unsupported conditional instruction
2318 return std::nullopt;
2319 NZCVUsedAfterCmp |= getUsedNZCV(CC);
2320 if (CCUseInstrs)
2321 CCUseInstrs->push_back(&Instr);
2322 }
2323 if (Instr.modifiesRegister(AArch64::NZCV, &TRI))
2324 break;
2325 }
2326 return NZCVUsedAfterCmp;
2327}
2328
2329static bool isADDSRegImm(unsigned Opcode) {
2330 return Opcode == AArch64::ADDSWri || Opcode == AArch64::ADDSXri;
2331}
2332
2333static bool isSUBSRegImm(unsigned Opcode) {
2334 return Opcode == AArch64::SUBSWri || Opcode == AArch64::SUBSXri;
2335}
2336
2338 unsigned Opc = sForm(MI);
2339 switch (Opc) {
2340 case AArch64::ANDSWri:
2341 case AArch64::ANDSWrr:
2342 case AArch64::ANDSWrs:
2343 case AArch64::ANDSXri:
2344 case AArch64::ANDSXrr:
2345 case AArch64::ANDSXrs:
2346 case AArch64::BICSWrr:
2347 case AArch64::BICSXrr:
2348 case AArch64::BICSWrs:
2349 case AArch64::BICSXrs:
2350 return true;
2351 default:
2352 return false;
2353 }
2354}
2355
2356/// Check if CmpInstr can be substituted by MI.
2357///
2358/// CmpInstr can be substituted:
2359/// - CmpInstr is either 'ADDS %vreg, 0' or 'SUBS %vreg, 0'
2360/// - and, MI and CmpInstr are from the same MachineBB
2361/// - and, condition flags are not alive in successors of the CmpInstr parent
2362/// - and, if MI opcode is the S form there must be no defs of flags between
2363/// MI and CmpInstr
2364/// or if MI opcode is not the S form there must be neither defs of flags
2365/// nor uses of flags between MI and CmpInstr.
2366/// - and, C is not used after CmpInstr; CmpInstr's C is from adds/subs #0 on
2367/// SrcReg and can differ from MI (e.g. carry out of ADCS/SBCS).
2368/// - and, V is not used after CmpInstr unless MI is AND/BIC (V cleared) or MI
2369/// has NoSWrap (overflow is poison and the fold is still safe).
2371 const TargetRegisterInfo &TRI) {
2372 // MI is an opcode sForm maps (add/sub/adc/sbc/and/bic and their S forms).
2373 assert(sForm(MI) != AArch64::INSTRUCTION_LIST_END);
2374
2375 const unsigned CmpOpcode = CmpInstr.getOpcode();
2376 if (!isADDSRegImm(CmpOpcode) && !isSUBSRegImm(CmpOpcode))
2377 return false;
2378
2379 assert((CmpInstr.getOperand(2).isImm() &&
2380 CmpInstr.getOperand(2).getImm() == 0) &&
2381 "Caller guarantees that CmpInstr compares with constant 0");
2382
2383 std::optional<UsedNZCV> NZVCUsed = examineCFlagsUse(MI, CmpInstr, TRI);
2384 if (!NZVCUsed || NZVCUsed->C)
2385 return false;
2386
2387 // CmpInstr is ADDS/SUBS with immediate 0 on SrcReg (compare SrcReg to zero).
2388 // After the fold, users see NZCV from MI (or its S form), not from CmpInstr.
2389 // N/Z match CmpInstr for the value in SrcReg; C/V need not match in general
2390 // (e.g. ADCS vs adds #0), so we require C unused after CmpInstr and gate V
2391 // as below. NoSWrap makes signed overflow poison; AND/BIC clear V.
2392 if (NZVCUsed->V && !MI.getFlag(MachineInstr::NoSWrap) && !isANDOpcode(MI))
2393 return false;
2394
2395 AccessKind AccessToCheck = AK_Write;
2396 if (sForm(MI) != MI.getOpcode())
2397 AccessToCheck = AK_All;
2398 return !areCFlagsAccessedBetweenInstrs(&MI, &CmpInstr, &TRI, AccessToCheck);
2399}
2400
2401/// Substitute an instruction comparing to zero with another instruction
2402/// which produces needed condition flags.
2403///
2404/// Return true on success.
2405bool AArch64InstrInfo::substituteCmpToZero(
2406 MachineInstr &CmpInstr, unsigned SrcReg,
2407 const MachineRegisterInfo &MRI) const {
2408 // Get the unique definition of SrcReg.
2409 MachineInstr *MI = MRI.getUniqueVRegDef(SrcReg);
2410 if (!MI)
2411 return false;
2412
2413 const TargetRegisterInfo &TRI = getRegisterInfo();
2414
2415 unsigned NewOpc = sForm(*MI);
2416 if (NewOpc == AArch64::INSTRUCTION_LIST_END)
2417 return false;
2418
2419 if (!canInstrSubstituteCmpInstr(*MI, CmpInstr, TRI))
2420 return false;
2421
2422 // Update the instruction to set NZCV.
2423 MI->setDesc(get(NewOpc));
2424 CmpInstr.eraseFromParent();
2426 MI->addRegisterDefined(AArch64::NZCV, &TRI);
2427 return true;
2428}
2429
2430/// \returns True if \p CmpInstr can be removed.
2431///
2432/// \p IsInvertCC is true if, after removing \p CmpInstr, condition
2433/// codes used in \p CCUseInstrs must be inverted.
2435 int CmpValue, const TargetRegisterInfo &TRI,
2437 bool &IsInvertCC) {
2438 assert((CmpValue == 0 || CmpValue == 1) &&
2439 "Only comparisons to 0 or 1 considered for removal!");
2440
2441 // MI is 'CSINCWr %vreg, wzr, wzr, <cc>' or 'CSINCXr %vreg, xzr, xzr, <cc>'
2442 unsigned MIOpc = MI.getOpcode();
2443 if (MIOpc == AArch64::CSINCWr) {
2444 if (MI.getOperand(1).getReg() != AArch64::WZR ||
2445 MI.getOperand(2).getReg() != AArch64::WZR)
2446 return false;
2447 } else if (MIOpc == AArch64::CSINCXr) {
2448 if (MI.getOperand(1).getReg() != AArch64::XZR ||
2449 MI.getOperand(2).getReg() != AArch64::XZR)
2450 return false;
2451 } else {
2452 return false;
2453 }
2455 if (MICC == AArch64CC::Invalid)
2456 return false;
2457
2458 // NZCV needs to be defined
2459 if (MI.findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr, true) != -1)
2460 return false;
2461
2462 // CmpInstr is 'ADDS %vreg, 0' or 'SUBS %vreg, 0' or 'SUBS %vreg, 1'
2463 const unsigned CmpOpcode = CmpInstr.getOpcode();
2464 bool IsSubsRegImm = isSUBSRegImm(CmpOpcode);
2465 if (CmpValue && !IsSubsRegImm)
2466 return false;
2467 if (!CmpValue && !IsSubsRegImm && !isADDSRegImm(CmpOpcode))
2468 return false;
2469
2470 // MI conditions allowed: eq, ne, mi, pl
2471 UsedNZCV MIUsedNZCV = getUsedNZCV(MICC);
2472 if (MIUsedNZCV.C || MIUsedNZCV.V)
2473 return false;
2474
2475 std::optional<UsedNZCV> NZCVUsedAfterCmp =
2476 examineCFlagsUse(MI, CmpInstr, TRI, &CCUseInstrs);
2477 // Condition flags are not used in CmpInstr basic block successors and only
2478 // Z or N flags allowed to be used after CmpInstr within its basic block
2479 if (!NZCVUsedAfterCmp || NZCVUsedAfterCmp->C || NZCVUsedAfterCmp->V)
2480 return false;
2481 // Z or N flag used after CmpInstr must correspond to the flag used in MI
2482 if ((MIUsedNZCV.Z && NZCVUsedAfterCmp->N) ||
2483 (MIUsedNZCV.N && NZCVUsedAfterCmp->Z))
2484 return false;
2485 // If CmpInstr is comparison to zero MI conditions are limited to eq, ne
2486 if (MIUsedNZCV.N && !CmpValue)
2487 return false;
2488
2489 // There must be no defs of flags between MI and CmpInstr
2490 if (areCFlagsAccessedBetweenInstrs(&MI, &CmpInstr, &TRI, AK_Write))
2491 return false;
2492
2493 // Condition code is inverted in the following cases:
2494 // 1. MI condition is ne; CmpInstr is 'ADDS %vreg, 0' or 'SUBS %vreg, 0'
2495 // 2. MI condition is eq, pl; CmpInstr is 'SUBS %vreg, 1'
2496 IsInvertCC = (CmpValue && (MICC == AArch64CC::EQ || MICC == AArch64CC::PL)) ||
2497 (!CmpValue && MICC == AArch64CC::NE);
2498 return true;
2499}
2500
2501/// Remove comparison in csinc-cmp sequence
2502///
2503/// Examples:
2504/// 1. \code
2505/// csinc w9, wzr, wzr, ne
2506/// cmp w9, #0
2507/// b.eq
2508/// \endcode
2509/// to
2510/// \code
2511/// csinc w9, wzr, wzr, ne
2512/// b.ne
2513/// \endcode
2514///
2515/// 2. \code
2516/// csinc x2, xzr, xzr, mi
2517/// cmp x2, #1
2518/// b.pl
2519/// \endcode
2520/// to
2521/// \code
2522/// csinc x2, xzr, xzr, mi
2523/// b.pl
2524/// \endcode
2525///
2526/// \param CmpInstr comparison instruction
2527/// \return True when comparison removed
2528bool AArch64InstrInfo::removeCmpToZeroOrOne(
2529 MachineInstr &CmpInstr, unsigned SrcReg, int CmpValue,
2530 const MachineRegisterInfo &MRI) const {
2531 MachineInstr *MI = MRI.getUniqueVRegDef(SrcReg);
2532 if (!MI)
2533 return false;
2534 const TargetRegisterInfo &TRI = getRegisterInfo();
2535 SmallVector<MachineInstr *, 4> CCUseInstrs;
2536 bool IsInvertCC = false;
2537 if (!canCmpInstrBeRemoved(*MI, CmpInstr, CmpValue, TRI, CCUseInstrs,
2538 IsInvertCC))
2539 return false;
2540 // Make transformation
2541 CmpInstr.eraseFromParent();
2542 if (IsInvertCC) {
2543 // Invert condition codes in CmpInstr CC users
2544 for (MachineInstr *CCUseInstr : CCUseInstrs) {
2545 int Idx = findCondCodeUseOperandIdxForBranchOrSelect(*CCUseInstr);
2546 assert(Idx >= 0 && "Unexpected instruction using CC.");
2547 MachineOperand &CCOperand = CCUseInstr->getOperand(Idx);
2549 static_cast<AArch64CC::CondCode>(CCOperand.getImm()));
2550 CCOperand.setImm(CCUse);
2551 }
2552 }
2553 return true;
2554}
2555
2556bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
2557 if (MI.getOpcode() != TargetOpcode::LOAD_STACK_GUARD &&
2558 MI.getOpcode() != AArch64::CATCHRET &&
2559 MI.getOpcode() != AArch64::STACK_GUARD_UNMIX)
2560 return false;
2561
2562 MachineBasicBlock &MBB = *MI.getParent();
2563 auto &Subtarget = MBB.getParent()->getSubtarget<AArch64Subtarget>();
2564 auto TRI = Subtarget.getRegisterInfo();
2565 DebugLoc DL = MI.getDebugLoc();
2566
2567 if (MI.getOpcode() == AArch64::STACK_GUARD_UNMIX) {
2568 // Expand STACK_GUARD_UNMIX to: sub Rd, fp, Rs
2569 // This computes FP - stored_mixed_value to unmix the cookie
2570 Register DstReg = MI.getOperand(0).getReg();
2571 Register SrcReg = MI.getOperand(1).getReg();
2572
2573 BuildMI(MBB, MI, DL, get(AArch64::SUBXrr), DstReg)
2574 .addReg(AArch64::FP)
2575 .addReg(SrcReg);
2576
2577 MBB.erase(MI);
2578 return true;
2579 }
2580
2581 if (MI.getOpcode() == AArch64::CATCHRET) {
2582 // Skip to the first instruction before the epilog.
2583 const TargetInstrInfo *TII =
2585 MachineBasicBlock *TargetMBB = MI.getOperand(0).getMBB();
2587 MachineBasicBlock::iterator FirstEpilogSEH = std::prev(MBBI);
2588 while (FirstEpilogSEH->getFlag(MachineInstr::FrameDestroy) &&
2589 FirstEpilogSEH != MBB.begin())
2590 FirstEpilogSEH = std::prev(FirstEpilogSEH);
2591 if (FirstEpilogSEH != MBB.begin())
2592 FirstEpilogSEH = std::next(FirstEpilogSEH);
2593 BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADRP))
2594 .addReg(AArch64::X0, RegState::Define)
2595 .addMBB(TargetMBB, AArch64II::MO_PAGE);
2596 BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADDXri))
2597 .addReg(AArch64::X0, RegState::Define)
2598 .addReg(AArch64::X0)
2600 .addImm(0);
2601 TargetMBB->setMachineBlockAddressTaken();
2602 return true;
2603 }
2604
2605 Register Reg = MI.getOperand(0).getReg();
2607 if (M.getStackProtectorGuard() == "sysreg") {
2608 const AArch64SysReg::SysReg *SrcReg =
2609 AArch64SysReg::lookupSysRegByName(M.getStackProtectorGuardReg());
2610 if (!SrcReg)
2611 report_fatal_error("Unknown SysReg for Stack Protector Guard Register");
2612
2613 // mrs xN, sysreg
2614 BuildMI(MBB, MI, DL, get(AArch64::MRS))
2616 .addImm(SrcReg->Encoding);
2617 int Offset = M.getStackProtectorGuardOffset();
2618 if (Offset >= 0 && Offset <= 32760 && Offset % 8 == 0) {
2619 // ldr xN, [xN, #offset]
2620 BuildMI(MBB, MI, DL, get(AArch64::LDRXui))
2621 .addDef(Reg)
2623 .addImm(Offset / 8);
2624 } else if (Offset >= -256 && Offset <= 255) {
2625 // ldur xN, [xN, #offset]
2626 BuildMI(MBB, MI, DL, get(AArch64::LDURXi))
2627 .addDef(Reg)
2629 .addImm(Offset);
2630 } else if (Offset >= -4095 && Offset <= 4095) {
2631 if (Offset > 0) {
2632 // add xN, xN, #offset
2633 BuildMI(MBB, MI, DL, get(AArch64::ADDXri))
2634 .addDef(Reg)
2636 .addImm(Offset)
2637 .addImm(0);
2638 } else {
2639 // sub xN, xN, #offset
2640 BuildMI(MBB, MI, DL, get(AArch64::SUBXri))
2641 .addDef(Reg)
2643 .addImm(-Offset)
2644 .addImm(0);
2645 }
2646 // ldr xN, [xN]
2647 BuildMI(MBB, MI, DL, get(AArch64::LDRXui))
2648 .addDef(Reg)
2650 .addImm(0);
2651 } else {
2652 // Cases that are larger than +/- 4095 and not a multiple of 8, or larger
2653 // than 23760.
2654 // It might be nice to use AArch64::MOVi32imm here, which would get
2655 // expanded in PreSched2 after PostRA, but our lone scratch Reg already
2656 // contains the MRS result. findScratchNonCalleeSaveRegister() in
2657 // AArch64FrameLowering might help us find such a scratch register
2658 // though. If we failed to find a scratch register, we could emit a
2659 // stream of add instructions to build up the immediate. Or, we could try
2660 // to insert a AArch64::MOVi32imm before register allocation so that we
2661 // didn't need to scavenge for a scratch register.
2662 report_fatal_error("Unable to encode Stack Protector Guard Offset");
2663 }
2664 MBB.erase(MI);
2665 return true;
2666 }
2667
2668 const GlobalValue *GV =
2669 cast<GlobalValue>((*MI.memoperands_begin())->getValue());
2670 const TargetMachine &TM = MBB.getParent()->getTarget();
2671 unsigned OpFlags = Subtarget.ClassifyGlobalReference(GV, TM);
2672 const unsigned char MO_NC = AArch64II::MO_NC;
2673
2674 unsigned GuardWidth = M.getStackProtectorGuardValueWidth().value_or(
2675 Subtarget.isTargetILP32() ? 4 : 8);
2676 if (GuardWidth != 4 && GuardWidth != 8)
2677 report_fatal_error("Unsupported stack protector value width");
2678 if ((OpFlags & AArch64II::MO_GOT) != 0) {
2679 BuildMI(MBB, MI, DL, get(AArch64::LOADgot), Reg)
2680 .addGlobalAddress(GV, 0, OpFlags);
2681 if (GuardWidth == 4) {
2682 unsigned Reg32 = TRI->getSubReg(Reg, AArch64::sub_32);
2683 BuildMI(MBB, MI, DL, get(AArch64::LDRWui))
2684 .addDef(Reg32)
2686 .addImm(0)
2687 .addMemOperand(*MI.memoperands_begin())
2689 } else {
2690 BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg)
2692 .addImm(0)
2693 .addMemOperand(*MI.memoperands_begin());
2694 }
2695 } else if (TM.getCodeModel() == CodeModel::Large) {
2696 BuildMI(MBB, MI, DL, get(AArch64::MOVZXi), Reg)
2697 .addGlobalAddress(GV, 0, AArch64II::MO_G0 | MO_NC)
2698 .addImm(0);
2699 BuildMI(MBB, MI, DL, get(AArch64::MOVKXi), Reg)
2701 .addGlobalAddress(GV, 0, AArch64II::MO_G1 | MO_NC)
2702 .addImm(16);
2703 BuildMI(MBB, MI, DL, get(AArch64::MOVKXi), Reg)
2705 .addGlobalAddress(GV, 0, AArch64II::MO_G2 | MO_NC)
2706 .addImm(32);
2707 BuildMI(MBB, MI, DL, get(AArch64::MOVKXi), Reg)
2710 .addImm(48);
2711 if (GuardWidth == 4) {
2712 unsigned Reg32 = TRI->getSubReg(Reg, AArch64::sub_32);
2713 BuildMI(MBB, MI, DL, get(AArch64::LDRWui))
2714 .addDef(Reg32)
2716 .addImm(0)
2717 .addMemOperand(*MI.memoperands_begin())
2719 } else {
2720 BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg)
2722 .addImm(0)
2723 .addMemOperand(*MI.memoperands_begin());
2724 }
2725 } else {
2726 BuildMI(MBB, MI, DL, get(AArch64::ADRP), Reg)
2727 .addGlobalAddress(GV, 0, OpFlags | AArch64II::MO_PAGE);
2728 unsigned char LoFlags = OpFlags | AArch64II::MO_PAGEOFF | MO_NC;
2729 if (GuardWidth == 4) {
2730 unsigned Reg32 = TRI->getSubReg(Reg, AArch64::sub_32);
2731 BuildMI(MBB, MI, DL, get(AArch64::LDRWui))
2732 .addDef(Reg32)
2734 .addGlobalAddress(GV, 0, LoFlags)
2735 .addMemOperand(*MI.memoperands_begin())
2737 } else {
2738 BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg)
2740 .addGlobalAddress(GV, 0, LoFlags)
2741 .addMemOperand(*MI.memoperands_begin());
2742 }
2743 }
2744 // To match MSVC. Unlike x86_64 which uses xor instruction to mix the cookie,
2745 // we use sub instruction to mix the cookie on aarch64.
2746 // The mixing happens here in expandPostRAPseudo (after RA) to ensure we use
2747 // the final frame pointer value.
2748 if (Subtarget.getTargetTriple().isOSMSVCRT())
2749 BuildMI(MBB, MI, DL, get(AArch64::SUBXrr), Reg)
2750 .addReg(AArch64::FP)
2752
2753 MBB.erase(MI);
2754
2755 return true;
2756}
2757
2758// Return true if this instruction simply sets its single destination register
2759// to zero. This is equivalent to a register rename of the zero-register.
2761 switch (MI.getOpcode()) {
2762 default:
2763 break;
2764 case AArch64::MOVZWi:
2765 case AArch64::MOVZXi: // movz Rd, #0 (LSL #0)
2766 if (MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == 0) {
2767 assert(MI.getDesc().getNumOperands() == 3 &&
2768 MI.getOperand(2).getImm() == 0 && "invalid MOVZi operands");
2769 return true;
2770 }
2771 break;
2772 case AArch64::ANDWri: // and Rd, Rzr, #imm
2773 return MI.getOperand(1).getReg() == AArch64::WZR;
2774 case AArch64::ANDXri:
2775 return MI.getOperand(1).getReg() == AArch64::XZR;
2776 case TargetOpcode::COPY:
2777 return MI.getOperand(1).getReg() == AArch64::WZR;
2778 }
2779 return false;
2780}
2781
2782// Return true if this instruction simply renames a general register without
2783// modifying bits.
2785 switch (MI.getOpcode()) {
2786 default:
2787 break;
2788 case TargetOpcode::COPY: {
2789 // GPR32 copies will by lowered to ORRXrs
2790 Register DstReg = MI.getOperand(0).getReg();
2791 return (AArch64::GPR32RegClass.contains(DstReg) ||
2792 AArch64::GPR64RegClass.contains(DstReg));
2793 }
2794 case AArch64::ORRXrs: // orr Xd, Xzr, Xm (LSL #0)
2795 if (MI.getOperand(1).getReg() == AArch64::XZR) {
2796 assert(MI.getDesc().getNumOperands() == 4 &&
2797 MI.getOperand(3).getImm() == 0 && "invalid ORRrs operands");
2798 return true;
2799 }
2800 break;
2801 case AArch64::ADDXri: // add Xd, Xn, #0 (LSL #0)
2802 if (MI.getOperand(2).getImm() == 0) {
2803 assert(MI.getDesc().getNumOperands() == 4 &&
2804 MI.getOperand(3).getImm() == 0 && "invalid ADDXri operands");
2805 return true;
2806 }
2807 break;
2808 }
2809 return false;
2810}
2811
2812// Return true if this instruction simply renames a general register without
2813// modifying bits.
2815 switch (MI.getOpcode()) {
2816 default:
2817 break;
2818 case TargetOpcode::COPY: {
2819 Register DstReg = MI.getOperand(0).getReg();
2820 return AArch64::FPR128RegClass.contains(DstReg);
2821 }
2822 case AArch64::ORRv16i8:
2823 if (MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) {
2824 assert(MI.getDesc().getNumOperands() == 3 && MI.getOperand(0).isReg() &&
2825 "invalid ORRv16i8 operands");
2826 return true;
2827 }
2828 break;
2829 }
2830 return false;
2831}
2832
2833static bool isFrameLoadOpcode(int Opcode) {
2834 switch (Opcode) {
2835 default:
2836 return false;
2837 case AArch64::LDRWui:
2838 case AArch64::LDRXui:
2839 case AArch64::LDRBui:
2840 case AArch64::LDRHui:
2841 case AArch64::LDRSui:
2842 case AArch64::LDRDui:
2843 case AArch64::LDRQui:
2844 case AArch64::LDR_PXI:
2845 return true;
2846 }
2847}
2848
2850 int &FrameIndex) const {
2851 if (!isFrameLoadOpcode(MI.getOpcode()))
2852 return Register();
2853
2854 if (MI.getOperand(0).getSubReg() == 0 && MI.getOperand(1).isFI() &&
2855 MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) {
2856 FrameIndex = MI.getOperand(1).getIndex();
2857 return MI.getOperand(0).getReg();
2858 }
2859 return Register();
2860}
2861
2862static bool isFrameStoreOpcode(int Opcode) {
2863 switch (Opcode) {
2864 default:
2865 return false;
2866 case AArch64::STRWui:
2867 case AArch64::STRXui:
2868 case AArch64::STRBui:
2869 case AArch64::STRHui:
2870 case AArch64::STRSui:
2871 case AArch64::STRDui:
2872 case AArch64::STRQui:
2873 case AArch64::STR_PXI:
2874 return true;
2875 }
2876}
2877
2879 int &FrameIndex) const {
2880 if (!isFrameStoreOpcode(MI.getOpcode()))
2881 return Register();
2882
2883 if (MI.getOperand(0).getSubReg() == 0 && MI.getOperand(1).isFI() &&
2884 MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) {
2885 FrameIndex = MI.getOperand(1).getIndex();
2886 return MI.getOperand(0).getReg();
2887 }
2888 return Register();
2889}
2890
2892 int &FrameIndex) const {
2893 if (!isFrameStoreOpcode(MI.getOpcode()))
2894 return Register();
2895
2896 if (Register Reg = isStoreToStackSlot(MI, FrameIndex))
2897 return Reg;
2898
2900 if (hasStoreToStackSlot(MI, Accesses)) {
2901 if (Accesses.size() > 1)
2902 return Register();
2903
2904 FrameIndex =
2905 cast<FixedStackPseudoSourceValue>(Accesses.front()->getPseudoValue())
2906 ->getFrameIndex();
2907 return MI.getOperand(0).getReg();
2908 }
2909 return Register();
2910}
2911
2913 int &FrameIndex) const {
2914 if (!isFrameLoadOpcode(MI.getOpcode()))
2915 return Register();
2916
2917 if (Register Reg = isLoadFromStackSlot(MI, FrameIndex))
2918 return Reg;
2919
2921 if (hasLoadFromStackSlot(MI, Accesses)) {
2922 if (Accesses.size() > 1)
2923 return Register();
2924
2925 FrameIndex =
2926 cast<FixedStackPseudoSourceValue>(Accesses.front()->getPseudoValue())
2927 ->getFrameIndex();
2928 return MI.getOperand(0).getReg();
2929 }
2930 return Register();
2931}
2932
2933/// Check all MachineMemOperands for a hint to suppress pairing.
2935 return llvm::any_of(MI.memoperands(), [](MachineMemOperand *MMO) {
2936 return MMO->getFlags() & MOSuppressPair;
2937 });
2938}
2939
2940/// Set a flag on the first MachineMemOperand to suppress pairing.
2942 if (MI.memoperands_empty())
2943 return;
2944 (*MI.memoperands_begin())->setFlags(MOSuppressPair);
2945}
2946
2947/// Check all MachineMemOperands for a hint that the load/store is strided.
2949 return llvm::any_of(MI.memoperands(), [](MachineMemOperand *MMO) {
2950 return MMO->getFlags() & MOStridedAccess;
2951 });
2952}
2953
2955 switch (Opc) {
2956 default:
2957 return false;
2958 case AArch64::STURSi:
2959 case AArch64::STRSpre:
2960 case AArch64::STURDi:
2961 case AArch64::STRDpre:
2962 case AArch64::STURQi:
2963 case AArch64::STRQpre:
2964 case AArch64::STURBBi:
2965 case AArch64::STURHHi:
2966 case AArch64::STURWi:
2967 case AArch64::STRWpre:
2968 case AArch64::STURXi:
2969 case AArch64::STRXpre:
2970 case AArch64::LDURSi:
2971 case AArch64::LDRSpre:
2972 case AArch64::LDURDi:
2973 case AArch64::LDRDpre:
2974 case AArch64::LDURQi:
2975 case AArch64::LDRQpre:
2976 case AArch64::LDURWi:
2977 case AArch64::LDRWpre:
2978 case AArch64::LDURXi:
2979 case AArch64::LDRXpre:
2980 case AArch64::LDRSWpre:
2981 case AArch64::LDURSWi:
2982 case AArch64::LDURHHi:
2983 case AArch64::LDURBBi:
2984 case AArch64::LDURSBWi:
2985 case AArch64::LDURSHWi:
2986 return true;
2987 }
2988}
2989
2990std::optional<unsigned> AArch64InstrInfo::getUnscaledLdSt(unsigned Opc) {
2991 switch (Opc) {
2992 default: return {};
2993 case AArch64::PRFMui: return AArch64::PRFUMi;
2994 case AArch64::LDRXui: return AArch64::LDURXi;
2995 case AArch64::LDRWui: return AArch64::LDURWi;
2996 case AArch64::LDRBui: return AArch64::LDURBi;
2997 case AArch64::LDRHui: return AArch64::LDURHi;
2998 case AArch64::LDRSui: return AArch64::LDURSi;
2999 case AArch64::LDRDui: return AArch64::LDURDi;
3000 case AArch64::LDRQui: return AArch64::LDURQi;
3001 case AArch64::LDRBBui: return AArch64::LDURBBi;
3002 case AArch64::LDRHHui: return AArch64::LDURHHi;
3003 case AArch64::LDRSBXui: return AArch64::LDURSBXi;
3004 case AArch64::LDRSBWui: return AArch64::LDURSBWi;
3005 case AArch64::LDRSHXui: return AArch64::LDURSHXi;
3006 case AArch64::LDRSHWui: return AArch64::LDURSHWi;
3007 case AArch64::LDRSWui: return AArch64::LDURSWi;
3008 case AArch64::STRXui: return AArch64::STURXi;
3009 case AArch64::STRWui: return AArch64::STURWi;
3010 case AArch64::STRBui: return AArch64::STURBi;
3011 case AArch64::STRHui: return AArch64::STURHi;
3012 case AArch64::STRSui: return AArch64::STURSi;
3013 case AArch64::STRDui: return AArch64::STURDi;
3014 case AArch64::STRQui: return AArch64::STURQi;
3015 case AArch64::STRBBui: return AArch64::STURBBi;
3016 case AArch64::STRHHui: return AArch64::STURHHi;
3017 }
3018}
3019
3021 switch (Opc) {
3022 default:
3023 llvm_unreachable("Unhandled Opcode in getLoadStoreImmIdx");
3024 case AArch64::ADDG:
3025 case AArch64::LDAPURBi:
3026 case AArch64::LDAPURHi:
3027 case AArch64::LDAPURi:
3028 case AArch64::LDAPURSBWi:
3029 case AArch64::LDAPURSBXi:
3030 case AArch64::LDAPURSHWi:
3031 case AArch64::LDAPURSHXi:
3032 case AArch64::LDAPURSWi:
3033 case AArch64::LDAPURXi:
3034 case AArch64::LDR_PPXI:
3035 case AArch64::LDR_PXI:
3036 case AArch64::LDR_ZXI:
3037 case AArch64::LDR_ZZXI:
3038 case AArch64::LDR_ZZXI_STRIDED_CONTIGUOUS:
3039 case AArch64::LDR_ZZZXI:
3040 case AArch64::LDR_ZZZZXI:
3041 case AArch64::LDR_ZZZZXI_STRIDED_CONTIGUOUS:
3042 case AArch64::LDRBBui:
3043 case AArch64::LDRBui:
3044 case AArch64::LDRDui:
3045 case AArch64::LDRHHui:
3046 case AArch64::LDRHui:
3047 case AArch64::LDRQui:
3048 case AArch64::LDRSBWui:
3049 case AArch64::LDRSBXui:
3050 case AArch64::LDRSHWui:
3051 case AArch64::LDRSHXui:
3052 case AArch64::LDRSui:
3053 case AArch64::LDRSWui:
3054 case AArch64::LDRWui:
3055 case AArch64::LDRXui:
3056 case AArch64::LDURBBi:
3057 case AArch64::LDURBi:
3058 case AArch64::LDURDi:
3059 case AArch64::LDURHHi:
3060 case AArch64::LDURHi:
3061 case AArch64::LDURQi:
3062 case AArch64::LDURSBWi:
3063 case AArch64::LDURSBXi:
3064 case AArch64::LDURSHWi:
3065 case AArch64::LDURSHXi:
3066 case AArch64::LDURSi:
3067 case AArch64::LDURSWi:
3068 case AArch64::LDURWi:
3069 case AArch64::LDURXi:
3070 case AArch64::PRFMui:
3071 case AArch64::PRFUMi:
3072 case AArch64::ST2Gi:
3073 case AArch64::STGi:
3074 case AArch64::STLURBi:
3075 case AArch64::STLURHi:
3076 case AArch64::STLURWi:
3077 case AArch64::STLURXi:
3078 case AArch64::StoreSwiftAsyncContext:
3079 case AArch64::STR_PPXI:
3080 case AArch64::STR_PXI:
3081 case AArch64::STR_ZXI:
3082 case AArch64::STR_ZZXI:
3083 case AArch64::STR_ZZXI_STRIDED_CONTIGUOUS:
3084 case AArch64::STR_ZZZXI:
3085 case AArch64::STR_ZZZZXI:
3086 case AArch64::STR_ZZZZXI_STRIDED_CONTIGUOUS:
3087 case AArch64::STRBBui:
3088 case AArch64::STRBui:
3089 case AArch64::STRDui:
3090 case AArch64::STRHHui:
3091 case AArch64::STRHui:
3092 case AArch64::STRQui:
3093 case AArch64::STRSui:
3094 case AArch64::STRWui:
3095 case AArch64::STRXui:
3096 case AArch64::STURBBi:
3097 case AArch64::STURBi:
3098 case AArch64::STURDi:
3099 case AArch64::STURHHi:
3100 case AArch64::STURHi:
3101 case AArch64::STURQi:
3102 case AArch64::STURSi:
3103 case AArch64::STURWi:
3104 case AArch64::STURXi:
3105 case AArch64::STZ2Gi:
3106 case AArch64::STZGi:
3107 case AArch64::TAGPstack:
3108 case AArch64::ATOMIC_STORE_HINT_Bi:
3109 case AArch64::ATOMIC_STORE_HINT_Hi:
3110 case AArch64::ATOMIC_STORE_HINT_Wi:
3111 case AArch64::ATOMIC_STORE_HINT_Si:
3112 case AArch64::ATOMIC_STORE_HINT_Xi:
3113 case AArch64::ATOMIC_STORE_HINT_Di:
3114 case AArch64::ATOMIC_STORE_HINT_Bui:
3115 case AArch64::ATOMIC_STORE_HINT_Hui:
3116 case AArch64::ATOMIC_STORE_HINT_Wui:
3117 case AArch64::ATOMIC_STORE_HINT_Sui:
3118 case AArch64::ATOMIC_STORE_HINT_Xui:
3119 case AArch64::ATOMIC_STORE_HINT_Dui:
3120 return 2;
3121 case AArch64::LD1B_D_IMM:
3122 case AArch64::LD1B_H_IMM:
3123 case AArch64::LD1B_IMM:
3124 case AArch64::LD1B_S_IMM:
3125 case AArch64::LD1D_IMM:
3126 case AArch64::LD1H_D_IMM:
3127 case AArch64::LD1H_IMM:
3128 case AArch64::LD1H_S_IMM:
3129 case AArch64::LD1RB_D_IMM:
3130 case AArch64::LD1RB_H_IMM:
3131 case AArch64::LD1RB_IMM:
3132 case AArch64::LD1RB_S_IMM:
3133 case AArch64::LD1RD_IMM:
3134 case AArch64::LD1RH_D_IMM:
3135 case AArch64::LD1RH_IMM:
3136 case AArch64::LD1RH_S_IMM:
3137 case AArch64::LD1RSB_D_IMM:
3138 case AArch64::LD1RSB_H_IMM:
3139 case AArch64::LD1RSB_S_IMM:
3140 case AArch64::LD1RSH_D_IMM:
3141 case AArch64::LD1RSH_S_IMM:
3142 case AArch64::LD1RSW_IMM:
3143 case AArch64::LD1RW_D_IMM:
3144 case AArch64::LD1RW_IMM:
3145 case AArch64::LD1SB_D_IMM:
3146 case AArch64::LD1SB_H_IMM:
3147 case AArch64::LD1SB_S_IMM:
3148 case AArch64::LD1SH_D_IMM:
3149 case AArch64::LD1SH_S_IMM:
3150 case AArch64::LD1SW_D_IMM:
3151 case AArch64::LD1W_D_IMM:
3152 case AArch64::LD1W_IMM:
3153 case AArch64::LD2B_IMM:
3154 case AArch64::LD2D_IMM:
3155 case AArch64::LD2H_IMM:
3156 case AArch64::LD2W_IMM:
3157 case AArch64::LD3B_IMM:
3158 case AArch64::LD3D_IMM:
3159 case AArch64::LD3H_IMM:
3160 case AArch64::LD3W_IMM:
3161 case AArch64::LD4B_IMM:
3162 case AArch64::LD4D_IMM:
3163 case AArch64::LD4H_IMM:
3164 case AArch64::LD4W_IMM:
3165 case AArch64::LDG:
3166 case AArch64::LDNF1B_D_IMM:
3167 case AArch64::LDNF1B_H_IMM:
3168 case AArch64::LDNF1B_IMM:
3169 case AArch64::LDNF1B_S_IMM:
3170 case AArch64::LDNF1D_IMM:
3171 case AArch64::LDNF1H_D_IMM:
3172 case AArch64::LDNF1H_IMM:
3173 case AArch64::LDNF1H_S_IMM:
3174 case AArch64::LDNF1SB_D_IMM:
3175 case AArch64::LDNF1SB_H_IMM:
3176 case AArch64::LDNF1SB_S_IMM:
3177 case AArch64::LDNF1SH_D_IMM:
3178 case AArch64::LDNF1SH_S_IMM:
3179 case AArch64::LDNF1SW_D_IMM:
3180 case AArch64::LDNF1W_D_IMM:
3181 case AArch64::LDNF1W_IMM:
3182 case AArch64::LDNPDi:
3183 case AArch64::LDNPQi:
3184 case AArch64::LDNPSi:
3185 case AArch64::LDNPWi:
3186 case AArch64::LDNPXi:
3187 case AArch64::LDNT1B_ZRI:
3188 case AArch64::LDNT1D_ZRI:
3189 case AArch64::LDNT1H_ZRI:
3190 case AArch64::LDNT1W_ZRI:
3191 case AArch64::LDPDi:
3192 case AArch64::LDPQi:
3193 case AArch64::LDPSi:
3194 case AArch64::LDPWi:
3195 case AArch64::LDPXi:
3196 case AArch64::LDRBBpost:
3197 case AArch64::LDRBBpre:
3198 case AArch64::LDRBpost:
3199 case AArch64::LDRBpre:
3200 case AArch64::LDRDpost:
3201 case AArch64::LDRDpre:
3202 case AArch64::LDRHHpost:
3203 case AArch64::LDRHHpre:
3204 case AArch64::LDRHpost:
3205 case AArch64::LDRHpre:
3206 case AArch64::LDRQpost:
3207 case AArch64::LDRQpre:
3208 case AArch64::LDRSpost:
3209 case AArch64::LDRSpre:
3210 case AArch64::LDRWpost:
3211 case AArch64::LDRWpre:
3212 case AArch64::LDRXpost:
3213 case AArch64::LDRXpre:
3214 case AArch64::ST1B_D_IMM:
3215 case AArch64::ST1B_H_IMM:
3216 case AArch64::ST1B_IMM:
3217 case AArch64::ST1B_S_IMM:
3218 case AArch64::ST1D_IMM:
3219 case AArch64::ST1H_D_IMM:
3220 case AArch64::ST1H_IMM:
3221 case AArch64::ST1H_S_IMM:
3222 case AArch64::ST1W_D_IMM:
3223 case AArch64::ST1W_IMM:
3224 case AArch64::ST2B_IMM:
3225 case AArch64::ST2D_IMM:
3226 case AArch64::ST2H_IMM:
3227 case AArch64::ST2W_IMM:
3228 case AArch64::ST3B_IMM:
3229 case AArch64::ST3D_IMM:
3230 case AArch64::ST3H_IMM:
3231 case AArch64::ST3W_IMM:
3232 case AArch64::ST4B_IMM:
3233 case AArch64::ST4D_IMM:
3234 case AArch64::ST4H_IMM:
3235 case AArch64::ST4W_IMM:
3236 case AArch64::STGPi:
3237 case AArch64::STGPreIndex:
3238 case AArch64::STZGPreIndex:
3239 case AArch64::ST2GPreIndex:
3240 case AArch64::STZ2GPreIndex:
3241 case AArch64::STGPostIndex:
3242 case AArch64::STZGPostIndex:
3243 case AArch64::ST2GPostIndex:
3244 case AArch64::STZ2GPostIndex:
3245 case AArch64::STNPDi:
3246 case AArch64::STNPQi:
3247 case AArch64::STNPSi:
3248 case AArch64::STNPWi:
3249 case AArch64::STNPXi:
3250 case AArch64::STNT1B_ZRI:
3251 case AArch64::STNT1D_ZRI:
3252 case AArch64::STNT1H_ZRI:
3253 case AArch64::STNT1W_ZRI:
3254 case AArch64::STPDi:
3255 case AArch64::STPQi:
3256 case AArch64::STPSi:
3257 case AArch64::STPWi:
3258 case AArch64::STPXi:
3259 case AArch64::STRBBpost:
3260 case AArch64::STRBBpre:
3261 case AArch64::STRBpost:
3262 case AArch64::STRBpre:
3263 case AArch64::STRDpost:
3264 case AArch64::STRDpre:
3265 case AArch64::STRHHpost:
3266 case AArch64::STRHHpre:
3267 case AArch64::STRHpost:
3268 case AArch64::STRHpre:
3269 case AArch64::STRQpost:
3270 case AArch64::STRQpre:
3271 case AArch64::STRSpost:
3272 case AArch64::STRSpre:
3273 case AArch64::STRWpost:
3274 case AArch64::STRWpre:
3275 case AArch64::STRXpost:
3276 case AArch64::STRXpre:
3277 case AArch64::LD1B_2Z_IMM:
3278 case AArch64::LD1B_2Z_STRIDED_IMM:
3279 case AArch64::LD1H_2Z_IMM:
3280 case AArch64::LD1H_2Z_STRIDED_IMM:
3281 case AArch64::LD1W_2Z_IMM:
3282 case AArch64::LD1W_2Z_STRIDED_IMM:
3283 case AArch64::LD1D_2Z_IMM:
3284 case AArch64::LD1D_2Z_STRIDED_IMM:
3285 case AArch64::LD1B_4Z_IMM:
3286 case AArch64::LD1B_4Z_STRIDED_IMM:
3287 case AArch64::LD1H_4Z_IMM:
3288 case AArch64::LD1H_4Z_STRIDED_IMM:
3289 case AArch64::LD1W_4Z_IMM:
3290 case AArch64::LD1W_4Z_STRIDED_IMM:
3291 case AArch64::LD1D_4Z_IMM:
3292 case AArch64::LD1D_4Z_STRIDED_IMM:
3293 case AArch64::LD1B_2Z_IMM_PSEUDO:
3294 case AArch64::LD1H_2Z_IMM_PSEUDO:
3295 case AArch64::LD1W_2Z_IMM_PSEUDO:
3296 case AArch64::LD1D_2Z_IMM_PSEUDO:
3297 case AArch64::LD1B_4Z_IMM_PSEUDO:
3298 case AArch64::LD1H_4Z_IMM_PSEUDO:
3299 case AArch64::LD1W_4Z_IMM_PSEUDO:
3300 case AArch64::LD1D_4Z_IMM_PSEUDO:
3301 case AArch64::ST1B_2Z_IMM:
3302 case AArch64::ST1B_2Z_STRIDED_IMM:
3303 case AArch64::ST1H_2Z_IMM:
3304 case AArch64::ST1H_2Z_STRIDED_IMM:
3305 case AArch64::ST1W_2Z_IMM:
3306 case AArch64::ST1W_2Z_STRIDED_IMM:
3307 case AArch64::ST1D_2Z_IMM:
3308 case AArch64::ST1D_2Z_STRIDED_IMM:
3309 case AArch64::LDNT1B_2Z_IMM_PSEUDO:
3310 case AArch64::LDNT1B_2Z_IMM:
3311 case AArch64::LDNT1B_2Z_STRIDED_IMM:
3312 case AArch64::LDNT1H_2Z_IMM_PSEUDO:
3313 case AArch64::LDNT1H_2Z_IMM:
3314 case AArch64::LDNT1H_2Z_STRIDED_IMM:
3315 case AArch64::LDNT1W_2Z_IMM_PSEUDO:
3316 case AArch64::LDNT1W_2Z_IMM:
3317 case AArch64::LDNT1W_2Z_STRIDED_IMM:
3318 case AArch64::LDNT1D_2Z_IMM_PSEUDO:
3319 case AArch64::LDNT1D_2Z_IMM:
3320 case AArch64::LDNT1D_2Z_STRIDED_IMM:
3321 case AArch64::STNT1B_2Z_IMM:
3322 case AArch64::STNT1B_2Z_STRIDED_IMM:
3323 case AArch64::STNT1H_2Z_IMM:
3324 case AArch64::STNT1H_2Z_STRIDED_IMM:
3325 case AArch64::STNT1W_2Z_IMM:
3326 case AArch64::STNT1W_2Z_STRIDED_IMM:
3327 case AArch64::STNT1D_2Z_IMM:
3328 case AArch64::STNT1D_2Z_STRIDED_IMM:
3329 case AArch64::ST1B_2Z_IMM_PSEUDO:
3330 case AArch64::ST1H_2Z_IMM_PSEUDO:
3331 case AArch64::ST1W_2Z_IMM_PSEUDO:
3332 case AArch64::ST1D_2Z_IMM_PSEUDO:
3333 case AArch64::STNT1B_2Z_IMM_PSEUDO:
3334 case AArch64::STNT1H_2Z_IMM_PSEUDO:
3335 case AArch64::STNT1W_2Z_IMM_PSEUDO:
3336 case AArch64::STNT1D_2Z_IMM_PSEUDO:
3337 case AArch64::ST1B_4Z_IMM:
3338 case AArch64::ST1B_4Z_STRIDED_IMM:
3339 case AArch64::ST1H_4Z_IMM:
3340 case AArch64::ST1H_4Z_STRIDED_IMM:
3341 case AArch64::ST1W_4Z_IMM:
3342 case AArch64::ST1W_4Z_STRIDED_IMM:
3343 case AArch64::ST1D_4Z_IMM:
3344 case AArch64::ST1D_4Z_STRIDED_IMM:
3345 case AArch64::LDNT1B_4Z_IMM_PSEUDO:
3346 case AArch64::LDNT1B_4Z_IMM:
3347 case AArch64::LDNT1B_4Z_STRIDED_IMM:
3348 case AArch64::LDNT1H_4Z_IMM_PSEUDO:
3349 case AArch64::LDNT1H_4Z_IMM:
3350 case AArch64::LDNT1H_4Z_STRIDED_IMM:
3351 case AArch64::LDNT1W_4Z_IMM_PSEUDO:
3352 case AArch64::LDNT1W_4Z_IMM:
3353 case AArch64::LDNT1W_4Z_STRIDED_IMM:
3354 case AArch64::LDNT1D_4Z_IMM_PSEUDO:
3355 case AArch64::LDNT1D_4Z_IMM:
3356 case AArch64::LDNT1D_4Z_STRIDED_IMM:
3357 case AArch64::STNT1B_4Z_IMM:
3358 case AArch64::STNT1B_4Z_STRIDED_IMM:
3359 case AArch64::STNT1H_4Z_IMM:
3360 case AArch64::STNT1H_4Z_STRIDED_IMM:
3361 case AArch64::STNT1W_4Z_IMM:
3362 case AArch64::STNT1W_4Z_STRIDED_IMM:
3363 case AArch64::STNT1D_4Z_IMM:
3364 case AArch64::STNT1D_4Z_STRIDED_IMM:
3365 case AArch64::ST1B_4Z_IMM_PSEUDO:
3366 case AArch64::ST1H_4Z_IMM_PSEUDO:
3367 case AArch64::ST1W_4Z_IMM_PSEUDO:
3368 case AArch64::ST1D_4Z_IMM_PSEUDO:
3369 case AArch64::STNT1B_4Z_IMM_PSEUDO:
3370 case AArch64::STNT1H_4Z_IMM_PSEUDO:
3371 case AArch64::STNT1W_4Z_IMM_PSEUDO:
3372 case AArch64::STNT1D_4Z_IMM_PSEUDO:
3373 return 3;
3374 case AArch64::LDPDpost:
3375 case AArch64::LDPDpre:
3376 case AArch64::LDPQpost:
3377 case AArch64::LDPQpre:
3378 case AArch64::LDPSpost:
3379 case AArch64::LDPSpre:
3380 case AArch64::LDPWpost:
3381 case AArch64::LDPWpre:
3382 case AArch64::LDPXpost:
3383 case AArch64::LDPXpre:
3384 case AArch64::STGPpre:
3385 case AArch64::STGPpost:
3386 case AArch64::STPDpost:
3387 case AArch64::STPDpre:
3388 case AArch64::STPQpost:
3389 case AArch64::STPQpre:
3390 case AArch64::STPSpost:
3391 case AArch64::STPSpre:
3392 case AArch64::STPWpost:
3393 case AArch64::STPWpre:
3394 case AArch64::STPXpost:
3395 case AArch64::STPXpre:
3396 return 4;
3397 }
3398}
3399
3401 switch (MI.getOpcode()) {
3402 default:
3403 return false;
3404 // Scaled instructions.
3405 case AArch64::STRSui:
3406 case AArch64::STRDui:
3407 case AArch64::STRQui:
3408 case AArch64::STRXui:
3409 case AArch64::STRWui:
3410 case AArch64::LDRSui:
3411 case AArch64::LDRDui:
3412 case AArch64::LDRQui:
3413 case AArch64::LDRXui:
3414 case AArch64::LDRWui:
3415 case AArch64::LDRSWui:
3416 // Unscaled instructions.
3417 case AArch64::STURSi:
3418 case AArch64::STRSpre:
3419 case AArch64::STURDi:
3420 case AArch64::STRDpre:
3421 case AArch64::STURQi:
3422 case AArch64::STRQpre:
3423 case AArch64::STURWi:
3424 case AArch64::STRWpre:
3425 case AArch64::STURXi:
3426 case AArch64::STRXpre:
3427 case AArch64::LDURSi:
3428 case AArch64::LDRSpre:
3429 case AArch64::LDURDi:
3430 case AArch64::LDRDpre:
3431 case AArch64::LDURQi:
3432 case AArch64::LDRQpre:
3433 case AArch64::LDURWi:
3434 case AArch64::LDRWpre:
3435 case AArch64::LDURXi:
3436 case AArch64::LDRXpre:
3437 case AArch64::LDURSWi:
3438 case AArch64::LDRSWpre:
3439 // SVE instructions.
3440 case AArch64::LDR_ZXI:
3441 case AArch64::STR_ZXI:
3442 return true;
3443 }
3444}
3445
3447 switch (MI.getOpcode()) {
3448 default:
3449 assert((!MI.isCall() || !MI.isReturn()) &&
3450 "Unexpected instruction - was a new tail call opcode introduced?");
3451 return false;
3452 case AArch64::TCRETURNdi:
3453 case AArch64::TCRETURNri:
3454 case AArch64::TCRETURNrix16x17:
3455 case AArch64::TCRETURNrix17:
3456 case AArch64::TCRETURNrinotx16:
3457 case AArch64::TCRETURNriALL:
3458 case AArch64::AUTH_TCRETURN:
3459 case AArch64::AUTH_TCRETURN_BTI:
3460 return true;
3461 }
3462}
3463
3465 switch (Opc) {
3466 default:
3467 llvm_unreachable("Opcode has no flag setting equivalent!");
3468 // 32-bit cases:
3469 case AArch64::ADDWri:
3470 return AArch64::ADDSWri;
3471 case AArch64::ADDWrr:
3472 return AArch64::ADDSWrr;
3473 case AArch64::ADDWrs:
3474 return AArch64::ADDSWrs;
3475 case AArch64::ADDWrx:
3476 return AArch64::ADDSWrx;
3477 case AArch64::ANDWri:
3478 return AArch64::ANDSWri;
3479 case AArch64::ANDWrr:
3480 return AArch64::ANDSWrr;
3481 case AArch64::ANDWrs:
3482 return AArch64::ANDSWrs;
3483 case AArch64::BICWrr:
3484 return AArch64::BICSWrr;
3485 case AArch64::BICWrs:
3486 return AArch64::BICSWrs;
3487 case AArch64::SUBWri:
3488 return AArch64::SUBSWri;
3489 case AArch64::SUBWrr:
3490 return AArch64::SUBSWrr;
3491 case AArch64::SUBWrs:
3492 return AArch64::SUBSWrs;
3493 case AArch64::SUBWrx:
3494 return AArch64::SUBSWrx;
3495 // 64-bit cases:
3496 case AArch64::ADDXri:
3497 return AArch64::ADDSXri;
3498 case AArch64::ADDXrr:
3499 return AArch64::ADDSXrr;
3500 case AArch64::ADDXrs:
3501 return AArch64::ADDSXrs;
3502 case AArch64::ADDXrx:
3503 return AArch64::ADDSXrx;
3504 case AArch64::ANDXri:
3505 return AArch64::ANDSXri;
3506 case AArch64::ANDXrr:
3507 return AArch64::ANDSXrr;
3508 case AArch64::ANDXrs:
3509 return AArch64::ANDSXrs;
3510 case AArch64::BICXrr:
3511 return AArch64::BICSXrr;
3512 case AArch64::BICXrs:
3513 return AArch64::BICSXrs;
3514 case AArch64::SUBXri:
3515 return AArch64::SUBSXri;
3516 case AArch64::SUBXrr:
3517 return AArch64::SUBSXrr;
3518 case AArch64::SUBXrs:
3519 return AArch64::SUBSXrs;
3520 case AArch64::SUBXrx:
3521 return AArch64::SUBSXrx;
3522 // SVE instructions:
3523 case AArch64::AND_PPzPP:
3524 return AArch64::ANDS_PPzPP;
3525 case AArch64::BIC_PPzPP:
3526 return AArch64::BICS_PPzPP;
3527 case AArch64::EOR_PPzPP:
3528 return AArch64::EORS_PPzPP;
3529 case AArch64::NAND_PPzPP:
3530 return AArch64::NANDS_PPzPP;
3531 case AArch64::NOR_PPzPP:
3532 return AArch64::NORS_PPzPP;
3533 case AArch64::ORN_PPzPP:
3534 return AArch64::ORNS_PPzPP;
3535 case AArch64::ORR_PPzPP:
3536 return AArch64::ORRS_PPzPP;
3537 case AArch64::BRKA_PPzP:
3538 return AArch64::BRKAS_PPzP;
3539 case AArch64::BRKPA_PPzPP:
3540 return AArch64::BRKPAS_PPzPP;
3541 case AArch64::BRKB_PPzP:
3542 return AArch64::BRKBS_PPzP;
3543 case AArch64::BRKPB_PPzPP:
3544 return AArch64::BRKPBS_PPzPP;
3545 case AArch64::BRKN_PPzP:
3546 return AArch64::BRKNS_PPzP;
3547 case AArch64::RDFFR_PPz:
3548 return AArch64::RDFFRS_PPz;
3549 case AArch64::PTRUE_B:
3550 return AArch64::PTRUES_B;
3551 }
3552}
3553
3554// Is this a candidate for ld/st merging or pairing? For example, we don't
3555// touch volatiles or load/stores that have a hint to avoid pair formation.
3557
3558 bool IsPreLdSt = isPreLdSt(MI);
3559
3560 // If this is a volatile load/store, don't mess with it.
3561 if (MI.hasOrderedMemoryRef())
3562 return false;
3563
3564 // Make sure this is a reg/fi+imm (as opposed to an address reloc).
3565 // For Pre-inc LD/ST, the operand is shifted by one.
3566 assert((MI.getOperand(IsPreLdSt ? 2 : 1).isReg() ||
3567 MI.getOperand(IsPreLdSt ? 2 : 1).isFI()) &&
3568 "Expected a reg or frame index operand.");
3569
3570 // For Pre-indexed addressing quadword instructions, the third operand is the
3571 // immediate value.
3572 bool IsImmPreLdSt = IsPreLdSt && MI.getOperand(3).isImm();
3573
3574 if (!MI.getOperand(2).isImm() && !IsImmPreLdSt)
3575 return false;
3576
3577 // Can't merge/pair if the instruction modifies the base register.
3578 // e.g., ldr x0, [x0]
3579 // This case will never occur with an FI base.
3580 // However, if the instruction is an LDR<S,D,Q,W,X,SW>pre or
3581 // STR<S,D,Q,W,X>pre, it can be merged.
3582 // For example:
3583 // ldr q0, [x11, #32]!
3584 // ldr q1, [x11, #16]
3585 // to
3586 // ldp q0, q1, [x11, #32]!
3587 if (MI.getOperand(1).isReg() && !IsPreLdSt) {
3588 Register BaseReg = MI.getOperand(1).getReg();
3590 if (MI.modifiesRegister(BaseReg, TRI))
3591 return false;
3592 }
3593
3594 // Pairing SVE fills/spills is only valid for little-endian targets that
3595 // implement VLS 128.
3596 switch (MI.getOpcode()) {
3597 default:
3598 break;
3599 case AArch64::LDR_ZXI:
3600 case AArch64::STR_ZXI:
3601 if (!Subtarget.isLittleEndian() ||
3602 Subtarget.getSVEVectorSizeInBits() != 128)
3603 return false;
3604 }
3605
3606 // Check if this load/store has a hint to avoid pair formation.
3607 // MachineMemOperands hints are set by the AArch64StorePairSuppress pass.
3609 return false;
3610
3611 // Do not pair any callee-save store/reload instructions in the
3612 // prologue/epilogue if the CFI information encoded the operations as separate
3613 // instructions, as that will cause the size of the actual prologue to mismatch
3614 // with the prologue size recorded in the Windows CFI.
3615 if ((MI.getFlag(MachineInstr::FrameSetup) ||
3616 MI.getFlag(MachineInstr::FrameDestroy)) &&
3617 MI.getMF()->needsWinCFI())
3618 return false;
3619
3620 // On some CPUs quad load/store pairs are slower than two single load/stores.
3621 if (Subtarget.isPaired128Slow()) {
3622 switch (MI.getOpcode()) {
3623 default:
3624 break;
3625 case AArch64::LDURQi:
3626 case AArch64::STURQi:
3627 case AArch64::LDRQui:
3628 case AArch64::STRQui:
3629 return false;
3630 }
3631 }
3632
3633 return true;
3634}
3635
3638 int64_t &Offset, bool &OffsetIsScalable, LocationSize &Width) const {
3639 if (!LdSt.mayLoadOrStore())
3640 return false;
3641
3642 const MachineOperand *BaseOp;
3643 TypeSize WidthN(0, false);
3644 if (!getMemOperandWithOffsetWidth(LdSt, BaseOp, Offset, OffsetIsScalable,
3645 WidthN))
3646 return false;
3647 // The maximum vscale is 16 under AArch64, return the maximal extent for the
3648 // vector.
3649 Width = LocationSize::precise(WidthN);
3650 BaseOps.push_back(BaseOp);
3651 return true;
3652}
3653
3654std::optional<ExtAddrMode>
3656 const MachineOperand *Base; // Filled with the base operand of MI.
3657 int64_t Offset; // Filled with the offset of MI.
3658 bool OffsetIsScalable;
3659 if (!getMemOperandWithOffset(MemI, Base, Offset, OffsetIsScalable))
3660 return std::nullopt;
3661
3662 if (!Base->isReg())
3663 return std::nullopt;
3664 ExtAddrMode AM;
3665 AM.BaseReg = Base->getReg();
3666 AM.Displacement = Offset;
3667 AM.ScaledReg = 0;
3668 AM.Scale = 0;
3669 return AM;
3670}
3671
3673 Register Reg,
3674 const MachineInstr &AddrI,
3675 ExtAddrMode &AM) const {
3676 // Filter out instructions into which we cannot fold.
3677 unsigned NumBytes;
3678 int64_t OffsetScale = 1;
3679 switch (MemI.getOpcode()) {
3680 default:
3681 return false;
3682
3683 case AArch64::LDURQi:
3684 case AArch64::STURQi:
3685 NumBytes = 16;
3686 break;
3687
3688 case AArch64::LDURDi:
3689 case AArch64::STURDi:
3690 case AArch64::LDURXi:
3691 case AArch64::STURXi:
3692 NumBytes = 8;
3693 break;
3694
3695 case AArch64::LDURWi:
3696 case AArch64::LDURSWi:
3697 case AArch64::STURWi:
3698 NumBytes = 4;
3699 break;
3700
3701 case AArch64::LDURHi:
3702 case AArch64::STURHi:
3703 case AArch64::LDURHHi:
3704 case AArch64::STURHHi:
3705 case AArch64::LDURSHXi:
3706 case AArch64::LDURSHWi:
3707 NumBytes = 2;
3708 break;
3709
3710 case AArch64::LDRBroX:
3711 case AArch64::LDRBBroX:
3712 case AArch64::LDRSBXroX:
3713 case AArch64::LDRSBWroX:
3714 case AArch64::STRBroX:
3715 case AArch64::STRBBroX:
3716 case AArch64::LDURBi:
3717 case AArch64::LDURBBi:
3718 case AArch64::LDURSBXi:
3719 case AArch64::LDURSBWi:
3720 case AArch64::STURBi:
3721 case AArch64::STURBBi:
3722 case AArch64::LDRBui:
3723 case AArch64::LDRBBui:
3724 case AArch64::LDRSBXui:
3725 case AArch64::LDRSBWui:
3726 case AArch64::STRBui:
3727 case AArch64::STRBBui:
3728 NumBytes = 1;
3729 break;
3730
3731 case AArch64::LDRQroX:
3732 case AArch64::STRQroX:
3733 case AArch64::LDRQui:
3734 case AArch64::STRQui:
3735 NumBytes = 16;
3736 OffsetScale = 16;
3737 break;
3738
3739 case AArch64::LDRDroX:
3740 case AArch64::STRDroX:
3741 case AArch64::LDRXroX:
3742 case AArch64::STRXroX:
3743 case AArch64::LDRDui:
3744 case AArch64::STRDui:
3745 case AArch64::LDRXui:
3746 case AArch64::STRXui:
3747 NumBytes = 8;
3748 OffsetScale = 8;
3749 break;
3750
3751 case AArch64::LDRWroX:
3752 case AArch64::LDRSWroX:
3753 case AArch64::STRWroX:
3754 case AArch64::LDRWui:
3755 case AArch64::LDRSWui:
3756 case AArch64::STRWui:
3757 NumBytes = 4;
3758 OffsetScale = 4;
3759 break;
3760
3761 case AArch64::LDRHroX:
3762 case AArch64::STRHroX:
3763 case AArch64::LDRHHroX:
3764 case AArch64::STRHHroX:
3765 case AArch64::LDRSHXroX:
3766 case AArch64::LDRSHWroX:
3767 case AArch64::LDRHui:
3768 case AArch64::STRHui:
3769 case AArch64::LDRHHui:
3770 case AArch64::STRHHui:
3771 case AArch64::LDRSHXui:
3772 case AArch64::LDRSHWui:
3773 NumBytes = 2;
3774 OffsetScale = 2;
3775 break;
3776 }
3777
3778 // Check the fold operand is not the loaded/stored value.
3779 const MachineOperand &BaseRegOp = MemI.getOperand(0);
3780 if (BaseRegOp.isReg() && BaseRegOp.getReg() == Reg)
3781 return false;
3782
3783 // Handle memory instructions with a [Reg, Reg] addressing mode.
3784 if (MemI.getOperand(2).isReg()) {
3785 // Bail if the addressing mode already includes extension of the offset
3786 // register.
3787 if (MemI.getOperand(3).getImm())
3788 return false;
3789
3790 // Check if we actually have a scaled offset.
3791 if (MemI.getOperand(4).getImm() == 0)
3792 OffsetScale = 1;
3793
3794 // If the address instructions is folded into the base register, then the
3795 // addressing mode must not have a scale. Then we can swap the base and the
3796 // scaled registers.
3797 if (MemI.getOperand(1).getReg() == Reg && OffsetScale != 1)
3798 return false;
3799
3800 switch (AddrI.getOpcode()) {
3801 default:
3802 return false;
3803
3804 case AArch64::SBFMXri:
3805 // sxtw Xa, Wm
3806 // ldr Xd, [Xn, Xa, lsl #N]
3807 // ->
3808 // ldr Xd, [Xn, Wm, sxtw #N]
3809 if (AddrI.getOperand(2).getImm() != 0 ||
3810 AddrI.getOperand(3).getImm() != 31)
3811 return false;
3812
3813 AM.BaseReg = MemI.getOperand(1).getReg();
3814 if (AM.BaseReg == Reg)
3815 AM.BaseReg = MemI.getOperand(2).getReg();
3816 AM.ScaledReg = AddrI.getOperand(1).getReg();
3817 AM.Scale = OffsetScale;
3818 AM.Displacement = 0;
3820 return true;
3821
3822 case TargetOpcode::SUBREG_TO_REG: {
3823 // mov Wa, Wm
3824 // ldr Xd, [Xn, Xa, lsl #N]
3825 // ->
3826 // ldr Xd, [Xn, Wm, uxtw #N]
3827
3828 // Zero-extension looks like an ORRWrs followed by a SUBREG_TO_REG.
3829 if (AddrI.getOperand(2).getImm() != AArch64::sub_32)
3830 return false;
3831
3832 const MachineRegisterInfo &MRI = AddrI.getMF()->getRegInfo();
3833 Register OffsetReg = AddrI.getOperand(1).getReg();
3834 if (!OffsetReg.isVirtual() || !MRI.hasOneNonDBGUse(OffsetReg))
3835 return false;
3836
3837 const MachineInstr &DefMI = *MRI.getVRegDef(OffsetReg);
3838 if (DefMI.getOpcode() != AArch64::ORRWrs ||
3839 DefMI.getOperand(1).getReg() != AArch64::WZR ||
3840 DefMI.getOperand(3).getImm() != 0)
3841 return false;
3842
3843 AM.BaseReg = MemI.getOperand(1).getReg();
3844 if (AM.BaseReg == Reg)
3845 AM.BaseReg = MemI.getOperand(2).getReg();
3846 AM.ScaledReg = DefMI.getOperand(2).getReg();
3847 AM.Scale = OffsetScale;
3848 AM.Displacement = 0;
3850 return true;
3851 }
3852 }
3853 }
3854
3855 // Handle memory instructions with a [Reg, #Imm] addressing mode.
3856
3857 // Check we are not breaking a potential conversion to an LDP.
3858 auto validateOffsetForLDP = [](unsigned NumBytes, int64_t OldOffset,
3859 int64_t NewOffset) -> bool {
3860 int64_t MinOffset, MaxOffset;
3861 switch (NumBytes) {
3862 default:
3863 return true;
3864 case 4:
3865 MinOffset = -256;
3866 MaxOffset = 252;
3867 break;
3868 case 8:
3869 MinOffset = -512;
3870 MaxOffset = 504;
3871 break;
3872 case 16:
3873 MinOffset = -1024;
3874 MaxOffset = 1008;
3875 break;
3876 }
3877 return OldOffset < MinOffset || OldOffset > MaxOffset ||
3878 (NewOffset >= MinOffset && NewOffset <= MaxOffset);
3879 };
3880 auto canFoldAddSubImmIntoAddrMode = [&](int64_t Disp) -> bool {
3881 int64_t OldOffset = MemI.getOperand(2).getImm() * OffsetScale;
3882 int64_t NewOffset = OldOffset + Disp;
3883 if (!isLegalAddressingMode(NumBytes, NewOffset, /* Scale */ 0))
3884 return false;
3885 // If the old offset would fit into an LDP, but the new offset wouldn't,
3886 // bail out.
3887 if (!validateOffsetForLDP(NumBytes, OldOffset, NewOffset))
3888 return false;
3889 AM.BaseReg = AddrI.getOperand(1).getReg();
3890 AM.ScaledReg = 0;
3891 AM.Scale = 0;
3892 AM.Displacement = NewOffset;
3894 return true;
3895 };
3896
3897 auto canFoldAddRegIntoAddrMode =
3898 [&](int64_t Scale,
3900 if (MemI.getOperand(2).getImm() != 0)
3901 return false;
3902 if ((unsigned)Scale != Scale)
3903 return false;
3904 if (!isLegalAddressingMode(NumBytes, /* Offset */ 0, Scale))
3905 return false;
3906 AM.BaseReg = AddrI.getOperand(1).getReg();
3907 AM.ScaledReg = AddrI.getOperand(2).getReg();
3908 AM.Scale = Scale;
3909 AM.Displacement = 0;
3910 AM.Form = Form;
3911 return true;
3912 };
3913
3914 auto avoidSlowSTRQ = [&](const MachineInstr &MemI) {
3915 unsigned Opcode = MemI.getOpcode();
3916 return (Opcode == AArch64::STURQi || Opcode == AArch64::STRQui) &&
3917 Subtarget.isSTRQroSlow();
3918 };
3919
3920 int64_t Disp = 0;
3921 const bool OptSize = MemI.getMF()->getFunction().hasOptSize();
3922 switch (AddrI.getOpcode()) {
3923 default:
3924 return false;
3925
3926 case AArch64::ADDXri:
3927 // add Xa, Xn, #N
3928 // ldr Xd, [Xa, #M]
3929 // ->
3930 // ldr Xd, [Xn, #N'+M]
3931 Disp = AddrI.getOperand(2).getImm() << AddrI.getOperand(3).getImm();
3932 return canFoldAddSubImmIntoAddrMode(Disp);
3933
3934 case AArch64::SUBXri:
3935 // sub Xa, Xn, #N
3936 // ldr Xd, [Xa, #M]
3937 // ->
3938 // ldr Xd, [Xn, #N'+M]
3939 Disp = AddrI.getOperand(2).getImm() << AddrI.getOperand(3).getImm();
3940 return canFoldAddSubImmIntoAddrMode(-Disp);
3941
3942 case AArch64::ADDXrs: {
3943 // add Xa, Xn, Xm, lsl #N
3944 // ldr Xd, [Xa]
3945 // ->
3946 // ldr Xd, [Xn, Xm, lsl #N]
3947
3948 // Don't fold the add if the result would be slower, unless optimising for
3949 // size.
3950 unsigned Shift = static_cast<unsigned>(AddrI.getOperand(3).getImm());
3952 return false;
3953 Shift = AArch64_AM::getShiftValue(Shift);
3954 if (!OptSize) {
3955 if (Shift != 2 && Shift != 3 && Subtarget.hasAddrLSLSlow14())
3956 return false;
3957 if (avoidSlowSTRQ(MemI))
3958 return false;
3959 }
3960 return canFoldAddRegIntoAddrMode(1ULL << Shift);
3961 }
3962
3963 case AArch64::ADDXrr:
3964 // add Xa, Xn, Xm
3965 // ldr Xd, [Xa]
3966 // ->
3967 // ldr Xd, [Xn, Xm, lsl #0]
3968
3969 // Don't fold the add if the result would be slower, unless optimising for
3970 // size.
3971 if (!OptSize && avoidSlowSTRQ(MemI))
3972 return false;
3973 return canFoldAddRegIntoAddrMode(1);
3974
3975 case AArch64::ADDXrx:
3976 // add Xa, Xn, Wm, {s,u}xtw #N
3977 // ldr Xd, [Xa]
3978 // ->
3979 // ldr Xd, [Xn, Wm, {s,u}xtw #N]
3980
3981 // Don't fold the add if the result would be slower, unless optimising for
3982 // size.
3983 if (!OptSize && avoidSlowSTRQ(MemI))
3984 return false;
3985
3986 // Can fold only sign-/zero-extend of a word.
3987 unsigned Imm = static_cast<unsigned>(AddrI.getOperand(3).getImm());
3989 if (Extend != AArch64_AM::UXTW && Extend != AArch64_AM::SXTW)
3990 return false;
3991
3992 return canFoldAddRegIntoAddrMode(
3996 }
3997}
3998
3999// Given an opcode for an instruction with a [Reg, #Imm] addressing mode,
4000// return the opcode of an instruction performing the same operation, but using
4001// the [Reg, Reg] addressing mode.
4002static unsigned regOffsetOpcode(unsigned Opcode) {
4003 switch (Opcode) {
4004 default:
4005 llvm_unreachable("Address folding not implemented for instruction");
4006
4007 case AArch64::LDURQi:
4008 case AArch64::LDRQui:
4009 return AArch64::LDRQroX;
4010 case AArch64::STURQi:
4011 case AArch64::STRQui:
4012 return AArch64::STRQroX;
4013 case AArch64::LDURDi:
4014 case AArch64::LDRDui:
4015 return AArch64::LDRDroX;
4016 case AArch64::STURDi:
4017 case AArch64::STRDui:
4018 return AArch64::STRDroX;
4019 case AArch64::LDURXi:
4020 case AArch64::LDRXui:
4021 return AArch64::LDRXroX;
4022 case AArch64::STURXi:
4023 case AArch64::STRXui:
4024 return AArch64::STRXroX;
4025 case AArch64::LDURWi:
4026 case AArch64::LDRWui:
4027 return AArch64::LDRWroX;
4028 case AArch64::LDURSWi:
4029 case AArch64::LDRSWui:
4030 return AArch64::LDRSWroX;
4031 case AArch64::STURWi:
4032 case AArch64::STRWui:
4033 return AArch64::STRWroX;
4034 case AArch64::LDURHi:
4035 case AArch64::LDRHui:
4036 return AArch64::LDRHroX;
4037 case AArch64::STURHi:
4038 case AArch64::STRHui:
4039 return AArch64::STRHroX;
4040 case AArch64::LDURHHi:
4041 case AArch64::LDRHHui:
4042 return AArch64::LDRHHroX;
4043 case AArch64::STURHHi:
4044 case AArch64::STRHHui:
4045 return AArch64::STRHHroX;
4046 case AArch64::LDURSHXi:
4047 case AArch64::LDRSHXui:
4048 return AArch64::LDRSHXroX;
4049 case AArch64::LDURSHWi:
4050 case AArch64::LDRSHWui:
4051 return AArch64::LDRSHWroX;
4052 case AArch64::LDURBi:
4053 case AArch64::LDRBui:
4054 return AArch64::LDRBroX;
4055 case AArch64::LDURBBi:
4056 case AArch64::LDRBBui:
4057 return AArch64::LDRBBroX;
4058 case AArch64::LDURSBXi:
4059 case AArch64::LDRSBXui:
4060 return AArch64::LDRSBXroX;
4061 case AArch64::LDURSBWi:
4062 case AArch64::LDRSBWui:
4063 return AArch64::LDRSBWroX;
4064 case AArch64::STURBi:
4065 case AArch64::STRBui:
4066 return AArch64::STRBroX;
4067 case AArch64::STURBBi:
4068 case AArch64::STRBBui:
4069 return AArch64::STRBBroX;
4070 }
4071}
4072
4073// Given an opcode for an instruction with a [Reg, #Imm] addressing mode, return
4074// the opcode of an instruction performing the same operation, but using the
4075// [Reg, #Imm] addressing mode with scaled offset.
4076unsigned scaledOffsetOpcode(unsigned Opcode, unsigned &Scale) {
4077 switch (Opcode) {
4078 default:
4079 llvm_unreachable("Address folding not implemented for instruction");
4080
4081 case AArch64::LDURQi:
4082 Scale = 16;
4083 return AArch64::LDRQui;
4084 case AArch64::STURQi:
4085 Scale = 16;
4086 return AArch64::STRQui;
4087 case AArch64::LDURDi:
4088 Scale = 8;
4089 return AArch64::LDRDui;
4090 case AArch64::STURDi:
4091 Scale = 8;
4092 return AArch64::STRDui;
4093 case AArch64::LDURXi:
4094 Scale = 8;
4095 return AArch64::LDRXui;
4096 case AArch64::STURXi:
4097 Scale = 8;
4098 return AArch64::STRXui;
4099 case AArch64::LDURWi:
4100 Scale = 4;
4101 return AArch64::LDRWui;
4102 case AArch64::LDURSWi:
4103 Scale = 4;
4104 return AArch64::LDRSWui;
4105 case AArch64::STURWi:
4106 Scale = 4;
4107 return AArch64::STRWui;
4108 case AArch64::LDURHi:
4109 Scale = 2;
4110 return AArch64::LDRHui;
4111 case AArch64::STURHi:
4112 Scale = 2;
4113 return AArch64::STRHui;
4114 case AArch64::LDURHHi:
4115 Scale = 2;
4116 return AArch64::LDRHHui;
4117 case AArch64::STURHHi:
4118 Scale = 2;
4119 return AArch64::STRHHui;
4120 case AArch64::LDURSHXi:
4121 Scale = 2;
4122 return AArch64::LDRSHXui;
4123 case AArch64::LDURSHWi:
4124 Scale = 2;
4125 return AArch64::LDRSHWui;
4126 case AArch64::LDURBi:
4127 Scale = 1;
4128 return AArch64::LDRBui;
4129 case AArch64::LDURBBi:
4130 Scale = 1;
4131 return AArch64::LDRBBui;
4132 case AArch64::LDURSBXi:
4133 Scale = 1;
4134 return AArch64::LDRSBXui;
4135 case AArch64::LDURSBWi:
4136 Scale = 1;
4137 return AArch64::LDRSBWui;
4138 case AArch64::STURBi:
4139 Scale = 1;
4140 return AArch64::STRBui;
4141 case AArch64::STURBBi:
4142 Scale = 1;
4143 return AArch64::STRBBui;
4144 case AArch64::LDRQui:
4145 case AArch64::STRQui:
4146 Scale = 16;
4147 return Opcode;
4148 case AArch64::LDRDui:
4149 case AArch64::STRDui:
4150 case AArch64::LDRXui:
4151 case AArch64::STRXui:
4152 Scale = 8;
4153 return Opcode;
4154 case AArch64::LDRWui:
4155 case AArch64::LDRSWui:
4156 case AArch64::STRWui:
4157 Scale = 4;
4158 return Opcode;
4159 case AArch64::LDRHui:
4160 case AArch64::STRHui:
4161 case AArch64::LDRHHui:
4162 case AArch64::STRHHui:
4163 case AArch64::LDRSHXui:
4164 case AArch64::LDRSHWui:
4165 Scale = 2;
4166 return Opcode;
4167 case AArch64::LDRBui:
4168 case AArch64::LDRBBui:
4169 case AArch64::LDRSBXui:
4170 case AArch64::LDRSBWui:
4171 case AArch64::STRBui:
4172 case AArch64::STRBBui:
4173 Scale = 1;
4174 return Opcode;
4175 }
4176}
4177
4178// Given an opcode for an instruction with a [Reg, #Imm] addressing mode, return
4179// the opcode of an instruction performing the same operation, but using the
4180// [Reg, #Imm] addressing mode with unscaled offset.
4181unsigned unscaledOffsetOpcode(unsigned Opcode) {
4182 switch (Opcode) {
4183 default:
4184 llvm_unreachable("Address folding not implemented for instruction");
4185
4186 case AArch64::LDURQi:
4187 case AArch64::STURQi:
4188 case AArch64::LDURDi:
4189 case AArch64::STURDi:
4190 case AArch64::LDURXi:
4191 case AArch64::STURXi:
4192 case AArch64::LDURWi:
4193 case AArch64::LDURSWi:
4194 case AArch64::STURWi:
4195 case AArch64::LDURHi:
4196 case AArch64::STURHi:
4197 case AArch64::LDURHHi:
4198 case AArch64::STURHHi:
4199 case AArch64::LDURSHXi:
4200 case AArch64::LDURSHWi:
4201 case AArch64::LDURBi:
4202 case AArch64::STURBi:
4203 case AArch64::LDURBBi:
4204 case AArch64::STURBBi:
4205 case AArch64::LDURSBWi:
4206 case AArch64::LDURSBXi:
4207 return Opcode;
4208 case AArch64::LDRQui:
4209 return AArch64::LDURQi;
4210 case AArch64::STRQui:
4211 return AArch64::STURQi;
4212 case AArch64::LDRDui:
4213 return AArch64::LDURDi;
4214 case AArch64::STRDui:
4215 return AArch64::STURDi;
4216 case AArch64::LDRXui:
4217 return AArch64::LDURXi;
4218 case AArch64::STRXui:
4219 return AArch64::STURXi;
4220 case AArch64::LDRWui:
4221 return AArch64::LDURWi;
4222 case AArch64::LDRSWui:
4223 return AArch64::LDURSWi;
4224 case AArch64::STRWui:
4225 return AArch64::STURWi;
4226 case AArch64::LDRHui:
4227 return AArch64::LDURHi;
4228 case AArch64::STRHui:
4229 return AArch64::STURHi;
4230 case AArch64::LDRHHui:
4231 return AArch64::LDURHHi;
4232 case AArch64::STRHHui:
4233 return AArch64::STURHHi;
4234 case AArch64::LDRSHXui:
4235 return AArch64::LDURSHXi;
4236 case AArch64::LDRSHWui:
4237 return AArch64::LDURSHWi;
4238 case AArch64::LDRBBui:
4239 return AArch64::LDURBBi;
4240 case AArch64::LDRBui:
4241 return AArch64::LDURBi;
4242 case AArch64::STRBBui:
4243 return AArch64::STURBBi;
4244 case AArch64::STRBui:
4245 return AArch64::STURBi;
4246 case AArch64::LDRSBWui:
4247 return AArch64::LDURSBWi;
4248 case AArch64::LDRSBXui:
4249 return AArch64::LDURSBXi;
4250 }
4251}
4252
4253// Given the opcode of a memory load/store instruction, return the opcode of an
4254// instruction performing the same operation, but using
4255// the [Reg, Reg, {s,u}xtw #N] addressing mode with sign-/zero-extend of the
4256// offset register.
4257static unsigned offsetExtendOpcode(unsigned Opcode) {
4258 switch (Opcode) {
4259 default:
4260 llvm_unreachable("Address folding not implemented for instruction");
4261
4262 case AArch64::LDRQroX:
4263 case AArch64::LDURQi:
4264 case AArch64::LDRQui:
4265 return AArch64::LDRQroW;
4266 case AArch64::STRQroX:
4267 case AArch64::STURQi:
4268 case AArch64::STRQui:
4269 return AArch64::STRQroW;
4270 case AArch64::LDRDroX:
4271 case AArch64::LDURDi:
4272 case AArch64::LDRDui:
4273 return AArch64::LDRDroW;
4274 case AArch64::STRDroX:
4275 case AArch64::STURDi:
4276 case AArch64::STRDui:
4277 return AArch64::STRDroW;
4278 case AArch64::LDRXroX:
4279 case AArch64::LDURXi:
4280 case AArch64::LDRXui:
4281 return AArch64::LDRXroW;
4282 case AArch64::STRXroX:
4283 case AArch64::STURXi:
4284 case AArch64::STRXui:
4285 return AArch64::STRXroW;
4286 case AArch64::LDRWroX:
4287 case AArch64::LDURWi:
4288 case AArch64::LDRWui:
4289 return AArch64::LDRWroW;
4290 case AArch64::LDRSWroX:
4291 case AArch64::LDURSWi:
4292 case AArch64::LDRSWui:
4293 return AArch64::LDRSWroW;
4294 case AArch64::STRWroX:
4295 case AArch64::STURWi:
4296 case AArch64::STRWui:
4297 return AArch64::STRWroW;
4298 case AArch64::LDRHroX:
4299 case AArch64::LDURHi:
4300 case AArch64::LDRHui:
4301 return AArch64::LDRHroW;
4302 case AArch64::STRHroX:
4303 case AArch64::STURHi:
4304 case AArch64::STRHui:
4305 return AArch64::STRHroW;
4306 case AArch64::LDRHHroX:
4307 case AArch64::LDURHHi:
4308 case AArch64::LDRHHui:
4309 return AArch64::LDRHHroW;
4310 case AArch64::STRHHroX:
4311 case AArch64::STURHHi:
4312 case AArch64::STRHHui:
4313 return AArch64::STRHHroW;
4314 case AArch64::LDRSHXroX:
4315 case AArch64::LDURSHXi:
4316 case AArch64::LDRSHXui:
4317 return AArch64::LDRSHXroW;
4318 case AArch64::LDRSHWroX:
4319 case AArch64::LDURSHWi:
4320 case AArch64::LDRSHWui:
4321 return AArch64::LDRSHWroW;
4322 case AArch64::LDRBroX:
4323 case AArch64::LDURBi:
4324 case AArch64::LDRBui:
4325 return AArch64::LDRBroW;
4326 case AArch64::LDRBBroX:
4327 case AArch64::LDURBBi:
4328 case AArch64::LDRBBui:
4329 return AArch64::LDRBBroW;
4330 case AArch64::LDRSBXroX:
4331 case AArch64::LDURSBXi:
4332 case AArch64::LDRSBXui:
4333 return AArch64::LDRSBXroW;
4334 case AArch64::LDRSBWroX:
4335 case AArch64::LDURSBWi:
4336 case AArch64::LDRSBWui:
4337 return AArch64::LDRSBWroW;
4338 case AArch64::STRBroX:
4339 case AArch64::STURBi:
4340 case AArch64::STRBui:
4341 return AArch64::STRBroW;
4342 case AArch64::STRBBroX:
4343 case AArch64::STURBBi:
4344 case AArch64::STRBBui:
4345 return AArch64::STRBBroW;
4346 }
4347}
4348
4350 const ExtAddrMode &AM) const {
4351
4352 const DebugLoc &DL = MemI.getDebugLoc();
4353 MachineBasicBlock &MBB = *MemI.getParent();
4355
4357 if (AM.ScaledReg) {
4358 // The new instruction will be in the form `ldr Rt, [Xn, Xm, lsl #imm]`.
4359 unsigned Opcode = regOffsetOpcode(MemI.getOpcode());
4360 MRI.constrainRegClass(AM.BaseReg, &AArch64::GPR64spRegClass);
4361 auto B = BuildMI(MBB, MemI, DL, get(Opcode))
4362 .addReg(MemI.getOperand(0).getReg(),
4363 getDefRegState(MemI.mayLoad()))
4364 .addReg(AM.BaseReg)
4365 .addReg(AM.ScaledReg)
4366 .addImm(0)
4367 .addImm(AM.Scale > 1)
4368 .setMemRefs(MemI.memoperands())
4369 .setMIFlags(MemI.getFlags());
4370 return B.getInstr();
4371 }
4372
4373 assert(AM.ScaledReg == 0 && AM.Scale == 0 &&
4374 "Addressing mode not supported for folding");
4375
4376 // The new instruction will be in the form `ld[u]r Rt, [Xn, #imm]`.
4377 unsigned Scale = 1;
4378 unsigned Opcode = MemI.getOpcode();
4379 if (isInt<9>(AM.Displacement))
4380 Opcode = unscaledOffsetOpcode(Opcode);
4381 else
4382 Opcode = scaledOffsetOpcode(Opcode, Scale);
4383
4384 auto B =
4385 BuildMI(MBB, MemI, DL, get(Opcode))
4386 .addReg(MemI.getOperand(0).getReg(), getDefRegState(MemI.mayLoad()))
4387 .addReg(AM.BaseReg)
4388 .addImm(AM.Displacement / Scale)
4389 .setMemRefs(MemI.memoperands())
4390 .setMIFlags(MemI.getFlags());
4391 return B.getInstr();
4392 }
4393
4396 // The new instruction will be in the form `ldr Rt, [Xn, Wm, {s,u}xtw #N]`.
4397 assert(AM.ScaledReg && !AM.Displacement &&
4398 "Address offset can be a register or an immediate, but not both");
4399 unsigned Opcode = offsetExtendOpcode(MemI.getOpcode());
4400 MRI.constrainRegClass(AM.BaseReg, &AArch64::GPR64spRegClass);
4401 // Make sure the offset register is in the correct register class.
4402 Register OffsetReg = AM.ScaledReg;
4403 const TargetRegisterClass *RC = MRI.getRegClass(OffsetReg);
4404 if (RC->hasSuperClassEq(&AArch64::GPR64RegClass)) {
4405 OffsetReg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
4406 BuildMI(MBB, MemI, DL, get(TargetOpcode::COPY), OffsetReg)
4407 .addReg(AM.ScaledReg, {}, AArch64::sub_32);
4408 }
4409 auto B =
4410 BuildMI(MBB, MemI, DL, get(Opcode))
4411 .addReg(MemI.getOperand(0).getReg(), getDefRegState(MemI.mayLoad()))
4412 .addReg(AM.BaseReg)
4413 .addReg(OffsetReg)
4415 .addImm(AM.Scale != 1)
4416 .setMemRefs(MemI.memoperands())
4417 .setMIFlags(MemI.getFlags());
4418
4419 return B.getInstr();
4420 }
4421
4423 "Function must not be called with an addressing mode it can't handle");
4424}
4425
4426/// Return true if the opcode is a post-index ld/st instruction, which really
4427/// loads from base+0.
4428static bool isPostIndexLdStOpcode(unsigned Opcode) {
4429 switch (Opcode) {
4430 default:
4431 return false;
4432 case AArch64::LD1Fourv16b_POST:
4433 case AArch64::LD1Fourv1d_POST:
4434 case AArch64::LD1Fourv2d_POST:
4435 case AArch64::LD1Fourv2s_POST:
4436 case AArch64::LD1Fourv4h_POST:
4437 case AArch64::LD1Fourv4s_POST:
4438 case AArch64::LD1Fourv8b_POST:
4439 case AArch64::LD1Fourv8h_POST:
4440 case AArch64::LD1Onev16b_POST:
4441 case AArch64::LD1Onev1d_POST:
4442 case AArch64::LD1Onev2d_POST:
4443 case AArch64::LD1Onev2s_POST:
4444 case AArch64::LD1Onev4h_POST:
4445 case AArch64::LD1Onev4s_POST:
4446 case AArch64::LD1Onev8b_POST:
4447 case AArch64::LD1Onev8h_POST:
4448 case AArch64::LD1Rv16b_POST:
4449 case AArch64::LD1Rv1d_POST:
4450 case AArch64::LD1Rv2d_POST:
4451 case AArch64::LD1Rv2s_POST:
4452 case AArch64::LD1Rv4h_POST:
4453 case AArch64::LD1Rv4s_POST:
4454 case AArch64::LD1Rv8b_POST:
4455 case AArch64::LD1Rv8h_POST:
4456 case AArch64::LD1Threev16b_POST:
4457 case AArch64::LD1Threev1d_POST:
4458 case AArch64::LD1Threev2d_POST:
4459 case AArch64::LD1Threev2s_POST:
4460 case AArch64::LD1Threev4h_POST:
4461 case AArch64::LD1Threev4s_POST:
4462 case AArch64::LD1Threev8b_POST:
4463 case AArch64::LD1Threev8h_POST:
4464 case AArch64::LD1Twov16b_POST:
4465 case AArch64::LD1Twov1d_POST:
4466 case AArch64::LD1Twov2d_POST:
4467 case AArch64::LD1Twov2s_POST:
4468 case AArch64::LD1Twov4h_POST:
4469 case AArch64::LD1Twov4s_POST:
4470 case AArch64::LD1Twov8b_POST:
4471 case AArch64::LD1Twov8h_POST:
4472 case AArch64::LD1i16_POST:
4473 case AArch64::LD1i32_POST:
4474 case AArch64::LD1i64_POST:
4475 case AArch64::LD1i8_POST:
4476 case AArch64::LD2Rv16b_POST:
4477 case AArch64::LD2Rv1d_POST:
4478 case AArch64::LD2Rv2d_POST:
4479 case AArch64::LD2Rv2s_POST:
4480 case AArch64::LD2Rv4h_POST:
4481 case AArch64::LD2Rv4s_POST:
4482 case AArch64::LD2Rv8b_POST:
4483 case AArch64::LD2Rv8h_POST:
4484 case AArch64::LD2Twov16b_POST:
4485 case AArch64::LD2Twov2d_POST:
4486 case AArch64::LD2Twov2s_POST:
4487 case AArch64::LD2Twov4h_POST:
4488 case AArch64::LD2Twov4s_POST:
4489 case AArch64::LD2Twov8b_POST:
4490 case AArch64::LD2Twov8h_POST:
4491 case AArch64::LD2i16_POST:
4492 case AArch64::LD2i32_POST:
4493 case AArch64::LD2i64_POST:
4494 case AArch64::LD2i8_POST:
4495 case AArch64::LD3Rv16b_POST:
4496 case AArch64::LD3Rv1d_POST:
4497 case AArch64::LD3Rv2d_POST:
4498 case AArch64::LD3Rv2s_POST:
4499 case AArch64::LD3Rv4h_POST:
4500 case AArch64::LD3Rv4s_POST:
4501 case AArch64::LD3Rv8b_POST:
4502 case AArch64::LD3Rv8h_POST:
4503 case AArch64::LD3Threev16b_POST:
4504 case AArch64::LD3Threev2d_POST:
4505 case AArch64::LD3Threev2s_POST:
4506 case AArch64::LD3Threev4h_POST:
4507 case AArch64::LD3Threev4s_POST:
4508 case AArch64::LD3Threev8b_POST:
4509 case AArch64::LD3Threev8h_POST:
4510 case AArch64::LD3i16_POST:
4511 case AArch64::LD3i32_POST:
4512 case AArch64::LD3i64_POST:
4513 case AArch64::LD3i8_POST:
4514 case AArch64::LD4Fourv16b_POST:
4515 case AArch64::LD4Fourv2d_POST:
4516 case AArch64::LD4Fourv2s_POST:
4517 case AArch64::LD4Fourv4h_POST:
4518 case AArch64::LD4Fourv4s_POST:
4519 case AArch64::LD4Fourv8b_POST:
4520 case AArch64::LD4Fourv8h_POST:
4521 case AArch64::LD4Rv16b_POST:
4522 case AArch64::LD4Rv1d_POST:
4523 case AArch64::LD4Rv2d_POST:
4524 case AArch64::LD4Rv2s_POST:
4525 case AArch64::LD4Rv4h_POST:
4526 case AArch64::LD4Rv4s_POST:
4527 case AArch64::LD4Rv8b_POST:
4528 case AArch64::LD4Rv8h_POST:
4529 case AArch64::LD4i16_POST:
4530 case AArch64::LD4i32_POST:
4531 case AArch64::LD4i64_POST:
4532 case AArch64::LD4i8_POST:
4533 case AArch64::LDAPRWpost:
4534 case AArch64::LDAPRXpost:
4535 case AArch64::LDIAPPWpost:
4536 case AArch64::LDIAPPXpost:
4537 case AArch64::LDPDpost:
4538 case AArch64::LDPQpost:
4539 case AArch64::LDPSWpost:
4540 case AArch64::LDPSpost:
4541 case AArch64::LDPWpost:
4542 case AArch64::LDPXpost:
4543 case AArch64::LDRBBpost:
4544 case AArch64::LDRBpost:
4545 case AArch64::LDRDpost:
4546 case AArch64::LDRHHpost:
4547 case AArch64::LDRHpost:
4548 case AArch64::LDRQpost:
4549 case AArch64::LDRSBWpost:
4550 case AArch64::LDRSBXpost:
4551 case AArch64::LDRSHWpost:
4552 case AArch64::LDRSHXpost:
4553 case AArch64::LDRSWpost:
4554 case AArch64::LDRSpost:
4555 case AArch64::LDRWpost:
4556 case AArch64::LDRXpost:
4557 case AArch64::ST1Fourv16b_POST:
4558 case AArch64::ST1Fourv1d_POST:
4559 case AArch64::ST1Fourv2d_POST:
4560 case AArch64::ST1Fourv2s_POST:
4561 case AArch64::ST1Fourv4h_POST:
4562 case AArch64::ST1Fourv4s_POST:
4563 case AArch64::ST1Fourv8b_POST:
4564 case AArch64::ST1Fourv8h_POST:
4565 case AArch64::ST1Onev16b_POST:
4566 case AArch64::ST1Onev1d_POST:
4567 case AArch64::ST1Onev2d_POST:
4568 case AArch64::ST1Onev2s_POST:
4569 case AArch64::ST1Onev4h_POST:
4570 case AArch64::ST1Onev4s_POST:
4571 case AArch64::ST1Onev8b_POST:
4572 case AArch64::ST1Onev8h_POST:
4573 case AArch64::ST1Threev16b_POST:
4574 case AArch64::ST1Threev1d_POST:
4575 case AArch64::ST1Threev2d_POST:
4576 case AArch64::ST1Threev2s_POST:
4577 case AArch64::ST1Threev4h_POST:
4578 case AArch64::ST1Threev4s_POST:
4579 case AArch64::ST1Threev8b_POST:
4580 case AArch64::ST1Threev8h_POST:
4581 case AArch64::ST1Twov16b_POST:
4582 case AArch64::ST1Twov1d_POST:
4583 case AArch64::ST1Twov2d_POST:
4584 case AArch64::ST1Twov2s_POST:
4585 case AArch64::ST1Twov4h_POST:
4586 case AArch64::ST1Twov4s_POST:
4587 case AArch64::ST1Twov8b_POST:
4588 case AArch64::ST1Twov8h_POST:
4589 case AArch64::ST1i16_POST:
4590 case AArch64::ST1i32_POST:
4591 case AArch64::ST1i64_POST:
4592 case AArch64::ST1i8_POST:
4593 case AArch64::ST2GPostIndex:
4594 case AArch64::ST2Twov16b_POST:
4595 case AArch64::ST2Twov2d_POST:
4596 case AArch64::ST2Twov2s_POST:
4597 case AArch64::ST2Twov4h_POST:
4598 case AArch64::ST2Twov4s_POST:
4599 case AArch64::ST2Twov8b_POST:
4600 case AArch64::ST2Twov8h_POST:
4601 case AArch64::ST2i16_POST:
4602 case AArch64::ST2i32_POST:
4603 case AArch64::ST2i64_POST:
4604 case AArch64::ST2i8_POST:
4605 case AArch64::ST3Threev16b_POST:
4606 case AArch64::ST3Threev2d_POST:
4607 case AArch64::ST3Threev2s_POST:
4608 case AArch64::ST3Threev4h_POST:
4609 case AArch64::ST3Threev4s_POST:
4610 case AArch64::ST3Threev8b_POST:
4611 case AArch64::ST3Threev8h_POST:
4612 case AArch64::ST3i16_POST:
4613 case AArch64::ST3i32_POST:
4614 case AArch64::ST3i64_POST:
4615 case AArch64::ST3i8_POST:
4616 case AArch64::ST4Fourv16b_POST:
4617 case AArch64::ST4Fourv2d_POST:
4618 case AArch64::ST4Fourv2s_POST:
4619 case AArch64::ST4Fourv4h_POST:
4620 case AArch64::ST4Fourv4s_POST:
4621 case AArch64::ST4Fourv8b_POST:
4622 case AArch64::ST4Fourv8h_POST:
4623 case AArch64::ST4i16_POST:
4624 case AArch64::ST4i32_POST:
4625 case AArch64::ST4i64_POST:
4626 case AArch64::ST4i8_POST:
4627 case AArch64::STGPostIndex:
4628 case AArch64::STGPpost:
4629 case AArch64::STPDpost:
4630 case AArch64::STPQpost:
4631 case AArch64::STPSpost:
4632 case AArch64::STPWpost:
4633 case AArch64::STPXpost:
4634 case AArch64::STRBBpost:
4635 case AArch64::STRBpost:
4636 case AArch64::STRDpost:
4637 case AArch64::STRHHpost:
4638 case AArch64::STRHpost:
4639 case AArch64::STRQpost:
4640 case AArch64::STRSpost:
4641 case AArch64::STRWpost:
4642 case AArch64::STRXpost:
4643 case AArch64::STZ2GPostIndex:
4644 case AArch64::STZGPostIndex:
4645 return true;
4646 }
4647}
4648
4650 const MachineInstr &LdSt, const MachineOperand *&BaseOp, int64_t &Offset,
4651 bool &OffsetIsScalable, TypeSize &Width) const {
4652 assert(LdSt.mayLoadOrStore() && "Expected a memory operation.");
4653 // Handle only loads/stores with base register followed by immediate offset.
4654 if (LdSt.getNumExplicitOperands() == 3) {
4655 // Non-paired instruction (e.g., ldr x1, [x0, #8]).
4656 if ((!LdSt.getOperand(1).isReg() && !LdSt.getOperand(1).isFI()) ||
4657 !LdSt.getOperand(2).isImm())
4658 return false;
4659 } else if (LdSt.getNumExplicitOperands() == 4) {
4660 // Paired instruction (e.g., ldp x1, x2, [x0, #8]).
4661 if (!LdSt.getOperand(1).isReg() ||
4662 (!LdSt.getOperand(2).isReg() && !LdSt.getOperand(2).isFI()) ||
4663 !LdSt.getOperand(3).isImm())
4664 return false;
4665 } else
4666 return false;
4667
4668 // Get the scaling factor for the instruction and set the width for the
4669 // instruction.
4670 TypeSize Scale(0U, false);
4671 int64_t Dummy1, Dummy2;
4672
4673 // If this returns false, then it's an instruction we don't want to handle.
4674 if (!getMemOpInfo(LdSt.getOpcode(), Scale, Width, Dummy1, Dummy2))
4675 return false;
4676
4677 // Compute the offset. Offset is calculated as the immediate operand
4678 // multiplied by the scaling factor. Unscaled instructions have scaling factor
4679 // set to 1. Postindex are a special case which have an offset of 0.
4680 if (isPostIndexLdStOpcode(LdSt.getOpcode())) {
4681 BaseOp = &LdSt.getOperand(2);
4682 Offset = 0;
4683 } else if (LdSt.getNumExplicitOperands() == 3) {
4684 BaseOp = &LdSt.getOperand(1);
4685 Offset = LdSt.getOperand(2).getImm() * Scale.getKnownMinValue();
4686 } else {
4687 assert(LdSt.getNumExplicitOperands() == 4 && "invalid number of operands");
4688 BaseOp = &LdSt.getOperand(2);
4689 Offset = LdSt.getOperand(3).getImm() * Scale.getKnownMinValue();
4690 }
4691 OffsetIsScalable = Scale.isScalable();
4692
4693 return BaseOp->isReg() || BaseOp->isFI();
4694}
4695
4698 assert(LdSt.mayLoadOrStore() && "Expected a memory operation.");
4699 MachineOperand &OfsOp = LdSt.getOperand(LdSt.getNumExplicitOperands() - 1);
4700 assert(OfsOp.isImm() && "Offset operand wasn't immediate.");
4701 return OfsOp;
4702}
4703
4704bool AArch64InstrInfo::getMemOpInfo(unsigned Opcode, TypeSize &Scale,
4705 TypeSize &Width, int64_t &MinOffset,
4706 int64_t &MaxOffset) {
4707 switch (Opcode) {
4708 // Not a memory operation or something we want to handle.
4709 default:
4710 Scale = Width = TypeSize::getFixed(0);
4711 MinOffset = MaxOffset = 0;
4712 return false;
4713 // LDR / STR
4714 case AArch64::LDRQui:
4715 case AArch64::STRQui:
4716 Scale = Width = TypeSize::getFixed(16);
4717 MinOffset = 0;
4718 MaxOffset = 4095;
4719 break;
4720 case AArch64::LDRXui:
4721 case AArch64::LDRDui:
4722 case AArch64::STRXui:
4723 case AArch64::STRDui:
4724 case AArch64::PRFMui:
4725 case AArch64::ATOMIC_STORE_HINT_Xui:
4726 case AArch64::ATOMIC_STORE_HINT_Dui:
4727 Scale = Width = TypeSize::getFixed(8);
4728 MinOffset = 0;
4729 MaxOffset = 4095;
4730 break;
4731 case AArch64::LDRWui:
4732 case AArch64::LDRSui:
4733 case AArch64::LDRSWui:
4734 case AArch64::STRWui:
4735 case AArch64::STRSui:
4736 case AArch64::ATOMIC_STORE_HINT_Wui:
4737 case AArch64::ATOMIC_STORE_HINT_Sui:
4738 Scale = Width = TypeSize::getFixed(4);
4739 MinOffset = 0;
4740 MaxOffset = 4095;
4741 break;
4742 case AArch64::LDRHui:
4743 case AArch64::LDRHHui:
4744 case AArch64::LDRSHWui:
4745 case AArch64::LDRSHXui:
4746 case AArch64::STRHui:
4747 case AArch64::STRHHui:
4748 case AArch64::ATOMIC_STORE_HINT_Hui:
4749 Scale = Width = TypeSize::getFixed(2);
4750 MinOffset = 0;
4751 MaxOffset = 4095;
4752 break;
4753 case AArch64::LDRBui:
4754 case AArch64::LDRBBui:
4755 case AArch64::LDRSBWui:
4756 case AArch64::LDRSBXui:
4757 case AArch64::STRBui:
4758 case AArch64::STRBBui:
4759 case AArch64::ATOMIC_STORE_HINT_Bui:
4760 Scale = Width = TypeSize::getFixed(1);
4761 MinOffset = 0;
4762 MaxOffset = 4095;
4763 break;
4764 // post/pre inc
4765 case AArch64::STRQpre:
4766 case AArch64::LDRQpost:
4767 Scale = TypeSize::getFixed(1);
4768 Width = TypeSize::getFixed(16);
4769 MinOffset = -256;
4770 MaxOffset = 255;
4771 break;
4772 case AArch64::LDRDpost:
4773 case AArch64::LDRDpre:
4774 case AArch64::LDRXpost:
4775 case AArch64::LDRXpre:
4776 case AArch64::STRDpost:
4777 case AArch64::STRDpre:
4778 case AArch64::STRXpost:
4779 case AArch64::STRXpre:
4780 Scale = TypeSize::getFixed(1);
4781 Width = TypeSize::getFixed(8);
4782 MinOffset = -256;
4783 MaxOffset = 255;
4784 break;
4785 case AArch64::STRWpost:
4786 case AArch64::STRWpre:
4787 case AArch64::LDRWpost:
4788 case AArch64::LDRWpre:
4789 case AArch64::STRSpost:
4790 case AArch64::STRSpre:
4791 case AArch64::LDRSpost:
4792 case AArch64::LDRSpre:
4793 Scale = TypeSize::getFixed(1);
4794 Width = TypeSize::getFixed(4);
4795 MinOffset = -256;
4796 MaxOffset = 255;
4797 break;
4798 case AArch64::LDRHpost:
4799 case AArch64::LDRHpre:
4800 case AArch64::STRHpost:
4801 case AArch64::STRHpre:
4802 case AArch64::LDRHHpost:
4803 case AArch64::LDRHHpre:
4804 case AArch64::STRHHpost:
4805 case AArch64::STRHHpre:
4806 Scale = TypeSize::getFixed(1);
4807 Width = TypeSize::getFixed(2);
4808 MinOffset = -256;
4809 MaxOffset = 255;
4810 break;
4811 case AArch64::LDRBpost:
4812 case AArch64::LDRBpre:
4813 case AArch64::STRBpost:
4814 case AArch64::STRBpre:
4815 case AArch64::LDRBBpost:
4816 case AArch64::LDRBBpre:
4817 case AArch64::STRBBpost:
4818 case AArch64::STRBBpre:
4819 Scale = Width = TypeSize::getFixed(1);
4820 MinOffset = -256;
4821 MaxOffset = 255;
4822 break;
4823 // Unscaled
4824 case AArch64::LDURQi:
4825 case AArch64::STURQi:
4826 Scale = TypeSize::getFixed(1);
4827 Width = TypeSize::getFixed(16);
4828 MinOffset = -256;
4829 MaxOffset = 255;
4830 break;
4831 case AArch64::LDURXi:
4832 case AArch64::LDURDi:
4833 case AArch64::LDAPURXi:
4834 case AArch64::STURXi:
4835 case AArch64::STURDi:
4836 case AArch64::STLURXi:
4837 case AArch64::PRFUMi:
4838 case AArch64::ATOMIC_STORE_HINT_Xi:
4839 case AArch64::ATOMIC_STORE_HINT_Di:
4840 Scale = TypeSize::getFixed(1);
4841 Width = TypeSize::getFixed(8);
4842 MinOffset = -256;
4843 MaxOffset = 255;
4844 break;
4845 case AArch64::LDURWi:
4846 case AArch64::LDURSi:
4847 case AArch64::LDURSWi:
4848 case AArch64::LDAPURi:
4849 case AArch64::LDAPURSWi:
4850 case AArch64::STURWi:
4851 case AArch64::STURSi:
4852 case AArch64::STLURWi:
4853 case AArch64::ATOMIC_STORE_HINT_Wi:
4854 case AArch64::ATOMIC_STORE_HINT_Si:
4855 Scale = TypeSize::getFixed(1);
4856 Width = TypeSize::getFixed(4);
4857 MinOffset = -256;
4858 MaxOffset = 255;
4859 break;
4860 case AArch64::LDURHi:
4861 case AArch64::LDURHHi:
4862 case AArch64::LDURSHXi:
4863 case AArch64::LDURSHWi:
4864 case AArch64::LDAPURHi:
4865 case AArch64::LDAPURSHWi:
4866 case AArch64::LDAPURSHXi:
4867 case AArch64::STURHi:
4868 case AArch64::STURHHi:
4869 case AArch64::STLURHi:
4870 case AArch64::ATOMIC_STORE_HINT_Hi:
4871 Scale = TypeSize::getFixed(1);
4872 Width = TypeSize::getFixed(2);
4873 MinOffset = -256;
4874 MaxOffset = 255;
4875 break;
4876 case AArch64::LDURBi:
4877 case AArch64::LDURBBi:
4878 case AArch64::LDURSBXi:
4879 case AArch64::LDURSBWi:
4880 case AArch64::LDAPURBi:
4881 case AArch64::LDAPURSBWi:
4882 case AArch64::LDAPURSBXi:
4883 case AArch64::STURBi:
4884 case AArch64::STURBBi:
4885 case AArch64::STLURBi:
4886 case AArch64::ATOMIC_STORE_HINT_Bi:
4887 Scale = Width = TypeSize::getFixed(1);
4888 MinOffset = -256;
4889 MaxOffset = 255;
4890 break;
4891 // LDP / STP (including pre/post inc)
4892 case AArch64::LDPQi:
4893 case AArch64::LDNPQi:
4894 case AArch64::STPQi:
4895 case AArch64::STNPQi:
4896 case AArch64::LDPQpost:
4897 case AArch64::LDPQpre:
4898 case AArch64::STPQpost:
4899 case AArch64::STPQpre:
4900 Scale = TypeSize::getFixed(16);
4901 Width = TypeSize::getFixed(16 * 2);
4902 MinOffset = -64;
4903 MaxOffset = 63;
4904 break;
4905 case AArch64::LDPXi:
4906 case AArch64::LDPDi:
4907 case AArch64::LDNPXi:
4908 case AArch64::LDNPDi:
4909 case AArch64::STPXi:
4910 case AArch64::STPDi:
4911 case AArch64::STNPXi:
4912 case AArch64::STNPDi:
4913 case AArch64::LDPDpost:
4914 case AArch64::LDPDpre:
4915 case AArch64::LDPXpost:
4916 case AArch64::LDPXpre:
4917 case AArch64::STPDpost:
4918 case AArch64::STPDpre:
4919 case AArch64::STPXpost:
4920 case AArch64::STPXpre:
4921 Scale = TypeSize::getFixed(8);
4922 Width = TypeSize::getFixed(8 * 2);
4923 MinOffset = -64;
4924 MaxOffset = 63;
4925 break;
4926 case AArch64::LDPWi:
4927 case AArch64::LDPSi:
4928 case AArch64::LDNPWi:
4929 case AArch64::LDNPSi:
4930 case AArch64::STPWi:
4931 case AArch64::STPSi:
4932 case AArch64::STNPWi:
4933 case AArch64::STNPSi:
4934 case AArch64::LDPSpost:
4935 case AArch64::LDPSpre:
4936 case AArch64::LDPWpost:
4937 case AArch64::LDPWpre:
4938 case AArch64::STPSpost:
4939 case AArch64::STPSpre:
4940 case AArch64::STPWpost:
4941 case AArch64::STPWpre:
4942 Scale = TypeSize::getFixed(4);
4943 Width = TypeSize::getFixed(4 * 2);
4944 MinOffset = -64;
4945 MaxOffset = 63;
4946 break;
4947 case AArch64::StoreSwiftAsyncContext:
4948 // Store is an STRXui, but there might be an ADDXri in the expansion too.
4949 Scale = TypeSize::getFixed(1);
4950 Width = TypeSize::getFixed(8);
4951 MinOffset = 0;
4952 MaxOffset = 4095;
4953 break;
4954 case AArch64::ADDG:
4955 Scale = TypeSize::getFixed(16);
4956 Width = TypeSize::getFixed(0);
4957 MinOffset = 0;
4958 MaxOffset = 63;
4959 break;
4960 case AArch64::TAGPstack:
4961 Scale = TypeSize::getFixed(16);
4962 Width = TypeSize::getFixed(0);
4963 // TAGP with a negative offset turns into SUBP, which has a maximum offset
4964 // of 63 (not 64!).
4965 MinOffset = -63;
4966 MaxOffset = 63;
4967 break;
4968 case AArch64::LDG:
4969 case AArch64::STGi:
4970 case AArch64::STGPreIndex:
4971 case AArch64::STGPostIndex:
4972 case AArch64::STZGi:
4973 case AArch64::STZGPreIndex:
4974 case AArch64::STZGPostIndex:
4975 Scale = Width = TypeSize::getFixed(16);
4976 MinOffset = -256;
4977 MaxOffset = 255;
4978 break;
4979 // SVE
4980 case AArch64::STR_ZZZZXI:
4981 case AArch64::STR_ZZZZXI_STRIDED_CONTIGUOUS:
4982 case AArch64::LDR_ZZZZXI:
4983 case AArch64::LDR_ZZZZXI_STRIDED_CONTIGUOUS:
4984 Scale = TypeSize::getScalable(16);
4985 Width = TypeSize::getScalable(16 * 4);
4986 MinOffset = -256;
4987 MaxOffset = 252;
4988 break;
4989 case AArch64::STR_ZZZXI:
4990 case AArch64::LDR_ZZZXI:
4991 Scale = TypeSize::getScalable(16);
4992 Width = TypeSize::getScalable(16 * 3);
4993 MinOffset = -256;
4994 MaxOffset = 253;
4995 break;
4996 case AArch64::STR_ZZXI:
4997 case AArch64::STR_ZZXI_STRIDED_CONTIGUOUS:
4998 case AArch64::LDR_ZZXI:
4999 case AArch64::LDR_ZZXI_STRIDED_CONTIGUOUS:
5000 Scale = TypeSize::getScalable(16);
5001 Width = TypeSize::getScalable(16 * 2);
5002 MinOffset = -256;
5003 MaxOffset = 254;
5004 break;
5005 case AArch64::LDR_PXI:
5006 case AArch64::STR_PXI:
5007 Scale = Width = TypeSize::getScalable(2);
5008 MinOffset = -256;
5009 MaxOffset = 255;
5010 break;
5011 case AArch64::LDR_PPXI:
5012 case AArch64::STR_PPXI:
5013 Scale = TypeSize::getScalable(2);
5014 Width = TypeSize::getScalable(2 * 2);
5015 MinOffset = -256;
5016 MaxOffset = 254;
5017 break;
5018 case AArch64::LDR_ZXI:
5019 case AArch64::STR_ZXI:
5020 Scale = Width = TypeSize::getScalable(16);
5021 MinOffset = -256;
5022 MaxOffset = 255;
5023 break;
5024 case AArch64::LD1B_IMM:
5025 case AArch64::LD1H_IMM:
5026 case AArch64::LD1W_IMM:
5027 case AArch64::LD1D_IMM:
5028 case AArch64::LDNT1B_ZRI:
5029 case AArch64::LDNT1H_ZRI:
5030 case AArch64::LDNT1W_ZRI:
5031 case AArch64::LDNT1D_ZRI:
5032 case AArch64::ST1B_IMM:
5033 case AArch64::ST1H_IMM:
5034 case AArch64::ST1W_IMM:
5035 case AArch64::ST1D_IMM:
5036 case AArch64::STNT1B_ZRI:
5037 case AArch64::STNT1H_ZRI:
5038 case AArch64::STNT1W_ZRI:
5039 case AArch64::STNT1D_ZRI:
5040 case AArch64::LDNF1B_IMM:
5041 case AArch64::LDNF1H_IMM:
5042 case AArch64::LDNF1W_IMM:
5043 case AArch64::LDNF1D_IMM:
5044 // A full vectors worth of data
5045 // Width = mbytes * elements
5046 Scale = Width = TypeSize::getScalable(16);
5047 MinOffset = -8;
5048 MaxOffset = 7;
5049 break;
5050 case AArch64::LD2B_IMM:
5051 case AArch64::LD2H_IMM:
5052 case AArch64::LD2W_IMM:
5053 case AArch64::LD2D_IMM:
5054 case AArch64::ST2B_IMM:
5055 case AArch64::ST2H_IMM:
5056 case AArch64::ST2W_IMM:
5057 case AArch64::ST2D_IMM:
5058 case AArch64::LD1B_2Z_IMM:
5059 case AArch64::LD1B_2Z_STRIDED_IMM:
5060 case AArch64::LD1H_2Z_IMM:
5061 case AArch64::LD1H_2Z_STRIDED_IMM:
5062 case AArch64::LD1W_2Z_IMM:
5063 case AArch64::LD1W_2Z_STRIDED_IMM:
5064 case AArch64::LD1D_2Z_IMM:
5065 case AArch64::LD1D_2Z_STRIDED_IMM:
5066 case AArch64::LD1B_2Z_IMM_PSEUDO:
5067 case AArch64::LD1H_2Z_IMM_PSEUDO:
5068 case AArch64::LD1W_2Z_IMM_PSEUDO:
5069 case AArch64::LD1D_2Z_IMM_PSEUDO:
5070 case AArch64::ST1B_2Z_IMM:
5071 case AArch64::ST1B_2Z_STRIDED_IMM:
5072 case AArch64::ST1H_2Z_IMM:
5073 case AArch64::ST1H_2Z_STRIDED_IMM:
5074 case AArch64::ST1W_2Z_IMM:
5075 case AArch64::ST1W_2Z_STRIDED_IMM:
5076 case AArch64::ST1D_2Z_IMM:
5077 case AArch64::ST1D_2Z_STRIDED_IMM:
5078 case AArch64::LDNT1B_2Z_IMM_PSEUDO:
5079 case AArch64::LDNT1B_2Z_IMM:
5080 case AArch64::LDNT1B_2Z_STRIDED_IMM:
5081 case AArch64::LDNT1H_2Z_IMM_PSEUDO:
5082 case AArch64::LDNT1H_2Z_IMM:
5083 case AArch64::LDNT1H_2Z_STRIDED_IMM:
5084 case AArch64::LDNT1W_2Z_IMM_PSEUDO:
5085 case AArch64::LDNT1W_2Z_IMM:
5086 case AArch64::LDNT1W_2Z_STRIDED_IMM:
5087 case AArch64::LDNT1D_2Z_IMM_PSEUDO:
5088 case AArch64::LDNT1D_2Z_IMM:
5089 case AArch64::LDNT1D_2Z_STRIDED_IMM:
5090 case AArch64::STNT1B_2Z_IMM:
5091 case AArch64::STNT1B_2Z_STRIDED_IMM:
5092 case AArch64::STNT1H_2Z_IMM:
5093 case AArch64::STNT1H_2Z_STRIDED_IMM:
5094 case AArch64::STNT1W_2Z_IMM:
5095 case AArch64::STNT1W_2Z_STRIDED_IMM:
5096 case AArch64::STNT1D_2Z_IMM:
5097 case AArch64::STNT1D_2Z_STRIDED_IMM:
5098 case AArch64::ST1B_2Z_IMM_PSEUDO:
5099 case AArch64::ST1H_2Z_IMM_PSEUDO:
5100 case AArch64::ST1W_2Z_IMM_PSEUDO:
5101 case AArch64::ST1D_2Z_IMM_PSEUDO:
5102 case AArch64::STNT1B_2Z_IMM_PSEUDO:
5103 case AArch64::STNT1H_2Z_IMM_PSEUDO:
5104 case AArch64::STNT1W_2Z_IMM_PSEUDO:
5105 case AArch64::STNT1D_2Z_IMM_PSEUDO:
5106 Scale = Width = TypeSize::getScalable(16 * 2);
5107 MinOffset = -8;
5108 MaxOffset = 7;
5109 break;
5110 case AArch64::LD3B_IMM:
5111 case AArch64::LD3H_IMM:
5112 case AArch64::LD3W_IMM:
5113 case AArch64::LD3D_IMM:
5114 case AArch64::ST3B_IMM:
5115 case AArch64::ST3H_IMM:
5116 case AArch64::ST3W_IMM:
5117 case AArch64::ST3D_IMM:
5118 Scale = Width = TypeSize::getScalable(16 * 3);
5119 MinOffset = -8;
5120 MaxOffset = 7;
5121 break;
5122 case AArch64::LD4B_IMM:
5123 case AArch64::LD4H_IMM:
5124 case AArch64::LD4W_IMM:
5125 case AArch64::LD4D_IMM:
5126 case AArch64::ST4B_IMM:
5127 case AArch64::ST4H_IMM:
5128 case AArch64::ST4W_IMM:
5129 case AArch64::ST4D_IMM:
5130 case AArch64::LD1B_4Z_IMM:
5131 case AArch64::LD1B_4Z_STRIDED_IMM:
5132 case AArch64::LD1H_4Z_IMM:
5133 case AArch64::LD1H_4Z_STRIDED_IMM:
5134 case AArch64::LD1W_4Z_IMM:
5135 case AArch64::LD1W_4Z_STRIDED_IMM:
5136 case AArch64::LD1D_4Z_IMM:
5137 case AArch64::LD1D_4Z_STRIDED_IMM:
5138 case AArch64::LD1B_4Z_IMM_PSEUDO:
5139 case AArch64::LD1H_4Z_IMM_PSEUDO:
5140 case AArch64::LD1W_4Z_IMM_PSEUDO:
5141 case AArch64::LD1D_4Z_IMM_PSEUDO:
5142 case AArch64::ST1B_4Z_IMM:
5143 case AArch64::ST1B_4Z_STRIDED_IMM:
5144 case AArch64::ST1H_4Z_IMM:
5145 case AArch64::ST1H_4Z_STRIDED_IMM:
5146 case AArch64::ST1W_4Z_IMM:
5147 case AArch64::ST1W_4Z_STRIDED_IMM:
5148 case AArch64::ST1D_4Z_IMM:
5149 case AArch64::ST1D_4Z_STRIDED_IMM:
5150 case AArch64::LDNT1B_4Z_IMM_PSEUDO:
5151 case AArch64::LDNT1B_4Z_IMM:
5152 case AArch64::LDNT1B_4Z_STRIDED_IMM:
5153 case AArch64::LDNT1H_4Z_IMM_PSEUDO:
5154 case AArch64::LDNT1H_4Z_IMM:
5155 case AArch64::LDNT1H_4Z_STRIDED_IMM:
5156 case AArch64::LDNT1W_4Z_IMM_PSEUDO:
5157 case AArch64::LDNT1W_4Z_IMM:
5158 case AArch64::LDNT1W_4Z_STRIDED_IMM:
5159 case AArch64::LDNT1D_4Z_IMM_PSEUDO:
5160 case AArch64::LDNT1D_4Z_IMM:
5161 case AArch64::LDNT1D_4Z_STRIDED_IMM:
5162 case AArch64::STNT1B_4Z_IMM:
5163 case AArch64::STNT1B_4Z_STRIDED_IMM:
5164 case AArch64::STNT1H_4Z_IMM:
5165 case AArch64::STNT1H_4Z_STRIDED_IMM:
5166 case AArch64::STNT1W_4Z_IMM:
5167 case AArch64::STNT1W_4Z_STRIDED_IMM:
5168 case AArch64::STNT1D_4Z_IMM:
5169 case AArch64::STNT1D_4Z_STRIDED_IMM:
5170 case AArch64::ST1B_4Z_IMM_PSEUDO:
5171 case AArch64::ST1H_4Z_IMM_PSEUDO:
5172 case AArch64::ST1W_4Z_IMM_PSEUDO:
5173 case AArch64::ST1D_4Z_IMM_PSEUDO:
5174 case AArch64::STNT1B_4Z_IMM_PSEUDO:
5175 case AArch64::STNT1H_4Z_IMM_PSEUDO:
5176 case AArch64::STNT1W_4Z_IMM_PSEUDO:
5177 case AArch64::STNT1D_4Z_IMM_PSEUDO:
5178 Scale = Width = TypeSize::getScalable(16 * 4);
5179 MinOffset = -8;
5180 MaxOffset = 7;
5181 break;
5182 case AArch64::LD1B_H_IMM:
5183 case AArch64::LD1SB_H_IMM:
5184 case AArch64::LD1H_S_IMM:
5185 case AArch64::LD1SH_S_IMM:
5186 case AArch64::LD1W_D_IMM:
5187 case AArch64::LD1SW_D_IMM:
5188 case AArch64::ST1B_H_IMM:
5189 case AArch64::ST1H_S_IMM:
5190 case AArch64::ST1W_D_IMM:
5191 case AArch64::LDNF1B_H_IMM:
5192 case AArch64::LDNF1SB_H_IMM:
5193 case AArch64::LDNF1H_S_IMM:
5194 case AArch64::LDNF1SH_S_IMM:
5195 case AArch64::LDNF1W_D_IMM:
5196 case AArch64::LDNF1SW_D_IMM:
5197 // A half vector worth of data
5198 // Width = mbytes * elements
5199 Scale = Width = TypeSize::getScalable(8);
5200 MinOffset = -8;
5201 MaxOffset = 7;
5202 break;
5203 case AArch64::LD1B_S_IMM:
5204 case AArch64::LD1SB_S_IMM:
5205 case AArch64::LD1H_D_IMM:
5206 case AArch64::LD1SH_D_IMM:
5207 case AArch64::ST1B_S_IMM:
5208 case AArch64::ST1H_D_IMM:
5209 case AArch64::LDNF1B_S_IMM:
5210 case AArch64::LDNF1SB_S_IMM:
5211 case AArch64::LDNF1H_D_IMM:
5212 case AArch64::LDNF1SH_D_IMM:
5213 // A quarter vector worth of data
5214 // Width = mbytes * elements
5215 Scale = Width = TypeSize::getScalable(4);
5216 MinOffset = -8;
5217 MaxOffset = 7;
5218 break;
5219 case AArch64::LD1B_D_IMM:
5220 case AArch64::LD1SB_D_IMM:
5221 case AArch64::ST1B_D_IMM:
5222 case AArch64::LDNF1B_D_IMM:
5223 case AArch64::LDNF1SB_D_IMM:
5224 // A eighth vector worth of data
5225 // Width = mbytes * elements
5226 Scale = Width = TypeSize::getScalable(2);
5227 MinOffset = -8;
5228 MaxOffset = 7;
5229 break;
5230 case AArch64::ST2Gi:
5231 case AArch64::ST2GPreIndex:
5232 case AArch64::ST2GPostIndex:
5233 case AArch64::STZ2Gi:
5234 case AArch64::STZ2GPreIndex:
5235 case AArch64::STZ2GPostIndex:
5236 Scale = TypeSize::getFixed(16);
5237 Width = TypeSize::getFixed(32);
5238 MinOffset = -256;
5239 MaxOffset = 255;
5240 break;
5241 case AArch64::STGPi:
5242 case AArch64::STGPpost:
5243 case AArch64::STGPpre:
5244 Scale = Width = TypeSize::getFixed(16);
5245 MinOffset = -64;
5246 MaxOffset = 63;
5247 break;
5248 case AArch64::LD1RB_IMM:
5249 case AArch64::LD1RB_H_IMM:
5250 case AArch64::LD1RB_S_IMM:
5251 case AArch64::LD1RB_D_IMM:
5252 case AArch64::LD1RSB_H_IMM:
5253 case AArch64::LD1RSB_S_IMM:
5254 case AArch64::LD1RSB_D_IMM:
5255 Scale = Width = TypeSize::getFixed(1);
5256 MinOffset = 0;
5257 MaxOffset = 63;
5258 break;
5259 case AArch64::LD1RH_IMM:
5260 case AArch64::LD1RH_S_IMM:
5261 case AArch64::LD1RH_D_IMM:
5262 case AArch64::LD1RSH_S_IMM:
5263 case AArch64::LD1RSH_D_IMM:
5264 Scale = Width = TypeSize::getFixed(2);
5265 MinOffset = 0;
5266 MaxOffset = 63;
5267 break;
5268 case AArch64::LD1RW_IMM:
5269 case AArch64::LD1RW_D_IMM:
5270 case AArch64::LD1RSW_IMM:
5271 Scale = Width = TypeSize::getFixed(4);
5272 MinOffset = 0;
5273 MaxOffset = 63;
5274 break;
5275 case AArch64::LD1RD_IMM:
5276 Scale = Width = TypeSize::getFixed(8);
5277 MinOffset = 0;
5278 MaxOffset = 63;
5279 break;
5280 }
5281
5282 return true;
5283}
5284
5285// Scaling factor for unscaled load or store.
5287 switch (Opc) {
5288 default:
5289 llvm_unreachable("Opcode has unknown scale!");
5290 case AArch64::LDRBui:
5291 case AArch64::LDRBBui:
5292 case AArch64::LDURBBi:
5293 case AArch64::LDRSBWui:
5294 case AArch64::LDURSBWi:
5295 case AArch64::STRBui:
5296 case AArch64::STRBBui:
5297 case AArch64::STURBBi:
5298 return 1;
5299 case AArch64::LDRHui:
5300 case AArch64::LDRHHui:
5301 case AArch64::LDURHHi:
5302 case AArch64::LDRSHWui:
5303 case AArch64::LDURSHWi:
5304 case AArch64::STRHui:
5305 case AArch64::STRHHui:
5306 case AArch64::STURHHi:
5307 return 2;
5308 case AArch64::LDRSui:
5309 case AArch64::LDURSi:
5310 case AArch64::LDRSpre:
5311 case AArch64::LDRSWui:
5312 case AArch64::LDURSWi:
5313 case AArch64::LDRSWpre:
5314 case AArch64::LDRWpre:
5315 case AArch64::LDRWui:
5316 case AArch64::LDURWi:
5317 case AArch64::STRSui:
5318 case AArch64::STURSi:
5319 case AArch64::STRSpre:
5320 case AArch64::STRWui:
5321 case AArch64::STURWi:
5322 case AArch64::STRWpre:
5323 case AArch64::LDPSi:
5324 case AArch64::LDPSWi:
5325 case AArch64::LDPWi:
5326 case AArch64::STPSi:
5327 case AArch64::STPWi:
5328 return 4;
5329 case AArch64::LDRDui:
5330 case AArch64::LDURDi:
5331 case AArch64::LDRDpre:
5332 case AArch64::LDRXui:
5333 case AArch64::LDURXi:
5334 case AArch64::LDRXpre:
5335 case AArch64::STRDui:
5336 case AArch64::STURDi:
5337 case AArch64::STRDpre:
5338 case AArch64::STRXui:
5339 case AArch64::STURXi:
5340 case AArch64::STRXpre:
5341 case AArch64::LDPDi:
5342 case AArch64::LDPXi:
5343 case AArch64::STPDi:
5344 case AArch64::STPXi:
5345 return 8;
5346 case AArch64::LDRQui:
5347 case AArch64::LDURQi:
5348 case AArch64::STRQui:
5349 case AArch64::STURQi:
5350 case AArch64::STRQpre:
5351 case AArch64::LDPQi:
5352 case AArch64::LDRQpre:
5353 case AArch64::STPQi:
5354 case AArch64::STGi:
5355 case AArch64::STZGi:
5356 case AArch64::ST2Gi:
5357 case AArch64::STZ2Gi:
5358 case AArch64::STGPi:
5359 return 16;
5360 }
5361}
5362
5364 switch (MI.getOpcode()) {
5365 default:
5366 return false;
5367 case AArch64::LDRWpre:
5368 case AArch64::LDRXpre:
5369 case AArch64::LDRSWpre:
5370 case AArch64::LDRSpre:
5371 case AArch64::LDRDpre:
5372 case AArch64::LDRQpre:
5373 return true;
5374 }
5375}
5376
5378 switch (MI.getOpcode()) {
5379 default:
5380 return false;
5381 case AArch64::STRWpre:
5382 case AArch64::STRXpre:
5383 case AArch64::STRSpre:
5384 case AArch64::STRDpre:
5385 case AArch64::STRQpre:
5386 return true;
5387 }
5388}
5389
5391 return isPreLd(MI) || isPreSt(MI);
5392}
5393
5395 switch (MI.getOpcode()) {
5396 default:
5397 return false;
5398 case AArch64::LDURBBi:
5399 case AArch64::LDURHHi:
5400 case AArch64::LDURWi:
5401 case AArch64::LDRBBui:
5402 case AArch64::LDRHHui:
5403 case AArch64::LDRWui:
5404 case AArch64::LDRBBroX:
5405 case AArch64::LDRHHroX:
5406 case AArch64::LDRWroX:
5407 case AArch64::LDRBBroW:
5408 case AArch64::LDRHHroW:
5409 case AArch64::LDRWroW:
5410 return true;
5411 }
5412}
5413
5415 switch (MI.getOpcode()) {
5416 default:
5417 return false;
5418 case AArch64::LDURSBWi:
5419 case AArch64::LDURSHWi:
5420 case AArch64::LDURSBXi:
5421 case AArch64::LDURSHXi:
5422 case AArch64::LDURSWi:
5423 case AArch64::LDRSBWui:
5424 case AArch64::LDRSHWui:
5425 case AArch64::LDRSBXui:
5426 case AArch64::LDRSHXui:
5427 case AArch64::LDRSWui:
5428 case AArch64::LDRSBWroX:
5429 case AArch64::LDRSHWroX:
5430 case AArch64::LDRSBXroX:
5431 case AArch64::LDRSHXroX:
5432 case AArch64::LDRSWroX:
5433 case AArch64::LDRSBWroW:
5434 case AArch64::LDRSHWroW:
5435 case AArch64::LDRSBXroW:
5436 case AArch64::LDRSHXroW:
5437 case AArch64::LDRSWroW:
5438 return true;
5439 }
5440}
5441
5443 switch (MI.getOpcode()) {
5444 default:
5445 return false;
5446 case AArch64::LDPSi:
5447 case AArch64::LDPSWi:
5448 case AArch64::LDPDi:
5449 case AArch64::LDPQi:
5450 case AArch64::LDPWi:
5451 case AArch64::LDPXi:
5452 case AArch64::STPSi:
5453 case AArch64::STPDi:
5454 case AArch64::STPQi:
5455 case AArch64::STPWi:
5456 case AArch64::STPXi:
5457 case AArch64::STGPi:
5458 return true;
5459 }
5460}
5461
5463 assert(MI.mayLoadOrStore() && "Load or store instruction expected");
5464 unsigned Idx =
5466 : 1;
5467 return MI.getOperand(Idx);
5468}
5469
5470const MachineOperand &
5472 assert(MI.mayLoadOrStore() && "Load or store instruction expected");
5473 unsigned Idx =
5475 : 2;
5476 return MI.getOperand(Idx);
5477}
5478
5479const MachineOperand &
5481 switch (MI.getOpcode()) {
5482 default:
5483 llvm_unreachable("Unexpected opcode");
5484 case AArch64::LDRBroX:
5485 case AArch64::LDRBBroX:
5486 case AArch64::LDRSBXroX:
5487 case AArch64::LDRSBWroX:
5488 case AArch64::LDRHroX:
5489 case AArch64::LDRHHroX:
5490 case AArch64::LDRSHXroX:
5491 case AArch64::LDRSHWroX:
5492 case AArch64::LDRWroX:
5493 case AArch64::LDRSroX:
5494 case AArch64::LDRSWroX:
5495 case AArch64::LDRDroX:
5496 case AArch64::LDRXroX:
5497 case AArch64::LDRQroX:
5498 return MI.getOperand(4);
5499 }
5500}
5501
5503 Register Reg) {
5504 if (MI.getParent() == nullptr)
5505 return nullptr;
5506 const MachineFunction *MF = MI.getParent()->getParent();
5507 return MF ? MF->getRegInfo().getRegClassOrNull(Reg) : nullptr;
5508}
5509
5511 auto IsHFPR = [&](const MachineOperand &Op) {
5512 if (!Op.isReg())
5513 return false;
5514 auto Reg = Op.getReg();
5515 if (Reg.isPhysical())
5516 return AArch64::FPR16RegClass.contains(Reg);
5517 const TargetRegisterClass *TRC = ::getRegClass(MI, Reg);
5518 return TRC == &AArch64::FPR16RegClass ||
5519 TRC == &AArch64::FPR16_loRegClass;
5520 };
5521 return llvm::any_of(MI.operands(), IsHFPR);
5522}
5523
5525 auto IsQFPR = [&](const MachineOperand &Op) {
5526 if (!Op.isReg())
5527 return false;
5528 auto Reg = Op.getReg();
5529 if (Reg.isPhysical())
5530 return AArch64::FPR128RegClass.contains(Reg);
5531 const TargetRegisterClass *TRC = ::getRegClass(MI, Reg);
5532 return TRC == &AArch64::FPR128RegClass ||
5533 TRC == &AArch64::FPR128_loRegClass;
5534 };
5535 return llvm::any_of(MI.operands(), IsQFPR);
5536}
5537
5539 switch (MI.getOpcode()) {
5540 case AArch64::BRK:
5541 case AArch64::HLT:
5542 case AArch64::PACIASP:
5543 case AArch64::PACIBSP:
5544 case AArch64::PACIASPPC:
5545 case AArch64::PACIBSPPC:
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.
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.constrainRegClass(DupSrcReg, RC);
8988
8989 unsigned DupSrcLane = Dup->getOperand(2).getImm();
8990
8991 unsigned IdxMulOp = IdxDupOp == 1 ? 2 : 1;
8992 MachineOperand &MulOp = Root.getOperand(IdxMulOp);
8993
8994 Register ResultReg = Root.getOperand(0).getReg();
8995
8997 MIB = BuildMI(MF, MIMetadata(Root), TII->get(MulOpc), ResultReg)
8998 .add(MulOp)
8999 .addReg(DupSrcReg)
9000 .addImm(DupSrcLane);
9001
9002 InsInstrs.push_back(MIB);
9003 return &Root;
9004}
9005
9006/// genFusedMultiplyAcc - Helper to generate fused multiply accumulate
9007/// instructions.
9008///
9009/// \see genFusedMultiply
9013 unsigned IdxMulOpd, unsigned MaddOpc, const TargetRegisterClass *RC) {
9014 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9016}
9017
9018/// genNeg - Helper to generate an intermediate negation of the second operand
9019/// of Root
9021 const TargetInstrInfo *TII, MachineInstr &Root,
9023 DenseMap<Register, unsigned> &InstrIdxForVirtReg,
9024 unsigned MnegOpc, const TargetRegisterClass *RC) {
9025 Register NewVR = MRI.createVirtualRegister(RC);
9027 BuildMI(MF, MIMetadata(Root), TII->get(MnegOpc), NewVR)
9028 .add(Root.getOperand(2));
9029 InsInstrs.push_back(MIB);
9030
9031 assert(InstrIdxForVirtReg.empty());
9032 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9033
9034 return NewVR;
9035}
9036
9037/// genFusedMultiplyAccNeg - Helper to generate fused multiply accumulate
9038/// instructions with an additional negation of the accumulator
9042 DenseMap<Register, unsigned> &InstrIdxForVirtReg, unsigned IdxMulOpd,
9043 unsigned MaddOpc, unsigned MnegOpc, const TargetRegisterClass *RC) {
9044 assert(IdxMulOpd == 1);
9045
9046 Register NewVR =
9047 genNeg(MF, MRI, TII, Root, InsInstrs, InstrIdxForVirtReg, MnegOpc, RC);
9048 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9049 FMAInstKind::Accumulator, &NewVR);
9050}
9051
9052/// genFusedMultiplyIdx - Helper to generate fused multiply accumulate
9053/// instructions.
9054///
9055/// \see genFusedMultiply
9059 unsigned IdxMulOpd, unsigned MaddOpc, const TargetRegisterClass *RC) {
9060 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9062}
9063
9064/// genFusedMultiplyAccNeg - Helper to generate fused multiply accumulate
9065/// instructions with an additional negation of the accumulator
9069 DenseMap<Register, unsigned> &InstrIdxForVirtReg, unsigned IdxMulOpd,
9070 unsigned MaddOpc, unsigned MnegOpc, const TargetRegisterClass *RC) {
9071 assert(IdxMulOpd == 1);
9072
9073 Register NewVR =
9074 genNeg(MF, MRI, TII, Root, InsInstrs, InstrIdxForVirtReg, MnegOpc, RC);
9075
9076 return genFusedMultiply(MF, MRI, TII, Root, InsInstrs, IdxMulOpd, MaddOpc, RC,
9077 FMAInstKind::Indexed, &NewVR);
9078}
9079
9080/// genMaddR - Generate madd instruction and combine mul and add using
9081/// an extra virtual register
9082/// Example - an ADD intermediate needs to be stored in a register:
9083/// MUL I=A,B,0
9084/// ADD R,I,Imm
9085/// ==> ORR V, ZR, Imm
9086/// ==> MADD R,A,B,V
9087/// \param MF Containing MachineFunction
9088/// \param MRI Register information
9089/// \param TII Target information
9090/// \param Root is the ADD instruction
9091/// \param [out] InsInstrs is a vector of machine instructions and will
9092/// contain the generated madd instruction
9093/// \param IdxMulOpd is index of operand in Root that is the result of
9094/// the MUL. In the example above IdxMulOpd is 1.
9095/// \param MaddOpc the opcode fo the madd instruction
9096/// \param VR is a virtual register that holds the value of an ADD operand
9097/// (V in the example above).
9098/// \param RC Register class of operands
9100 const TargetInstrInfo *TII, MachineInstr &Root,
9102 unsigned IdxMulOpd, unsigned MaddOpc, unsigned VR,
9103 const TargetRegisterClass *RC) {
9104 assert(IdxMulOpd == 1 || IdxMulOpd == 2);
9105
9106 MachineInstr *MUL = MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());
9107 Register ResultReg = Root.getOperand(0).getReg();
9108 Register SrcReg0 = MUL->getOperand(1).getReg();
9109 Register SrcReg1 = MUL->getOperand(2).getReg();
9110
9111 if (ResultReg.isVirtual())
9112 MRI.constrainRegClass(ResultReg, RC);
9113 if (SrcReg0.isVirtual())
9114 MRI.constrainRegClass(SrcReg0, RC);
9115 if (SrcReg1.isVirtual())
9116 MRI.constrainRegClass(SrcReg1, RC);
9118 MRI.constrainRegClass(VR, RC);
9119
9121 BuildMI(MF, MIMetadata(Root), TII->get(MaddOpc), ResultReg)
9122 .addReg(SrcReg0)
9123 .addReg(SrcReg1)
9124 .addReg(VR);
9125 // Insert the MADD
9126 InsInstrs.push_back(MIB);
9127 return MUL;
9128}
9129
9130/// Do the following transformation
9131/// A - (B + C) ==> (A - B) - C
9132/// A - (B + C) ==> (A - C) - B
9134 const TargetInstrInfo *TII, MachineInstr &Root,
9137 unsigned IdxOpd1,
9138 DenseMap<Register, unsigned> &InstrIdxForVirtReg) {
9139 assert(IdxOpd1 == 1 || IdxOpd1 == 2);
9140 unsigned IdxOtherOpd = IdxOpd1 == 1 ? 2 : 1;
9141 MachineInstr *AddMI = MRI.getUniqueVRegDef(Root.getOperand(2).getReg());
9142
9143 Register ResultReg = Root.getOperand(0).getReg();
9144 Register RegA = Root.getOperand(1).getReg();
9145 Register RegB = AddMI->getOperand(IdxOpd1).getReg();
9146 Register RegC = AddMI->getOperand(IdxOtherOpd).getReg();
9147 Register NewVR =
9148 MRI.createVirtualRegister(MRI.getRegClass(Root.getOperand(2).getReg()));
9149
9150 unsigned Opcode = Root.getOpcode();
9151 if (Opcode == AArch64::SUBSWrr)
9152 Opcode = AArch64::SUBWrr;
9153 else if (Opcode == AArch64::SUBSXrr)
9154 Opcode = AArch64::SUBXrr;
9155 else
9156 assert((Opcode == AArch64::SUBWrr || Opcode == AArch64::SUBXrr) &&
9157 "Unexpected instruction opcode.");
9158
9159 uint32_t Flags = Root.mergeFlagsWith(*AddMI);
9160 Flags &= ~MachineInstr::NoSWrap;
9161 Flags &= ~MachineInstr::NoUWrap;
9162
9163 MachineInstrBuilder MIB1 =
9164 BuildMI(MF, MIMetadata(Root), TII->get(Opcode), NewVR)
9165 .addReg(RegA)
9166 .addReg(RegB)
9167 .setMIFlags(Flags);
9168 MachineInstrBuilder MIB2 =
9169 BuildMI(MF, MIMetadata(Root), TII->get(Opcode), ResultReg)
9170 .addReg(NewVR)
9171 .addReg(RegC)
9172 .setMIFlags(Flags);
9173
9174 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9175 InsInstrs.push_back(MIB1);
9176 InsInstrs.push_back(MIB2);
9177 DelInstrs.push_back(AddMI);
9178 DelInstrs.push_back(&Root);
9179}
9180
9181unsigned AArch64InstrInfo::getReduceOpcodeForAccumulator(
9182 unsigned int AccumulatorOpCode) const {
9183 switch (AccumulatorOpCode) {
9184 case AArch64::UABALB_ZZZ_D:
9185 case AArch64::SABALB_ZZZ_D:
9186 case AArch64::UABALT_ZZZ_D:
9187 case AArch64::SABALT_ZZZ_D:
9188 return AArch64::ADD_ZZZ_D;
9189 case AArch64::UABALB_ZZZ_H:
9190 case AArch64::SABALB_ZZZ_H:
9191 case AArch64::UABALT_ZZZ_H:
9192 case AArch64::SABALT_ZZZ_H:
9193 return AArch64::ADD_ZZZ_H;
9194 case AArch64::UABALB_ZZZ_S:
9195 case AArch64::SABALB_ZZZ_S:
9196 case AArch64::UABALT_ZZZ_S:
9197 case AArch64::SABALT_ZZZ_S:
9198 return AArch64::ADD_ZZZ_S;
9199 case AArch64::UABALv16i8_v8i16:
9200 case AArch64::SABALv8i8_v8i16:
9201 case AArch64::SABAv8i16:
9202 case AArch64::UABAv8i16:
9203 return AArch64::ADDv8i16;
9204 case AArch64::SABALv2i32_v2i64:
9205 case AArch64::UABALv2i32_v2i64:
9206 case AArch64::SABALv4i32_v2i64:
9207 return AArch64::ADDv2i64;
9208 case AArch64::UABALv4i16_v4i32:
9209 case AArch64::SABALv4i16_v4i32:
9210 case AArch64::SABALv8i16_v4i32:
9211 case AArch64::SABAv4i32:
9212 case AArch64::UABAv4i32:
9213 return AArch64::ADDv4i32;
9214 case AArch64::UABALv4i32_v2i64:
9215 return AArch64::ADDv2i64;
9216 case AArch64::UABALv8i16_v4i32:
9217 return AArch64::ADDv4i32;
9218 case AArch64::UABALv8i8_v8i16:
9219 case AArch64::SABALv16i8_v8i16:
9220 return AArch64::ADDv8i16;
9221 case AArch64::UABAv16i8:
9222 case AArch64::SABAv16i8:
9223 return AArch64::ADDv16i8;
9224 case AArch64::UABAv4i16:
9225 case AArch64::SABAv4i16:
9226 return AArch64::ADDv4i16;
9227 case AArch64::UABAv2i32:
9228 case AArch64::SABAv2i32:
9229 return AArch64::ADDv2i32;
9230 case AArch64::UABAv8i8:
9231 case AArch64::SABAv8i8:
9232 return AArch64::ADDv8i8;
9233 default:
9234 llvm_unreachable("Unknown accumulator opcode");
9235 }
9236}
9237
9238/// When getMachineCombinerPatterns() finds potential patterns,
9239/// this function generates the instructions that could replace the
9240/// original code sequence
9241void AArch64InstrInfo::genAlternativeCodeSequence(
9242 MachineInstr &Root, unsigned Pattern,
9245 DenseMap<Register, unsigned> &InstrIdxForVirtReg) const {
9246 MachineBasicBlock &MBB = *Root.getParent();
9247 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
9248 MachineFunction &MF = *MBB.getParent();
9249 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
9250
9251 MachineInstr *MUL = nullptr;
9252 const TargetRegisterClass *RC;
9253 unsigned Opc;
9254 switch (Pattern) {
9255 default:
9256 // Reassociate instructions.
9257 TargetInstrInfo::genAlternativeCodeSequence(Root, Pattern, InsInstrs,
9258 DelInstrs, InstrIdxForVirtReg);
9259 return;
9261 // A - (B + C)
9262 // ==> (A - B) - C
9263 genSubAdd2SubSub(MF, MRI, TII, Root, InsInstrs, DelInstrs, 1,
9264 InstrIdxForVirtReg);
9265 return;
9267 // A - (B + C)
9268 // ==> (A - C) - B
9269 genSubAdd2SubSub(MF, MRI, TII, Root, InsInstrs, DelInstrs, 2,
9270 InstrIdxForVirtReg);
9271 return;
9274 // MUL I=A,B,0
9275 // ADD R,I,C
9276 // ==> MADD R,A,B,C
9277 // --- Create(MADD);
9279 Opc = AArch64::MADDWrrr;
9280 RC = &AArch64::GPR32RegClass;
9281 } else {
9282 Opc = AArch64::MADDXrrr;
9283 RC = &AArch64::GPR64RegClass;
9284 }
9285 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9286 break;
9289 // MUL I=A,B,0
9290 // ADD R,C,I
9291 // ==> MADD R,A,B,C
9292 // --- Create(MADD);
9294 Opc = AArch64::MADDWrrr;
9295 RC = &AArch64::GPR32RegClass;
9296 } else {
9297 Opc = AArch64::MADDXrrr;
9298 RC = &AArch64::GPR64RegClass;
9299 }
9300 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9301 break;
9306 // MUL I=A,B,0
9307 // ADD/SUB R,I,Imm
9308 // ==> MOV V, Imm/-Imm
9309 // ==> MADD R,A,B,V
9310 // --- Create(MADD);
9311 const TargetRegisterClass *RC;
9312 unsigned BitSize, MovImm;
9315 MovImm = AArch64::MOVi32imm;
9316 RC = &AArch64::GPR32spRegClass;
9317 BitSize = 32;
9318 Opc = AArch64::MADDWrrr;
9319 RC = &AArch64::GPR32RegClass;
9320 } else {
9321 MovImm = AArch64::MOVi64imm;
9322 RC = &AArch64::GPR64spRegClass;
9323 BitSize = 64;
9324 Opc = AArch64::MADDXrrr;
9325 RC = &AArch64::GPR64RegClass;
9326 }
9328 uint64_t Imm = Root.getOperand(2).getImm();
9329
9330 if (Root.getOperand(3).isImm()) {
9331 unsigned Val = Root.getOperand(3).getImm();
9332 Imm = Imm << Val;
9333 }
9334 bool IsSub = Pattern == AArch64MachineCombinerPattern::MULSUBWI_OP1 ||
9336 uint64_t UImm = SignExtend64(IsSub ? -Imm : Imm, BitSize);
9337 // Check that the immediate can be composed via a single instruction.
9339 AArch64_IMM::expandMOVImm(UImm, BitSize, Insn);
9340 if (Insn.size() != 1)
9341 return;
9342 MachineInstrBuilder MIB1 =
9343 BuildMI(MF, MIMetadata(Root), TII->get(MovImm), NewVR)
9344 .addImm(IsSub ? -Imm : Imm);
9345 InsInstrs.push_back(MIB1);
9346 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9347 MUL = genMaddR(MF, MRI, TII, Root, InsInstrs, 1, Opc, NewVR, RC);
9348 break;
9349 }
9352 // MUL I=A,B,0
9353 // SUB R,I, C
9354 // ==> SUB V, 0, C
9355 // ==> MADD R,A,B,V // = -C + A*B
9356 // --- Create(MADD);
9357 const TargetRegisterClass *SubRC;
9358 unsigned SubOpc, ZeroReg;
9360 SubOpc = AArch64::SUBWrr;
9361 SubRC = &AArch64::GPR32spRegClass;
9362 ZeroReg = AArch64::WZR;
9363 Opc = AArch64::MADDWrrr;
9364 RC = &AArch64::GPR32RegClass;
9365 } else {
9366 SubOpc = AArch64::SUBXrr;
9367 SubRC = &AArch64::GPR64spRegClass;
9368 ZeroReg = AArch64::XZR;
9369 Opc = AArch64::MADDXrrr;
9370 RC = &AArch64::GPR64RegClass;
9371 }
9372 Register NewVR = MRI.createVirtualRegister(SubRC);
9373 // SUB NewVR, 0, C
9374 MachineInstrBuilder MIB1 =
9375 BuildMI(MF, MIMetadata(Root), TII->get(SubOpc), NewVR)
9376 .addReg(ZeroReg)
9377 .add(Root.getOperand(2));
9378 InsInstrs.push_back(MIB1);
9379 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9380 MUL = genMaddR(MF, MRI, TII, Root, InsInstrs, 1, Opc, NewVR, RC);
9381 break;
9382 }
9385 // MUL I=A,B,0
9386 // SUB R,C,I
9387 // ==> MSUB R,A,B,C (computes C - A*B)
9388 // --- Create(MSUB);
9390 Opc = AArch64::MSUBWrrr;
9391 RC = &AArch64::GPR32RegClass;
9392 } else {
9393 Opc = AArch64::MSUBXrrr;
9394 RC = &AArch64::GPR64RegClass;
9395 }
9396 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9397 break;
9399 genMaddShf(MF, MRI, TII, Root, InsInstrs, DelInstrs, AArch64::MADDWrrr,
9400 false, InstrIdxForVirtReg);
9401 return;
9403 genMaddShf(MF, MRI, TII, Root, InsInstrs, DelInstrs, AArch64::MADDXrrr,
9404 true, InstrIdxForVirtReg);
9405 return;
9407 Opc = AArch64::MLAv8i8;
9408 RC = &AArch64::FPR64RegClass;
9409 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9410 break;
9412 Opc = AArch64::MLAv8i8;
9413 RC = &AArch64::FPR64RegClass;
9414 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9415 break;
9417 Opc = AArch64::MLAv16i8;
9418 RC = &AArch64::FPR128RegClass;
9419 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9420 break;
9422 Opc = AArch64::MLAv16i8;
9423 RC = &AArch64::FPR128RegClass;
9424 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9425 break;
9427 Opc = AArch64::MLAv4i16;
9428 RC = &AArch64::FPR64RegClass;
9429 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9430 break;
9432 Opc = AArch64::MLAv4i16;
9433 RC = &AArch64::FPR64RegClass;
9434 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9435 break;
9437 Opc = AArch64::MLAv8i16;
9438 RC = &AArch64::FPR128RegClass;
9439 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9440 break;
9442 Opc = AArch64::MLAv8i16;
9443 RC = &AArch64::FPR128RegClass;
9444 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9445 break;
9447 Opc = AArch64::MLAv2i32;
9448 RC = &AArch64::FPR64RegClass;
9449 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9450 break;
9452 Opc = AArch64::MLAv2i32;
9453 RC = &AArch64::FPR64RegClass;
9454 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9455 break;
9457 Opc = AArch64::MLAv4i32;
9458 RC = &AArch64::FPR128RegClass;
9459 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9460 break;
9462 Opc = AArch64::MLAv4i32;
9463 RC = &AArch64::FPR128RegClass;
9464 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9465 break;
9466
9468 Opc = AArch64::MLAv8i8;
9469 RC = &AArch64::FPR64RegClass;
9470 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9471 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv8i8,
9472 RC);
9473 break;
9475 Opc = AArch64::MLSv8i8;
9476 RC = &AArch64::FPR64RegClass;
9477 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9478 break;
9480 Opc = AArch64::MLAv16i8;
9481 RC = &AArch64::FPR128RegClass;
9482 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9483 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv16i8,
9484 RC);
9485 break;
9487 Opc = AArch64::MLSv16i8;
9488 RC = &AArch64::FPR128RegClass;
9489 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9490 break;
9492 Opc = AArch64::MLAv4i16;
9493 RC = &AArch64::FPR64RegClass;
9494 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9495 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i16,
9496 RC);
9497 break;
9499 Opc = AArch64::MLSv4i16;
9500 RC = &AArch64::FPR64RegClass;
9501 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9502 break;
9504 Opc = AArch64::MLAv8i16;
9505 RC = &AArch64::FPR128RegClass;
9506 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9507 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv8i16,
9508 RC);
9509 break;
9511 Opc = AArch64::MLSv8i16;
9512 RC = &AArch64::FPR128RegClass;
9513 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9514 break;
9516 Opc = AArch64::MLAv2i32;
9517 RC = &AArch64::FPR64RegClass;
9518 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9519 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv2i32,
9520 RC);
9521 break;
9523 Opc = AArch64::MLSv2i32;
9524 RC = &AArch64::FPR64RegClass;
9525 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9526 break;
9528 Opc = AArch64::MLAv4i32;
9529 RC = &AArch64::FPR128RegClass;
9530 MUL = genFusedMultiplyAccNeg(MF, MRI, TII, Root, InsInstrs,
9531 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i32,
9532 RC);
9533 break;
9535 Opc = AArch64::MLSv4i32;
9536 RC = &AArch64::FPR128RegClass;
9537 MUL = genFusedMultiplyAcc(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9538 break;
9539
9541 Opc = AArch64::MLAv4i16_indexed;
9542 RC = &AArch64::FPR64RegClass;
9543 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9544 break;
9546 Opc = AArch64::MLAv4i16_indexed;
9547 RC = &AArch64::FPR64RegClass;
9548 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9549 break;
9551 Opc = AArch64::MLAv8i16_indexed;
9552 RC = &AArch64::FPR128RegClass;
9553 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9554 break;
9556 Opc = AArch64::MLAv8i16_indexed;
9557 RC = &AArch64::FPR128RegClass;
9558 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9559 break;
9561 Opc = AArch64::MLAv2i32_indexed;
9562 RC = &AArch64::FPR64RegClass;
9563 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9564 break;
9566 Opc = AArch64::MLAv2i32_indexed;
9567 RC = &AArch64::FPR64RegClass;
9568 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9569 break;
9571 Opc = AArch64::MLAv4i32_indexed;
9572 RC = &AArch64::FPR128RegClass;
9573 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9574 break;
9576 Opc = AArch64::MLAv4i32_indexed;
9577 RC = &AArch64::FPR128RegClass;
9578 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9579 break;
9580
9582 Opc = AArch64::MLAv4i16_indexed;
9583 RC = &AArch64::FPR64RegClass;
9584 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9585 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i16,
9586 RC);
9587 break;
9589 Opc = AArch64::MLSv4i16_indexed;
9590 RC = &AArch64::FPR64RegClass;
9591 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9592 break;
9594 Opc = AArch64::MLAv8i16_indexed;
9595 RC = &AArch64::FPR128RegClass;
9596 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9597 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv8i16,
9598 RC);
9599 break;
9601 Opc = AArch64::MLSv8i16_indexed;
9602 RC = &AArch64::FPR128RegClass;
9603 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9604 break;
9606 Opc = AArch64::MLAv2i32_indexed;
9607 RC = &AArch64::FPR64RegClass;
9608 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9609 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv2i32,
9610 RC);
9611 break;
9613 Opc = AArch64::MLSv2i32_indexed;
9614 RC = &AArch64::FPR64RegClass;
9615 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9616 break;
9618 Opc = AArch64::MLAv4i32_indexed;
9619 RC = &AArch64::FPR128RegClass;
9620 MUL = genFusedMultiplyIdxNeg(MF, MRI, TII, Root, InsInstrs,
9621 InstrIdxForVirtReg, 1, Opc, AArch64::NEGv4i32,
9622 RC);
9623 break;
9625 Opc = AArch64::MLSv4i32_indexed;
9626 RC = &AArch64::FPR128RegClass;
9627 MUL = genFusedMultiplyIdx(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9628 break;
9629
9630 // Floating Point Support
9632 Opc = AArch64::FMADDHrrr;
9633 RC = &AArch64::FPR16RegClass;
9634 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9635 break;
9637 Opc = AArch64::FMADDSrrr;
9638 RC = &AArch64::FPR32RegClass;
9639 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9640 break;
9642 Opc = AArch64::FMADDDrrr;
9643 RC = &AArch64::FPR64RegClass;
9644 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9645 break;
9646
9648 Opc = AArch64::FMADDHrrr;
9649 RC = &AArch64::FPR16RegClass;
9650 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9651 break;
9653 Opc = AArch64::FMADDSrrr;
9654 RC = &AArch64::FPR32RegClass;
9655 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9656 break;
9658 Opc = AArch64::FMADDDrrr;
9659 RC = &AArch64::FPR64RegClass;
9660 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9661 break;
9662
9664 Opc = AArch64::FMLAv1i32_indexed;
9665 RC = &AArch64::FPR32RegClass;
9666 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9668 break;
9670 Opc = AArch64::FMLAv1i32_indexed;
9671 RC = &AArch64::FPR32RegClass;
9672 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9674 break;
9675
9677 Opc = AArch64::FMLAv1i64_indexed;
9678 RC = &AArch64::FPR64RegClass;
9679 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9681 break;
9683 Opc = AArch64::FMLAv1i64_indexed;
9684 RC = &AArch64::FPR64RegClass;
9685 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9687 break;
9688
9690 RC = &AArch64::FPR64RegClass;
9691 Opc = AArch64::FMLAv4i16_indexed;
9692 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9694 break;
9696 RC = &AArch64::FPR64RegClass;
9697 Opc = AArch64::FMLAv4f16;
9698 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9700 break;
9702 RC = &AArch64::FPR64RegClass;
9703 Opc = AArch64::FMLAv4i16_indexed;
9704 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9706 break;
9708 RC = &AArch64::FPR64RegClass;
9709 Opc = AArch64::FMLAv4f16;
9710 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9712 break;
9713
9716 RC = &AArch64::FPR64RegClass;
9718 Opc = AArch64::FMLAv2i32_indexed;
9719 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9721 } else {
9722 Opc = AArch64::FMLAv2f32;
9723 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9725 }
9726 break;
9729 RC = &AArch64::FPR64RegClass;
9731 Opc = AArch64::FMLAv2i32_indexed;
9732 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9734 } else {
9735 Opc = AArch64::FMLAv2f32;
9736 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9738 }
9739 break;
9740
9742 RC = &AArch64::FPR128RegClass;
9743 Opc = AArch64::FMLAv8i16_indexed;
9744 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9746 break;
9748 RC = &AArch64::FPR128RegClass;
9749 Opc = AArch64::FMLAv8f16;
9750 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9752 break;
9754 RC = &AArch64::FPR128RegClass;
9755 Opc = AArch64::FMLAv8i16_indexed;
9756 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9758 break;
9760 RC = &AArch64::FPR128RegClass;
9761 Opc = AArch64::FMLAv8f16;
9762 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9764 break;
9765
9768 RC = &AArch64::FPR128RegClass;
9770 Opc = AArch64::FMLAv2i64_indexed;
9771 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9773 } else {
9774 Opc = AArch64::FMLAv2f64;
9775 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9777 }
9778 break;
9781 RC = &AArch64::FPR128RegClass;
9783 Opc = AArch64::FMLAv2i64_indexed;
9784 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9786 } else {
9787 Opc = AArch64::FMLAv2f64;
9788 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9790 }
9791 break;
9792
9795 RC = &AArch64::FPR128RegClass;
9797 Opc = AArch64::FMLAv4i32_indexed;
9798 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9800 } else {
9801 Opc = AArch64::FMLAv4f32;
9802 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9804 }
9805 break;
9806
9809 RC = &AArch64::FPR128RegClass;
9811 Opc = AArch64::FMLAv4i32_indexed;
9812 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9814 } else {
9815 Opc = AArch64::FMLAv4f32;
9816 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9818 }
9819 break;
9820
9822 Opc = AArch64::FNMSUBHrrr;
9823 RC = &AArch64::FPR16RegClass;
9824 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9825 break;
9827 Opc = AArch64::FNMSUBSrrr;
9828 RC = &AArch64::FPR32RegClass;
9829 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9830 break;
9832 Opc = AArch64::FNMSUBDrrr;
9833 RC = &AArch64::FPR64RegClass;
9834 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9835 break;
9836
9838 Opc = AArch64::FNMADDHrrr;
9839 RC = &AArch64::FPR16RegClass;
9840 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9841 break;
9843 Opc = AArch64::FNMADDSrrr;
9844 RC = &AArch64::FPR32RegClass;
9845 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9846 break;
9848 Opc = AArch64::FNMADDDrrr;
9849 RC = &AArch64::FPR64RegClass;
9850 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC);
9851 break;
9852
9854 Opc = AArch64::FMSUBHrrr;
9855 RC = &AArch64::FPR16RegClass;
9856 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9857 break;
9859 Opc = AArch64::FMSUBSrrr;
9860 RC = &AArch64::FPR32RegClass;
9861 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9862 break;
9864 Opc = AArch64::FMSUBDrrr;
9865 RC = &AArch64::FPR64RegClass;
9866 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC);
9867 break;
9868
9870 Opc = AArch64::FMLSv1i32_indexed;
9871 RC = &AArch64::FPR32RegClass;
9872 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9874 break;
9875
9877 Opc = AArch64::FMLSv1i64_indexed;
9878 RC = &AArch64::FPR64RegClass;
9879 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9881 break;
9882
9885 RC = &AArch64::FPR64RegClass;
9887 MachineInstrBuilder MIB1 =
9888 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv4f16), NewVR)
9889 .add(Root.getOperand(2));
9890 InsInstrs.push_back(MIB1);
9891 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9893 Opc = AArch64::FMLAv4f16;
9894 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9895 FMAInstKind::Accumulator, &NewVR);
9896 } else {
9897 Opc = AArch64::FMLAv4i16_indexed;
9898 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9899 FMAInstKind::Indexed, &NewVR);
9900 }
9901 break;
9902 }
9904 RC = &AArch64::FPR64RegClass;
9905 Opc = AArch64::FMLSv4f16;
9906 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9908 break;
9910 RC = &AArch64::FPR64RegClass;
9911 Opc = AArch64::FMLSv4i16_indexed;
9912 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9914 break;
9915
9918 RC = &AArch64::FPR64RegClass;
9920 Opc = AArch64::FMLSv2i32_indexed;
9921 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9923 } else {
9924 Opc = AArch64::FMLSv2f32;
9925 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9927 }
9928 break;
9929
9932 RC = &AArch64::FPR128RegClass;
9934 MachineInstrBuilder MIB1 =
9935 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv8f16), NewVR)
9936 .add(Root.getOperand(2));
9937 InsInstrs.push_back(MIB1);
9938 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
9940 Opc = AArch64::FMLAv8f16;
9941 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9942 FMAInstKind::Accumulator, &NewVR);
9943 } else {
9944 Opc = AArch64::FMLAv8i16_indexed;
9945 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
9946 FMAInstKind::Indexed, &NewVR);
9947 }
9948 break;
9949 }
9951 RC = &AArch64::FPR128RegClass;
9952 Opc = AArch64::FMLSv8f16;
9953 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9955 break;
9957 RC = &AArch64::FPR128RegClass;
9958 Opc = AArch64::FMLSv8i16_indexed;
9959 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9961 break;
9962
9965 RC = &AArch64::FPR128RegClass;
9967 Opc = AArch64::FMLSv2i64_indexed;
9968 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9970 } else {
9971 Opc = AArch64::FMLSv2f64;
9972 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9974 }
9975 break;
9976
9979 RC = &AArch64::FPR128RegClass;
9981 Opc = AArch64::FMLSv4i32_indexed;
9982 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9984 } else {
9985 Opc = AArch64::FMLSv4f32;
9986 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 2, Opc, RC,
9988 }
9989 break;
9992 RC = &AArch64::FPR64RegClass;
9994 MachineInstrBuilder MIB1 =
9995 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv2f32), NewVR)
9996 .add(Root.getOperand(2));
9997 InsInstrs.push_back(MIB1);
9998 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
10000 Opc = AArch64::FMLAv2i32_indexed;
10001 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10002 FMAInstKind::Indexed, &NewVR);
10003 } else {
10004 Opc = AArch64::FMLAv2f32;
10005 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10006 FMAInstKind::Accumulator, &NewVR);
10007 }
10008 break;
10009 }
10012 RC = &AArch64::FPR128RegClass;
10014 MachineInstrBuilder MIB1 =
10015 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv4f32), NewVR)
10016 .add(Root.getOperand(2));
10017 InsInstrs.push_back(MIB1);
10018 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
10020 Opc = AArch64::FMLAv4i32_indexed;
10021 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10022 FMAInstKind::Indexed, &NewVR);
10023 } else {
10024 Opc = AArch64::FMLAv4f32;
10025 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10026 FMAInstKind::Accumulator, &NewVR);
10027 }
10028 break;
10029 }
10032 RC = &AArch64::FPR128RegClass;
10034 MachineInstrBuilder MIB1 =
10035 BuildMI(MF, MIMetadata(Root), TII->get(AArch64::FNEGv2f64), NewVR)
10036 .add(Root.getOperand(2));
10037 InsInstrs.push_back(MIB1);
10038 InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
10040 Opc = AArch64::FMLAv2i64_indexed;
10041 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10042 FMAInstKind::Indexed, &NewVR);
10043 } else {
10044 Opc = AArch64::FMLAv2f64;
10045 MUL = genFusedMultiply(MF, MRI, TII, Root, InsInstrs, 1, Opc, RC,
10046 FMAInstKind::Accumulator, &NewVR);
10047 }
10048 break;
10049 }
10052 unsigned IdxDupOp =
10054 : 2;
10055 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv2i32_indexed,
10056 &AArch64::FPR128RegClass, MRI);
10057 break;
10058 }
10061 unsigned IdxDupOp =
10063 : 2;
10064 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv2i64_indexed,
10065 &AArch64::FPR128RegClass, MRI);
10066 break;
10067 }
10070 unsigned IdxDupOp =
10072 : 2;
10073 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv4i16_indexed,
10074 &AArch64::FPR128_loRegClass, MRI);
10075 break;
10076 }
10079 unsigned IdxDupOp =
10081 : 2;
10082 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv4i32_indexed,
10083 &AArch64::FPR128RegClass, MRI);
10084 break;
10085 }
10088 unsigned IdxDupOp =
10090 : 2;
10091 genIndexedMultiply(Root, InsInstrs, IdxDupOp, AArch64::FMULv8i16_indexed,
10092 &AArch64::FPR128_loRegClass, MRI);
10093 break;
10094 }
10096 MUL = genFNegatedMAD(MF, MRI, TII, Root, InsInstrs);
10097 break;
10098 }
10100 generateGatherLanePattern(Root, InsInstrs, DelInstrs, InstrIdxForVirtReg,
10101 Pattern, 4);
10102 break;
10103 }
10105 generateGatherLanePattern(Root, InsInstrs, DelInstrs, InstrIdxForVirtReg,
10106 Pattern, 8);
10107 break;
10108 }
10110 generateGatherLanePattern(Root, InsInstrs, DelInstrs, InstrIdxForVirtReg,
10111 Pattern, 16);
10112 break;
10113 }
10114
10115 } // end switch (Pattern)
10116 // Record MUL and ADD/SUB for deletion
10117 if (MUL)
10118 DelInstrs.push_back(MUL);
10119 DelInstrs.push_back(&Root);
10120
10121 // Set the flags on the inserted instructions to be the merged flags of the
10122 // instructions that we have combined.
10123 uint32_t Flags = Root.getFlags();
10124 if (MUL)
10125 Flags = Root.mergeFlagsWith(*MUL);
10126 for (auto *MI : InsInstrs)
10127 MI->setFlags(Flags);
10128}
10129
10130/// Replace csincr-branch sequence by simple conditional branch
10131///
10132/// Examples:
10133/// 1. \code
10134/// csinc w9, wzr, wzr, <condition code>
10135/// tbnz w9, #0, 0x44
10136/// \endcode
10137/// to
10138/// \code
10139/// b.<inverted condition code>
10140/// \endcode
10141///
10142/// 2. \code
10143/// csinc w9, wzr, wzr, <condition code>
10144/// tbz w9, #0, 0x44
10145/// \endcode
10146/// to
10147/// \code
10148/// b.<condition code>
10149/// \endcode
10150///
10151/// Replace compare and branch sequence by TBZ/TBNZ instruction when the
10152/// compare's constant operand is power of 2.
10153///
10154/// Examples:
10155/// \code
10156/// and w8, w8, #0x400
10157/// cbnz w8, L1
10158/// \endcode
10159/// to
10160/// \code
10161/// tbnz w8, #10, L1
10162/// \endcode
10163///
10164/// \param MI Conditional Branch
10165/// \return True when the simple conditional branch is generated
10166///
10168 bool IsNegativeBranch = false;
10169 bool IsTestAndBranch = false;
10170 unsigned TargetBBInMI = 0;
10171 switch (MI.getOpcode()) {
10172 default:
10173 llvm_unreachable("Unknown branch instruction?");
10174 case AArch64::Bcc:
10175 case AArch64::CBWPri:
10176 case AArch64::CBXPri:
10177 case AArch64::CBBAssertExt:
10178 case AArch64::CBHAssertExt:
10179 case AArch64::CBWPrr:
10180 case AArch64::CBXPrr:
10181 return false;
10182 case AArch64::CBZW:
10183 case AArch64::CBZX:
10184 TargetBBInMI = 1;
10185 break;
10186 case AArch64::CBNZW:
10187 case AArch64::CBNZX:
10188 TargetBBInMI = 1;
10189 IsNegativeBranch = true;
10190 break;
10191 case AArch64::TBZW:
10192 case AArch64::TBZX:
10193 TargetBBInMI = 2;
10194 IsTestAndBranch = true;
10195 break;
10196 case AArch64::TBNZW:
10197 case AArch64::TBNZX:
10198 TargetBBInMI = 2;
10199 IsNegativeBranch = true;
10200 IsTestAndBranch = true;
10201 break;
10202 }
10203 // So we increment a zero register and test for bits other
10204 // than bit 0? Conservatively bail out in case the verifier
10205 // missed this case.
10206 if (IsTestAndBranch && MI.getOperand(1).getImm())
10207 return false;
10208
10209 // Find Definition.
10210 assert(MI.getParent() && "Incomplete machine instruction\n");
10211 MachineBasicBlock *MBB = MI.getParent();
10212 MachineFunction *MF = MBB->getParent();
10214 Register VReg = MI.getOperand(0).getReg();
10215 if (!VReg.isVirtual())
10216 return false;
10217
10218 MachineInstr *DefMI = MRI->getVRegDef(VReg);
10219 if (!DefMI)
10220 return false;
10221
10222 // Look through COPY instructions to find definition.
10223 while (DefMI->isCopy()) {
10224 Register CopyVReg = DefMI->getOperand(1).getReg();
10225 if (!CopyVReg.isVirtual())
10226 return false;
10227 if (!MRI->hasOneNonDBGUse(CopyVReg))
10228 return false;
10229 DefMI = MRI->getVRegDef(CopyVReg);
10230 if (!DefMI)
10231 return false;
10232 }
10233
10234 switch (DefMI->getOpcode()) {
10235 default:
10236 return false;
10237 // Fold AND into a TBZ/TBNZ if constant operand is power of 2.
10238 case AArch64::ANDWri:
10239 case AArch64::ANDXri: {
10240 if (IsTestAndBranch)
10241 return false;
10242 if (DefMI->getParent() != MBB)
10243 return false;
10244 if (!MRI->hasOneNonDBGUse(VReg))
10245 return false;
10246
10247 bool Is32Bit = (DefMI->getOpcode() == AArch64::ANDWri);
10248 uint64_t Mask = AArch64_AM::decodeLogicalImmediate(
10249 DefMI->getOperand(2).getImm(), Is32Bit ? 32 : 64);
10250 if (!isPowerOf2_64(Mask))
10251 return false;
10252
10253 MachineOperand &MO = DefMI->getOperand(1);
10254 Register NewReg = MO.getReg();
10255 if (!NewReg.isVirtual())
10256 return false;
10257
10258 if (!MRI->getVRegDef(NewReg))
10259 return false;
10260
10261 MachineBasicBlock &RefToMBB = *MBB;
10262 MachineBasicBlock *TBB = MI.getOperand(1).getMBB();
10263 DebugLoc DL = MI.getDebugLoc();
10264 unsigned Imm = Log2_64(Mask);
10265 unsigned Opc = (Imm < 32)
10266 ? (IsNegativeBranch ? AArch64::TBNZW : AArch64::TBZW)
10267 : (IsNegativeBranch ? AArch64::TBNZX : AArch64::TBZX);
10268 MachineInstr *NewMI = BuildMI(RefToMBB, MI, DL, get(Opc))
10269 .addReg(NewReg)
10270 .addImm(Imm)
10271 .addMBB(TBB);
10272 // Register lives on to the CBZ now.
10273 MO.setIsKill(false);
10274
10275 // For immediate smaller than 32, we need to use the 32-bit
10276 // variant (W) in all cases. Indeed the 64-bit variant does not
10277 // allow to encode them.
10278 // Therefore, if the input register is 64-bit, we need to take the
10279 // 32-bit sub-part.
10280 if (!Is32Bit && Imm < 32)
10281 NewMI->getOperand(0).setSubReg(AArch64::sub_32);
10282 MI.eraseFromParent();
10283 return true;
10284 }
10285 // Look for CSINC
10286 case AArch64::CSINCWr:
10287 case AArch64::CSINCXr: {
10288 if (!(DefMI->getOperand(1).getReg() == AArch64::WZR &&
10289 DefMI->getOperand(2).getReg() == AArch64::WZR) &&
10290 !(DefMI->getOperand(1).getReg() == AArch64::XZR &&
10291 DefMI->getOperand(2).getReg() == AArch64::XZR))
10292 return false;
10293
10294 if (DefMI->findRegisterDefOperandIdx(AArch64::NZCV, /*TRI=*/nullptr,
10295 true) != -1)
10296 return false;
10297
10298 AArch64CC::CondCode CC = (AArch64CC::CondCode)DefMI->getOperand(3).getImm();
10299 // Convert only when the condition code is not modified between
10300 // the CSINC and the branch. The CC may be used by other
10301 // instructions in between.
10303 return false;
10304 MachineBasicBlock &RefToMBB = *MBB;
10305 MachineBasicBlock *TBB = MI.getOperand(TargetBBInMI).getMBB();
10306 DebugLoc DL = MI.getDebugLoc();
10307 if (IsNegativeBranch)
10309 BuildMI(RefToMBB, MI, DL, get(AArch64::Bcc)).addImm(CC).addMBB(TBB);
10310 MI.eraseFromParent();
10311 return true;
10312 }
10313 }
10314}
10315
10316std::pair<unsigned, unsigned>
10317AArch64InstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
10318 const unsigned Mask = AArch64II::MO_FRAGMENT;
10319 return std::make_pair(TF & Mask, TF & ~Mask);
10320}
10321
10323AArch64InstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
10324 using namespace AArch64II;
10325
10326 static const std::pair<unsigned, const char *> TargetFlags[] = {
10327 {MO_PAGE, "aarch64-page"}, {MO_PAGEOFF, "aarch64-pageoff"},
10328 {MO_G3, "aarch64-g3"}, {MO_G2, "aarch64-g2"},
10329 {MO_G1, "aarch64-g1"}, {MO_G0, "aarch64-g0"},
10330 {MO_HI12, "aarch64-hi12"}};
10331 return ArrayRef(TargetFlags);
10332}
10333
10335AArch64InstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
10336 using namespace AArch64II;
10337
10338 static const std::pair<unsigned, const char *> TargetFlags[] = {
10339 {MO_COFFSTUB, "aarch64-coffstub"},
10340 {MO_GOT, "aarch64-got"},
10341 {MO_NC, "aarch64-nc"},
10342 {MO_S, "aarch64-s"},
10343 {MO_TLS, "aarch64-tls"},
10344 {MO_DLLIMPORT, "aarch64-dllimport"},
10345 {MO_PREL, "aarch64-prel"},
10346 {MO_TAGGED, "aarch64-tagged"},
10347 {MO_ARM64EC_CALLMANGLE, "aarch64-arm64ec-callmangle"},
10348 };
10349 return ArrayRef(TargetFlags);
10350}
10351
10353AArch64InstrInfo::getSerializableMachineMemOperandTargetFlags() const {
10354 static const std::pair<MachineMemOperand::Flags, const char *> TargetFlags[] =
10355 {{MOSuppressPair, "aarch64-suppress-pair"},
10356 {MOStridedAccess, "aarch64-strided-access"}};
10357 return ArrayRef(TargetFlags);
10358}
10359
10360/// Constants defining how certain sequences should be outlined.
10361/// This encompasses how an outlined function should be called, and what kind of
10362/// frame should be emitted for that outlined function.
10363///
10364/// \p MachineOutlinerDefault implies that the function should be called with
10365/// a save and restore of LR to the stack.
10366///
10367/// That is,
10368///
10369/// I1 Save LR OUTLINED_FUNCTION:
10370/// I2 --> BL OUTLINED_FUNCTION I1
10371/// I3 Restore LR I2
10372/// I3
10373/// RET
10374///
10375/// * Call construction overhead: 3 (save + BL + restore)
10376/// * Frame construction overhead: 1 (ret)
10377/// * Requires stack fixups? Yes
10378///
10379/// \p MachineOutlinerTailCall implies that the function is being created from
10380/// a sequence of instructions ending in a return.
10381///
10382/// That is,
10383///
10384/// I1 OUTLINED_FUNCTION:
10385/// I2 --> B OUTLINED_FUNCTION I1
10386/// RET I2
10387/// RET
10388///
10389/// * Call construction overhead: 1 (B)
10390/// * Frame construction overhead: 0 (Return included in sequence)
10391/// * Requires stack fixups? No
10392///
10393/// \p MachineOutlinerNoLRSave implies that the function should be called using
10394/// a BL instruction, but doesn't require LR to be saved and restored. This
10395/// happens when LR is known to be dead.
10396///
10397/// That is,
10398///
10399/// I1 OUTLINED_FUNCTION:
10400/// I2 --> BL OUTLINED_FUNCTION I1
10401/// I3 I2
10402/// I3
10403/// RET
10404///
10405/// * Call construction overhead: 1 (BL)
10406/// * Frame construction overhead: 1 (RET)
10407/// * Requires stack fixups? No
10408///
10409/// \p MachineOutlinerThunk implies that the function is being created from
10410/// a sequence of instructions ending in a call. The outlined function is
10411/// called with a BL instruction, and the outlined function tail-calls the
10412/// original call destination.
10413///
10414/// That is,
10415///
10416/// I1 OUTLINED_FUNCTION:
10417/// I2 --> BL OUTLINED_FUNCTION I1
10418/// BL f I2
10419/// B f
10420/// * Call construction overhead: 1 (BL)
10421/// * Frame construction overhead: 0
10422/// * Requires stack fixups? No
10423///
10424/// \p MachineOutlinerRegSave implies that the function should be called with a
10425/// save and restore of LR to an available register. This allows us to avoid
10426/// stack fixups. Note that this outlining variant is compatible with the
10427/// NoLRSave case.
10428///
10429/// That is,
10430///
10431/// I1 Save LR OUTLINED_FUNCTION:
10432/// I2 --> BL OUTLINED_FUNCTION I1
10433/// I3 Restore LR I2
10434/// I3
10435/// RET
10436///
10437/// * Call construction overhead: 3 (save + BL + restore)
10438/// * Frame construction overhead: 1 (ret)
10439/// * Requires stack fixups? No
10441 MachineOutlinerDefault, /// Emit a save, restore, call, and return.
10442 MachineOutlinerTailCall, /// Only emit a branch.
10443 MachineOutlinerNoLRSave, /// Emit a call and return.
10444 MachineOutlinerThunk, /// Emit a call and tail-call.
10445 MachineOutlinerRegSave /// Same as default, but save to a register.
10446};
10447
10453
10454/// Return true if the frame-record form of the outlined prologue is enabled for
10455/// the target of \p MF.
10456///
10457/// A non-leaf outlined function must save LR. On MachO, saving LR alone
10458/// (str x30) has no compact unwind encoding, so we get a large DWARF FDE
10459/// instead. Saving FP and LR as a frame record (stp x29, x30 ; mov x29, sp)
10460/// gets the small FRAME encoding, and costs one extra instruction.
10462 return MF.getSubtarget<AArch64Subtarget>()
10463 .getCLOpts()
10464 .outliner_compact_unwind_frame &&
10466}
10467
10468/// Return true if the outlined function in \p MBB should save FP and LR as a
10469/// frame record instead of saving LR alone.
10471 const MachineBasicBlock &MBB) {
10472 const MachineFunction &MF = *MBB.getParent();
10473
10474 // Only worth it if the function has unwind info to shrink.
10477 return false;
10478
10479 // Only safe if the outlined code never touches FP, since we overwrite it.
10481 for (const MachineInstr &MI : MBB.instrs())
10482 LRU.accumulate(MI);
10483 return LRU.available(AArch64::FP);
10484}
10485
10486/// Predict what the above will answer, for use while costing candidates. The
10487/// outlined function does not exist yet, so answer from \p RepeatedSequenceLocs
10488/// instead. This is only an estimate; buildOutlinedFrame() makes the call.
10490 std::vector<outliner::Candidate> &RepeatedSequenceLocs,
10491 const TargetRegisterInfo &TRI) {
10492 if (!isCompactUnwindFrameRecordEnabled(*RepeatedSequenceLocs.front().getMF()))
10493 return false;
10494
10495 // The outlined function is nounwind only if every candidate is, so it has
10496 // unwind info if any candidate does.
10497 if (llvm::none_of(RepeatedSequenceLocs, [](outliner::Candidate &C) {
10498 const MachineFunction &MF = *C.getMF();
10499 return MF.getInfo<AArch64FunctionInfo>()->needsDwarfUnwindInfo(MF);
10500 }))
10501 return false;
10502
10503 // FP is free in the outlined function only if it is free in every candidate.
10504 return llvm::all_of(RepeatedSequenceLocs, [&TRI](outliner::Candidate &C) {
10505 return C.isAvailableInsideSeq(AArch64::FP, TRI);
10506 });
10507}
10508
10510AArch64InstrInfo::findRegisterToSaveLRTo(outliner::Candidate &C) const {
10511 MachineFunction *MF = C.getMF();
10512 const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
10513 const AArch64RegisterInfo *ARI =
10514 static_cast<const AArch64RegisterInfo *>(&TRI);
10515 // Check if there is an available register across the sequence that we can
10516 // use.
10517 for (unsigned Reg : AArch64::GPR64RegClass) {
10518 if (!ARI->isReservedReg(*MF, Reg) &&
10519 Reg != AArch64::LR && // LR is not reserved, but don't use it.
10520 Reg != AArch64::X16 && // X16 is not guaranteed to be preserved.
10521 Reg != AArch64::X17 && // Ditto for X17.
10522 C.isAvailableAcrossAndOutOfSeq(Reg, TRI) &&
10523 C.isAvailableInsideSeq(Reg, TRI))
10524 return Reg;
10525 }
10526 return Register();
10527}
10528
10529static bool
10531 const outliner::Candidate &b) {
10532 const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
10533 const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
10534
10535 return MFIa->getSignReturnAddressCondition() ==
10537}
10538
10539static bool
10541 const outliner::Candidate &b) {
10542 const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
10543 const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
10544
10545 return MFIa->shouldSignWithBKey() == MFIb->shouldSignWithBKey();
10546}
10547
10549 const outliner::Candidate &b) {
10550 const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
10551 const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
10552
10553 const AArch64Subtarget &SubtargetA =
10555 const AArch64Subtarget &SubtargetB =
10556 b.getMF()->getSubtarget<AArch64Subtarget>();
10557
10558 // Return true only if branch-protection-pauth-lr attributes match
10559 // and +pauth-lr feature is enabled for both.
10560 if (MFIa->branchProtectionPAuthLR() != MFIb->branchProtectionPAuthLR())
10561 return false;
10562
10563 return !MFIa->branchProtectionPAuthLR() ||
10564 SubtargetA.hasPAuthLR() == SubtargetB.hasPAuthLR();
10565}
10566
10568 const outliner::Candidate &b) {
10569 const AArch64Subtarget &SubtargetA =
10571 const AArch64Subtarget &SubtargetB =
10572 b.getMF()->getSubtarget<AArch64Subtarget>();
10573 return SubtargetA.hasV8_3aOps() == SubtargetB.hasV8_3aOps();
10574}
10575
10576namespace {
10577struct SPAddSubImmEncoding {
10578 unsigned Opcode;
10579 int64_t Imm;
10580 int64_t Shift;
10581};
10582} // namespace
10583
10584/// Returns true if \p MI is an ADD/SUBXri with an immediate offset that reads
10585/// SP but does not write SP (e.g. "add x0, sp, #48").
10586static bool isSPAddSubImm(const MachineInstr &MI) {
10587 if (MI.getOpcode() != AArch64::ADDXri && MI.getOpcode() != AArch64::SUBXri)
10588 return false;
10589
10590 assert(MI.getNumExplicitOperands() == 4 && "Wrong number of operands");
10591 assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() &&
10592 MI.getOperand(3).isImm() && "Unexpected add/sub immediate operands");
10593
10594 if (MI.getOperand(0).getReg() == AArch64::SP)
10595 return false;
10596 if (MI.getOperand(1).getReg() != AArch64::SP)
10597 return false;
10598
10599 return MI.getOperand(2).isImm();
10600}
10601
10602/// Adjust the signed byte offset of \p MI, which must satisfy isSPAddSubImm,
10603/// by \p Delta and re-encode the result. Returns std::nullopt if the adjusted
10604/// offset is not encodable.
10605static std::optional<SPAddSubImmEncoding>
10606adjustSPAddSubImm(const MachineInstr &MI, int64_t Delta) {
10607 assert(isSPAddSubImm(MI) && "Expected an SP-based add/sub immediate");
10608 bool IsSub = MI.getOpcode() == AArch64::SUBXri;
10609
10610 // ADD/SUBXri encode a 12-bit unsigned immediate with an optional left shift
10611 // which can only be 12.
10612 int64_t ShiftImm = MI.getOperand(3).getImm();
10614 "Unexpected add/sub immediate shift type");
10615 unsigned Shift = AArch64_AM::getShiftValue(ShiftImm);
10616 assert((Shift == 0 || Shift == 12) && "Unexpected add/sub immediate shift");
10617
10618 int64_t Offset = MI.getOperand(2).getImm() << Shift;
10619 if (IsSub)
10620 Offset = -Offset;
10621
10622 // Apply the adjustment and try to re-encode.
10623 int64_t NewOffset = Offset + Delta;
10624 int64_t AbsOffset = std::abs(NewOffset);
10625
10626 SPAddSubImmEncoding Enc;
10627 Enc.Opcode = NewOffset < 0 ? AArch64::SUBXri : AArch64::ADDXri;
10628
10629 // Try to encode as a 12-bit immediate with shift=0 first.
10630 if (AbsOffset <= 0xfff) {
10631 Enc.Imm = AbsOffset;
10633 } else if ((AbsOffset & 0xfff) == 0 && (AbsOffset >> 12) <= 0xfff) {
10634 Enc.Imm = AbsOffset >> 12;
10636 } else {
10637 return std::nullopt;
10638 }
10639
10640 return Enc;
10641}
10642
10643std::optional<std::unique_ptr<outliner::OutlinedFunction>>
10644AArch64InstrInfo::getOutliningCandidateInfo(
10645 const MachineModuleInfo &MMI,
10646 std::vector<outliner::Candidate> &RepeatedSequenceLocs,
10647 unsigned MinRepeats) const {
10648 unsigned SequenceSize = 0;
10649 for (auto &MI : RepeatedSequenceLocs[0])
10650 SequenceSize += getInstSizeInBytes(MI);
10651
10652 unsigned NumBytesToCreateFrame = 0;
10653
10654 // Avoid splitting ADRP ADD/LDR pair into outlined functions.
10655 // These instructions are fused together by the scheduler.
10656 // Any candidate where ADRP is the last instruction should be rejected
10657 // as that will lead to splitting ADRP pair.
10658 MachineInstr &LastMI = RepeatedSequenceLocs[0].back();
10659 MachineInstr &FirstMI = RepeatedSequenceLocs[0].front();
10660 if (LastMI.getOpcode() == AArch64::ADRP &&
10661 (LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_PAGE) != 0 &&
10662 (LastMI.getOperand(1).getTargetFlags() & AArch64II::MO_GOT) != 0) {
10663 return std::nullopt;
10664 }
10665
10666 // Similarly any candidate where the first instruction is ADD/LDR with a
10667 // page offset should be rejected to avoid ADRP splitting.
10668 if ((FirstMI.getOpcode() == AArch64::ADDXri ||
10669 FirstMI.getOpcode() == AArch64::LDRXui) &&
10670 (FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_PAGEOFF) != 0 &&
10671 (FirstMI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) != 0) {
10672 return std::nullopt;
10673 }
10674
10675 // We only allow outlining for functions having exactly matching return
10676 // address signing attributes, i.e., all share the same value for the
10677 // attribute "sign-return-address", all share the same type of key they
10678 // are signed with & all share the same pauth-lr attributes.
10679 // Additionally we require all functions to simultaneously either support
10680 // v8.3a features or not. Otherwise an outlined function could get signed
10681 // using dedicated v8.3 instructions and a call from a function that doesn't
10682 // support v8.3 instructions would therefore be invalid.
10683 if (std::adjacent_find(
10684 RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
10685 [](const outliner::Candidate &a, const outliner::Candidate &b) {
10686 // Return true if a and b are non-equal w.r.t. return address
10687 // signing, support of v8.3a features or support of pauth-lr
10688 if (outliningCandidatesSigningScopeConsensus(a, b) &&
10689 outliningCandidatesSigningKeyConsensus(a, b) &&
10690 outliningCandidatesV8_3OpsConsensus(a, b) &&
10691 outliningCandidatesPAuthLRConsensus(a, b)) {
10692 return false;
10693 }
10694 return true;
10695 }) != RepeatedSequenceLocs.end()) {
10696 return std::nullopt;
10697 }
10698
10699 // Since at this point all candidates agree on their return address signing
10700 // picking just one is fine. If the candidate functions potentially sign their
10701 // return addresses, the outlined function should do the same. Note that in
10702 // the case of "sign-return-address"="non-leaf" this is an assumption: It is
10703 // not certainly true that the outlined function will have to sign its return
10704 // address but this decision is made later, when the decision to outline
10705 // has already been made.
10706 // The same holds for the number of additional instructions we need: On
10707 // v8.3a RET can be replaced by RETAA/RETAB and no AUT instruction is
10708 // necessary. However, at this point we don't know if the outlined function
10709 // will have a RET instruction so we assume the worst.
10710 const TargetRegisterInfo &TRI = getRegisterInfo();
10711 // Performing a tail call may require extra checks when PAuth is enabled.
10712 // If PAuth is disabled, set it to zero for uniformity.
10713 unsigned NumBytesToCheckLRInTCEpilogue = 0;
10714 const auto RASignCondition = RepeatedSequenceLocs[0]
10715 .getMF()
10716 ->getInfo<AArch64FunctionInfo>()
10717 ->getSignReturnAddressCondition();
10718 if (RASignCondition != SignReturnAddress::None) {
10719 // Candidates that have Return Address Authentication Hardening enabled are
10720 // discarded.
10721 //
10722 // In its current form, the machine outliner does not preserve X16/X17
10723 // across outlined function calls, even though it should as they are
10724 // caller-saved registers. And since the hardening based on load from the
10725 // return address may clobber one of these registers, if they are alive
10726 // across a call their value would be lost due to the hardening mechanism.
10727 llvm::erase_if(RepeatedSequenceLocs, [](outliner::Candidate &C) {
10728 return C.getMF()
10729 ->getInfo<AArch64FunctionInfo>()
10730 ->shouldHardenSignReturnAddress();
10731 });
10732 // If the sequence doesn't have enough candidates left, then we're done.
10733 if (RepeatedSequenceLocs.size() < MinRepeats)
10734 return std::nullopt;
10735
10736 // One PAC and one AUT instructions
10737 NumBytesToCreateFrame += 8;
10738
10739 // PAuth is enabled - set extra tail call cost, if any.
10740 auto LRCheckMethod = Subtarget.getAuthenticatedLRCheckMethod(
10741 *RepeatedSequenceLocs[0].getMF());
10742 NumBytesToCheckLRInTCEpilogue =
10744 // Checking the authenticated LR value may significantly impact
10745 // SequenceSize, so account for it for more precise results.
10746 if (isTailCallReturnInst(RepeatedSequenceLocs[0].back()))
10747 SequenceSize += NumBytesToCheckLRInTCEpilogue;
10748
10749 // We have to check if sp modifying instructions would get outlined.
10750 // If so we only allow outlining if sp is unchanged overall, so matching
10751 // sub and add instructions are okay to outline, all other sp modifications
10752 // are not
10753 auto hasIllegalSPModification = [&TRI](outliner::Candidate &C) {
10754 int SPValue = 0;
10755 for (auto &MI : C) {
10756 if (MI.modifiesRegister(AArch64::SP, &TRI)) {
10757 switch (MI.getOpcode()) {
10758 case AArch64::ADDXri:
10759 case AArch64::ADDWri:
10760 assert(MI.getNumOperands() == 4 && "Wrong number of operands");
10761 assert(MI.getOperand(2).isImm() &&
10762 "Expected operand to be immediate");
10763 assert(MI.getOperand(1).isReg() &&
10764 "Expected operand to be a register");
10765 // Check if the add just increments sp. If so, we search for
10766 // matching sub instructions that decrement sp. If not, the
10767 // modification is illegal
10768 if (MI.getOperand(1).getReg() == AArch64::SP)
10769 SPValue += MI.getOperand(2).getImm();
10770 else
10771 return true;
10772 break;
10773 case AArch64::SUBXri:
10774 case AArch64::SUBWri:
10775 assert(MI.getNumOperands() == 4 && "Wrong number of operands");
10776 assert(MI.getOperand(2).isImm() &&
10777 "Expected operand to be immediate");
10778 assert(MI.getOperand(1).isReg() &&
10779 "Expected operand to be a register");
10780 // Check if the sub just decrements sp. If so, we search for
10781 // matching add instructions that increment sp. If not, the
10782 // modification is illegal
10783 if (MI.getOperand(1).getReg() == AArch64::SP)
10784 SPValue -= MI.getOperand(2).getImm();
10785 else
10786 return true;
10787 break;
10788 default:
10789 return true;
10790 }
10791 }
10792 }
10793 if (SPValue)
10794 return true;
10795 return false;
10796 };
10797 // Remove candidates with illegal stack modifying instructions
10798 llvm::erase_if(RepeatedSequenceLocs, hasIllegalSPModification);
10799
10800 // If the sequence doesn't have enough candidates left, then we're done.
10801 if (RepeatedSequenceLocs.size() < MinRepeats)
10802 return std::nullopt;
10803 }
10804
10805 // Properties about candidate MBBs that hold for all of them.
10806 unsigned FlagsSetInAll = 0xF;
10807
10808 // Compute liveness information for each candidate, and set FlagsSetInAll.
10809 for (outliner::Candidate &C : RepeatedSequenceLocs)
10810 FlagsSetInAll &= C.Flags;
10811
10812 unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back().getOpcode();
10813
10814 // Helper lambda which sets call information for every candidate.
10815 auto SetCandidateCallInfo =
10816 [&RepeatedSequenceLocs](unsigned CallID, unsigned NumBytesForCall) {
10817 for (outliner::Candidate &C : RepeatedSequenceLocs)
10818 C.setCallInfo(CallID, NumBytesForCall);
10819 };
10820
10821 unsigned FrameID = MachineOutlinerDefault;
10822 NumBytesToCreateFrame += 4;
10823
10824 bool HasBTI = any_of(RepeatedSequenceLocs, [](outliner::Candidate &C) {
10825 return C.getMF()->getInfo<AArch64FunctionInfo>()->branchTargetEnforcement();
10826 });
10827
10828 // We check to see if CFI Instructions are present, and if they are
10829 // we find the number of CFI Instructions in the candidates.
10830 unsigned CFICount = 0;
10831 for (auto &I : RepeatedSequenceLocs[0]) {
10832 if (I.isCFIInstruction())
10833 CFICount++;
10834 }
10835
10836 // We compare the number of found CFI Instructions to the number of CFI
10837 // instructions in the parent function for each candidate. We must check this
10838 // since if we outline one of the CFI instructions in a function, we have to
10839 // outline them all for correctness. If we do not, the address offsets will be
10840 // incorrect between the two sections of the program.
10841 for (outliner::Candidate &C : RepeatedSequenceLocs) {
10842 std::vector<MCCFIInstruction> CFIInstructions =
10843 C.getMF()->getFrameInstructions();
10844
10845 if (CFICount > 0 && CFICount != CFIInstructions.size())
10846 return std::nullopt;
10847 }
10848
10849 // Returns true if an instructions is safe to fix up, false otherwise.
10850 auto IsSafeToFixup = [this, &TRI](MachineInstr &MI) {
10851 if (MI.isCall())
10852 return true;
10853
10854 if (!MI.modifiesRegister(AArch64::SP, &TRI) &&
10855 !MI.readsRegister(AArch64::SP, &TRI))
10856 return true;
10857
10858 // Any modification of SP will break our code to save/restore LR.
10859 // FIXME: We could handle some instructions which add a constant
10860 // offset to SP, with a bit more work.
10861 if (MI.modifiesRegister(AArch64::SP, &TRI))
10862 return false;
10863
10864 // At this point, we have a stack instruction that we might need to
10865 // fix up. We'll handle it if it's a load or store.
10866 if (MI.mayLoadOrStore()) {
10867 const MachineOperand *Base; // Filled with the base operand of MI.
10868 int64_t Offset; // Filled with the offset of MI.
10869 bool OffsetIsScalable;
10870
10871 // Does it allow us to offset the base operand and is the base the
10872 // register SP?
10873 if (!getMemOperandWithOffset(MI, Base, Offset, OffsetIsScalable) ||
10874 !Base->isReg() || Base->getReg() != AArch64::SP)
10875 return false;
10876
10877 // Fixe-up code below assumes bytes.
10878 if (OffsetIsScalable)
10879 return false;
10880
10881 // Find the minimum/maximum offset for this instruction and check
10882 // if fixing it up would be in range.
10883 int64_t MinOffset,
10884 MaxOffset; // Unscaled offsets for the instruction.
10885 // The scale to multiply the offsets by.
10886 TypeSize Scale(0U, false), DummyWidth(0U, false);
10887 getMemOpInfo(MI.getOpcode(), Scale, DummyWidth, MinOffset, MaxOffset);
10888
10889 Offset += 16; // Update the offset to what it would be if we outlined.
10890 if (Offset < MinOffset * (int64_t)Scale.getFixedValue() ||
10891 Offset > MaxOffset * (int64_t)Scale.getFixedValue())
10892 return false;
10893
10894 // It's in range, so we can outline it.
10895 return true;
10896 }
10897
10898 if (isSPAddSubImm(MI))
10899 return adjustSPAddSubImm(MI, 16).has_value();
10900
10901 // FIXME: Add handling for other SP-based address calculations that can be
10902 // adjusted after outlining.
10903 return false;
10904 };
10905
10906 // True if it's possible to fix up each stack instruction in this sequence.
10907 // Important for frames/call variants that modify the stack.
10908 bool AllStackInstrsSafe =
10909 llvm::all_of(RepeatedSequenceLocs[0], IsSafeToFixup);
10910
10911 // If the last instruction in any candidate is a terminator, then we should
10912 // tail call all of the candidates.
10913 if (RepeatedSequenceLocs[0].back().isTerminator()) {
10914 FrameID = MachineOutlinerTailCall;
10915 NumBytesToCreateFrame = 0;
10916 unsigned NumBytesForCall = 4 + NumBytesToCheckLRInTCEpilogue;
10917 SetCandidateCallInfo(MachineOutlinerTailCall, NumBytesForCall);
10918 }
10919
10920 else if (LastInstrOpcode == AArch64::BL ||
10921 ((LastInstrOpcode == AArch64::BLR ||
10922 LastInstrOpcode == AArch64::BLRNoIP) &&
10923 !HasBTI)) {
10924 // FIXME: Do we need to check if the code after this uses the value of LR?
10925 FrameID = MachineOutlinerThunk;
10926 NumBytesToCreateFrame = NumBytesToCheckLRInTCEpilogue;
10927 SetCandidateCallInfo(MachineOutlinerThunk, 4);
10928 }
10929
10930 else {
10931 // We need to decide how to emit calls + frames. We can always emit the same
10932 // frame if we don't need to save to the stack. If we have to save to the
10933 // stack, then we need a different frame.
10934 unsigned NumBytesNoStackCalls = 0;
10935 std::vector<outliner::Candidate> CandidatesWithoutStackFixups;
10936
10937 // Check if we have to save LR.
10938 for (outliner::Candidate &C : RepeatedSequenceLocs) {
10939 bool LRAvailable =
10941 ? C.isAvailableAcrossAndOutOfSeq(AArch64::LR, TRI)
10942 : true;
10943 // If we have a noreturn caller, then we're going to be conservative and
10944 // say that we have to save LR. If we don't have a ret at the end of the
10945 // block, then we can't reason about liveness accurately.
10946 //
10947 // FIXME: We can probably do better than always disabling this in
10948 // noreturn functions by fixing up the liveness info.
10949 bool IsNoReturn =
10950 C.getMF()->getFunction().hasFnAttribute(Attribute::NoReturn);
10951
10952 // Is LR available? If so, we don't need a save.
10953 if (LRAvailable && !IsNoReturn) {
10954 NumBytesNoStackCalls += 4;
10955 C.setCallInfo(MachineOutlinerNoLRSave, 4);
10956 CandidatesWithoutStackFixups.push_back(C);
10957 }
10958
10959 // Is an unused register available? If so, we won't modify the stack, so
10960 // we can outline with the same frame type as those that don't save LR.
10961 else if (findRegisterToSaveLRTo(C)) {
10962 NumBytesNoStackCalls += 12;
10963 C.setCallInfo(MachineOutlinerRegSave, 12);
10964 CandidatesWithoutStackFixups.push_back(C);
10965 }
10966
10967 // Is SP used in the sequence at all? If not, we don't have to modify
10968 // the stack, so we are guaranteed to get the same frame.
10969 else if (C.isAvailableInsideSeq(AArch64::SP, TRI)) {
10970 NumBytesNoStackCalls += 12;
10971 C.setCallInfo(MachineOutlinerDefault, 12);
10972 CandidatesWithoutStackFixups.push_back(C);
10973 }
10974
10975 // If we outline this, we need to modify the stack. Pretend we don't
10976 // outline this by saving all of its bytes.
10977 else {
10978 NumBytesNoStackCalls += SequenceSize;
10979 }
10980 }
10981
10982 // If there are no places where we have to save LR, then note that we
10983 // don't have to update the stack. Otherwise, give every candidate the
10984 // default call type, as long as it's safe to do so.
10985 if (!AllStackInstrsSafe ||
10986 NumBytesNoStackCalls <= RepeatedSequenceLocs.size() * 12) {
10987 RepeatedSequenceLocs = CandidatesWithoutStackFixups;
10988 FrameID = MachineOutlinerNoLRSave;
10989 if (RepeatedSequenceLocs.size() < MinRepeats)
10990 return std::nullopt;
10991 } else {
10992 SetCandidateCallInfo(MachineOutlinerDefault, 12);
10993
10994 // Bugzilla ID: 46767
10995 // TODO: Check if fixing up the stack more than once is safe so we can
10996 // outline these.
10997 //
10998 // An outline resulting in a caller that requires stack fixups at the
10999 // callsite to a callee that also requires stack fixups can happen when
11000 // there are no available registers at the candidate callsite for a
11001 // candidate that itself also has calls.
11002 //
11003 // In other words if function_containing_sequence in the following pseudo
11004 // assembly requires that we save LR at the point of the call, but there
11005 // are no available registers: in this case we save using SP and as a
11006 // result the SP offsets requires stack fixups by multiples of 16.
11007 //
11008 // function_containing_sequence:
11009 // ...
11010 // save LR to SP <- Requires stack instr fixups in OUTLINED_FUNCTION_N
11011 // call OUTLINED_FUNCTION_N
11012 // restore LR from SP
11013 // ...
11014 //
11015 // OUTLINED_FUNCTION_N:
11016 // save LR to SP <- Requires stack instr fixups in OUTLINED_FUNCTION_N
11017 // ...
11018 // bl foo
11019 // restore LR from SP
11020 // ret
11021 //
11022 // Because the code to handle more than one stack fixup does not
11023 // currently have the proper checks for legality, these cases will assert
11024 // in the AArch64 MachineOutliner. This is because the code to do this
11025 // needs more hardening, testing, better checks that generated code is
11026 // legal, etc and because it is only verified to handle a single pass of
11027 // stack fixup.
11028 //
11029 // The assert happens in AArch64InstrInfo::buildOutlinedFrame to catch
11030 // these cases until they are known to be handled. Bugzilla 46767 is
11031 // referenced in comments at the assert site.
11032 //
11033 // To avoid asserting (or generating non-legal code on noassert builds)
11034 // we remove all candidates which would need more than one stack fixup by
11035 // pruning the cases where the candidate has calls while also having no
11036 // available LR and having no available general purpose registers to copy
11037 // LR to (ie one extra stack save/restore).
11038 //
11039 if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) {
11040 erase_if(RepeatedSequenceLocs, [this, &TRI](outliner::Candidate &C) {
11041 auto IsCall = [](const MachineInstr &MI) { return MI.isCall(); };
11042 return (llvm::any_of(C, IsCall)) &&
11043 (!C.isAvailableAcrossAndOutOfSeq(AArch64::LR, TRI) ||
11044 !findRegisterToSaveLRTo(C));
11045 });
11046 }
11047 }
11048
11049 // If we dropped all of the candidates, bail out here.
11050 if (RepeatedSequenceLocs.size() < MinRepeats)
11051 return std::nullopt;
11052 }
11053
11054 // Does every candidate's MBB contain a call? If so, then we might have a call
11055 // in the range.
11056 if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) {
11057 // Check if the range contains a call. These require a save + restore of the
11058 // link register.
11059 outliner::Candidate &FirstCand = RepeatedSequenceLocs[0];
11060 bool ModStackToSaveLR = false;
11061 if (any_of(drop_end(FirstCand),
11062 [](const MachineInstr &MI) { return MI.isCall(); }))
11063 ModStackToSaveLR = true;
11064
11065 // Handle the last instruction separately. If this is a tail call, then the
11066 // last instruction is a call. We don't want to save + restore in this case.
11067 // However, it could be possible that the last instruction is a call without
11068 // it being valid to tail call this sequence. We should consider this as
11069 // well.
11070 else if (FrameID != MachineOutlinerThunk &&
11071 FrameID != MachineOutlinerTailCall && FirstCand.back().isCall())
11072 ModStackToSaveLR = true;
11073
11074 if (ModStackToSaveLR) {
11075 // We can't fix up the stack. Bail out.
11076 if (!AllStackInstrsSafe)
11077 return std::nullopt;
11078
11079 // Save + restore LR.
11080 NumBytesToCreateFrame += 8;
11081
11082 // Add the extra mov if we will save a frame record instead of just LR.
11084 RepeatedSequenceLocs, TRI))
11085 NumBytesToCreateFrame += 4;
11086 }
11087 }
11088
11089 // If we have CFI instructions, we can only outline if the outlined section
11090 // can be a tail call
11091 if (FrameID != MachineOutlinerTailCall && CFICount > 0)
11092 return std::nullopt;
11093
11094 return std::make_unique<outliner::OutlinedFunction>(
11095 RepeatedSequenceLocs, SequenceSize, NumBytesToCreateFrame, FrameID);
11096}
11097
11098void AArch64InstrInfo::mergeOutliningCandidateAttributes(
11099 Function &F, std::vector<outliner::Candidate> &Candidates) const {
11100 // If a bunch of candidates reach this point they must agree on their return
11101 // address signing. It is therefore enough to just consider the signing
11102 // behaviour of one of them
11103 const auto &CFn = Candidates.front().getMF()->getFunction();
11104
11105 if (CFn.hasFnAttribute("ptrauth-returns"))
11106 F.addFnAttr(CFn.getFnAttribute("ptrauth-returns"));
11107 if (CFn.hasFnAttribute("ptrauth-auth-traps"))
11108 F.addFnAttr(CFn.getFnAttribute("ptrauth-auth-traps"));
11109 if (CFn.hasFnAttribute("branch-protection-pauth-lr"))
11110 F.addFnAttr(CFn.getFnAttribute("branch-protection-pauth-lr"));
11111 // Since all candidates belong to the same module, just copy the
11112 // function-level attributes of an arbitrary function.
11113 if (CFn.hasFnAttribute("sign-return-address"))
11114 F.addFnAttr(CFn.getFnAttribute("sign-return-address"));
11115 if (CFn.hasFnAttribute("sign-return-address-key"))
11116 F.addFnAttr(CFn.getFnAttribute("sign-return-address-key"));
11117 // The "sign-return-address-harden" attribute is not included because no
11118 // candidate is supposed to have hardening enabled.
11119 assert(llvm::none_of(Candidates, [](const outliner::Candidate &C) {
11120 return C.getMF()
11121 ->getInfo<AArch64FunctionInfo>()
11122 ->shouldHardenSignReturnAddress();
11123 }));
11124
11125 AArch64GenInstrInfo::mergeOutliningCandidateAttributes(F, Candidates);
11126}
11127
11128bool AArch64InstrInfo::isFunctionSafeToOutlineFrom(
11129 MachineFunction &MF, bool OutlineFromLinkOnceODRs) const {
11131 OutlineFromLinkOnceODRs))
11132 return false;
11133
11134 // Outlining from functions with redzones is unsafe since the outliner may
11135 // modify the stack. Check if hasRedZone is true or unknown; if yes, don't
11136 // outline from it.
11137 AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
11138 if (!AFI || AFI->hasRedZone().value_or(true))
11139 return false;
11140
11141 // FIXME: Determine whether it is safe to outline from functions which contain
11142 // streaming-mode changes. We may need to ensure any smstart/smstop pairs are
11143 // outlined together and ensure it is safe to outline with async unwind info,
11144 // required for saving & restoring VG around calls.
11145 if (AFI->hasStreamingModeChanges())
11146 return false;
11147
11148 // FIXME: Teach the outliner to generate/handle Windows unwind info.
11149 if (MF.usesWindowsUnwindInfo())
11150 return false;
11151
11152 // It's safe to outline from MF.
11153 return true;
11154}
11155
11157AArch64InstrInfo::getOutlinableRanges(MachineBasicBlock &MBB,
11158 unsigned &Flags) const {
11160 "Must track liveness!");
11162 std::pair<MachineBasicBlock::iterator, MachineBasicBlock::iterator>>
11163 Ranges;
11164 // According to the AArch64 Procedure Call Standard, the following are
11165 // undefined on entry/exit from a function call:
11166 //
11167 // * Registers x16, x17, (and thus w16, w17)
11168 // * Condition codes (and thus the NZCV register)
11169 //
11170 // If any of these registers are used inside or live across an outlined
11171 // function, then they may be modified later, either by the compiler or
11172 // some other tool (like the linker).
11173 //
11174 // To avoid outlining in these situations, partition each block into ranges
11175 // where these registers are dead. We will only outline from those ranges.
11176 LiveRegUnits LRU(getRegisterInfo());
11177 auto AreAllUnsafeRegsDead = [&LRU]() {
11178 return LRU.available(AArch64::W16) && LRU.available(AArch64::W17) &&
11179 LRU.available(AArch64::NZCV);
11180 };
11181
11182 // We need to know if LR is live across an outlining boundary later on in
11183 // order to decide how we'll create the outlined call, frame, etc.
11184 //
11185 // It's pretty expensive to check this for *every candidate* within a block.
11186 // That's some potentially n^2 behaviour, since in the worst case, we'd need
11187 // to compute liveness from the end of the block for O(n) candidates within
11188 // the block.
11189 //
11190 // So, to improve the average case, let's keep track of liveness from the end
11191 // of the block to the beginning of *every outlinable range*. If we know that
11192 // LR is available in every range we could outline from, then we know that
11193 // we don't need to check liveness for any candidate within that range.
11194 bool LRAvailableEverywhere = true;
11195 // Compute liveness bottom-up.
11196 LRU.addLiveOuts(MBB);
11197 // Update flags that require info about the entire MBB.
11198 auto UpdateWholeMBBFlags = [&Flags](const MachineInstr &MI) {
11199 if (MI.isCall() && !MI.isTerminator())
11201 };
11202 // Range: [RangeBegin, RangeEnd)
11203 MachineBasicBlock::instr_iterator RangeBegin, RangeEnd;
11204 unsigned RangeLen;
11205 auto CreateNewRangeStartingAt =
11206 [&RangeBegin, &RangeEnd,
11207 &RangeLen](MachineBasicBlock::instr_iterator NewBegin) {
11208 RangeBegin = NewBegin;
11209 RangeEnd = std::next(RangeBegin);
11210 RangeLen = 0;
11211 };
11212 auto SaveRangeIfNonEmpty = [&RangeLen, &Ranges, &RangeBegin, &RangeEnd]() {
11213 // At least one unsafe register is not dead. We do not want to outline at
11214 // this point. If it is long enough to outline from and does not cross a
11215 // bundle boundary, save the range [RangeBegin, RangeEnd).
11216 if (RangeLen <= 1)
11217 return;
11218 if (!RangeBegin.isEnd() && RangeBegin->isBundledWithPred())
11219 return;
11220 if (!RangeEnd.isEnd() && RangeEnd->isBundledWithPred())
11221 return;
11222 Ranges.emplace_back(RangeBegin, RangeEnd);
11223 };
11224 // Find the first point where all unsafe registers are dead.
11225 // FIND: <safe instr> <-- end of first potential range
11226 // SKIP: <unsafe def>
11227 // SKIP: ... everything between ...
11228 // SKIP: <unsafe use>
11229 auto FirstPossibleEndPt = MBB.instr_rbegin();
11230 for (; FirstPossibleEndPt != MBB.instr_rend(); ++FirstPossibleEndPt) {
11231 if (!FirstPossibleEndPt->isDebugInstr())
11232 LRU.stepBackward(*FirstPossibleEndPt);
11233 // Update flags that impact how we outline across the entire block,
11234 // regardless of safety.
11235 UpdateWholeMBBFlags(*FirstPossibleEndPt);
11236 if (AreAllUnsafeRegsDead())
11237 break;
11238 }
11239 // If we exhausted the entire block, we have no safe ranges to outline.
11240 if (FirstPossibleEndPt == MBB.instr_rend())
11241 return Ranges;
11242 // Current range.
11243 CreateNewRangeStartingAt(FirstPossibleEndPt->getIterator());
11244 // StartPt points to the first place where all unsafe registers
11245 // are dead (if there is any such point). Begin partitioning the MBB into
11246 // ranges.
11247 // Pseudo probes are ordinary instructions to the mapper, so only skip debug
11248 // instructions here.
11249 for (auto &MI : instructionsWithoutDebug(FirstPossibleEndPt, MBB.instr_rend(),
11250 /*SkipPseudoOp=*/false)) {
11251 LRU.stepBackward(MI);
11252 UpdateWholeMBBFlags(MI);
11253 if (!AreAllUnsafeRegsDead()) {
11254 SaveRangeIfNonEmpty();
11255 CreateNewRangeStartingAt(MI.getIterator());
11256 continue;
11257 }
11258 LRAvailableEverywhere &= LRU.available(AArch64::LR);
11259 // Pseudo probes count because the mapper treats them as ordinary
11260 // instructions.
11261 RangeBegin = MI.getIterator();
11262 ++RangeLen;
11263 }
11264 // Above loop misses the last (or only) range. If we are still safe, then
11265 // let's save the range.
11266 if (AreAllUnsafeRegsDead())
11267 SaveRangeIfNonEmpty();
11268 if (Ranges.empty())
11269 return Ranges;
11270 // We found the ranges bottom-up. Mapping expects the top-down. Reverse
11271 // the order.
11272 std::reverse(Ranges.begin(), Ranges.end());
11273 // If there is at least one outlinable range where LR is unavailable
11274 // somewhere, remember that.
11275 if (!LRAvailableEverywhere)
11277 return Ranges;
11278}
11279
11281AArch64InstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
11283 unsigned Flags) const {
11284 MachineInstr &MI = *MIT;
11285
11286 // Don't outline anything used for return address signing. The outlined
11287 // function will get signed later if needed
11288 switch (MI.getOpcode()) {
11289 case AArch64::PACM:
11290 case AArch64::PACIASP:
11291 case AArch64::PACIBSP:
11292 case AArch64::PACIASPPC:
11293 case AArch64::PACIBSPPC:
11294 case AArch64::PACNBIASPPC:
11295 case AArch64::PACNBIBSPPC:
11296 case AArch64::AUTIASP:
11297 case AArch64::AUTIBSP:
11298 case AArch64::AUTIASPPCi:
11299 case AArch64::AUTIASPPCr:
11300 case AArch64::AUTIBSPPCi:
11301 case AArch64::AUTIBSPPCr:
11302 case AArch64::RETAA:
11303 case AArch64::RETAB:
11304 case AArch64::RETAASPPCi:
11305 case AArch64::RETAASPPCr:
11306 case AArch64::RETABSPPCi:
11307 case AArch64::RETABSPPCr:
11308 case AArch64::EMITBKEY:
11309 case AArch64::PAUTH_PROLOGUE:
11310 case AArch64::PAUTH_EPILOGUE:
11311 case AArch64::PAUTH_EPILOGUE_ENTRY_SP:
11313 }
11314
11315 // We can only outline these if we will tail call the outlined function, or
11316 // fix up the CFI offsets. Currently, CFI instructions are outlined only if
11317 // in a tail call.
11318 //
11319 // FIXME: If the proper fixups for the offset are implemented, this should be
11320 // possible.
11321 if (MI.isCFIInstruction())
11323
11324 // Is this a terminator for a basic block?
11325 if (MI.isTerminator())
11326 // TargetInstrInfo::getOutliningType has already filtered out anything
11327 // that would break this, so we can allow it here.
11329
11330 // Make sure none of the operands are un-outlinable.
11331 for (const MachineOperand &MOP : MI.operands()) {
11332 // A check preventing CFI indices was here before, but only CFI
11333 // instructions should have those.
11334 assert(!MOP.isCFIIndex());
11335
11336 // If it uses LR or W30 explicitly, then don't touch it.
11337 if (MOP.isReg() && !MOP.isImplicit() &&
11338 (MOP.getReg() == AArch64::LR || MOP.getReg() == AArch64::W30))
11340 }
11341
11342 // Special cases for instructions that can always be outlined, but will fail
11343 // the later tests. e.g, ADRPs, which are PC-relative use LR, but can always
11344 // be outlined because they don't require a *specific* value to be in LR.
11345 if (MI.getOpcode() == AArch64::ADRP)
11347
11348 // If MI is a call we might be able to outline it. We don't want to outline
11349 // any calls that rely on the position of items on the stack. When we outline
11350 // something containing a call, we have to emit a save and restore of LR in
11351 // the outlined function. Currently, this always happens by saving LR to the
11352 // stack. Thus, if we outline, say, half the parameters for a function call
11353 // plus the call, then we'll break the callee's expectations for the layout
11354 // of the stack.
11355 //
11356 // FIXME: Allow calls to functions which construct a stack frame, as long
11357 // as they don't access arguments on the stack.
11358 // FIXME: Figure out some way to analyze functions defined in other modules.
11359 // We should be able to compute the memory usage based on the IR calling
11360 // convention, even if we can't see the definition.
11361 if (MI.isCall()) {
11362 // Get the function associated with the call. Look at each operand and find
11363 // the one that represents the callee and get its name.
11364 const Function *Callee = nullptr;
11365 for (const MachineOperand &MOP : MI.operands()) {
11366 if (MOP.isGlobal()) {
11367 Callee = dyn_cast<Function>(MOP.getGlobal());
11368 break;
11369 }
11370 }
11371
11372 // Never outline calls to mcount. There isn't any rule that would require
11373 // this, but the Linux kernel's "ftrace" feature depends on it.
11374 if (Callee && Callee->getName() == "\01_mcount")
11376
11377 // If we don't know anything about the callee, assume it depends on the
11378 // stack layout of the caller. In that case, it's only legal to outline
11379 // as a tail-call. Explicitly list the call instructions we know about so we
11380 // don't get unexpected results with call pseudo-instructions.
11381 auto UnknownCallOutlineType = outliner::InstrType::Illegal;
11382 if (MI.getOpcode() == AArch64::BLR ||
11383 MI.getOpcode() == AArch64::BLRNoIP || MI.getOpcode() == AArch64::BL)
11384 UnknownCallOutlineType = outliner::InstrType::LegalTerminator;
11385
11386 if (!Callee)
11387 return UnknownCallOutlineType;
11388
11389 // We have a function we have information about. Check it if it's something
11390 // can safely outline.
11391 MachineFunction *CalleeMF = MMI.getMachineFunction(*Callee);
11392
11393 // We don't know what's going on with the callee at all. Don't touch it.
11394 if (!CalleeMF)
11395 return UnknownCallOutlineType;
11396
11397 // Check if we know anything about the callee saves on the function. If we
11398 // don't, then don't touch it, since that implies that we haven't
11399 // computed anything about its stack frame yet.
11400 MachineFrameInfo &MFI = CalleeMF->getFrameInfo();
11401 if (!MFI.isCalleeSavedInfoValid() || MFI.getStackSize() > 0 ||
11402 MFI.getNumObjects() > 0)
11403 return UnknownCallOutlineType;
11404
11405 // At this point, we can say that CalleeMF ought to not pass anything on the
11406 // stack. Therefore, we can outline it.
11408 }
11409
11410 // Don't touch the link register or W30.
11411 if (MI.readsRegister(AArch64::W30, &getRegisterInfo()) ||
11412 MI.modifiesRegister(AArch64::W30, &getRegisterInfo()))
11414
11415 // Don't outline BTI instructions, because that will prevent the outlining
11416 // site from being indirectly callable.
11417 if (hasBTISemantics(MI))
11419
11421}
11422
11423void AArch64InstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const {
11424 for (MachineInstr &MI : MBB) {
11425 const MachineOperand *Base;
11426 TypeSize Width(0, false);
11427 int64_t Offset;
11428 bool OffsetIsScalable;
11429
11430 // Is this a load or store with an immediate offset with SP as the base?
11431 if (MI.mayLoadOrStore() &&
11432 getMemOperandWithOffsetWidth(MI, Base, Offset, OffsetIsScalable,
11433 Width) &&
11434 Base->isReg() && Base->getReg() == AArch64::SP) {
11435 TypeSize Scale(0U, false);
11436 int64_t Dummy1, Dummy2;
11437
11438 MachineOperand &StackOffsetOperand =
11440 assert(StackOffsetOperand.isImm() && "Stack offset wasn't immediate!");
11441 getMemOpInfo(MI.getOpcode(), Scale, Width, Dummy1, Dummy2);
11442 assert(Scale != 0 && "Unexpected opcode!");
11443 assert(!OffsetIsScalable && "Expected offset to be a byte offset");
11444
11445 // We've pushed the return address to the stack, so add 16 to the offset.
11446 // This is safe, since we already checked if it would overflow when we
11447 // checked if this instruction was legal to outline.
11448 int64_t NewImm = (Offset + 16) / (int64_t)Scale.getFixedValue();
11449 StackOffsetOperand.setImm(NewImm);
11450 continue;
11451 }
11452
11453 if (isSPAddSubImm(MI)) {
11454 auto Enc = adjustSPAddSubImm(MI, 16);
11455 assert(Enc && "Unencodable SP add/sub should not have been outlined");
11456 MI.setDesc(get(Enc->Opcode));
11457 MI.getOperand(2).setImm(Enc->Imm);
11458 MI.getOperand(3).setImm(Enc->Shift);
11459 }
11460 }
11461}
11462
11464 const AArch64InstrInfo *TII,
11465 bool ShouldSignReturnAddr) {
11466 if (!ShouldSignReturnAddr)
11467 return;
11468
11469 BuildMI(MBB, MBB.begin(), DebugLoc(), TII->get(AArch64::PAUTH_PROLOGUE))
11471 TII->createPauthEpilogueInstr(MBB, DebugLoc());
11472}
11473
11474void AArch64InstrInfo::buildOutlinedFrame(
11476 const outliner::OutlinedFunction &OF) const {
11477
11478 AArch64FunctionInfo *FI = MF.getInfo<AArch64FunctionInfo>();
11479
11480 if (OF.FrameConstructionID == MachineOutlinerTailCall)
11481 FI->setOutliningStyle("Tail Call");
11482 else if (OF.FrameConstructionID == MachineOutlinerThunk) {
11483 // For thunk outlining, rewrite the last instruction from a call to a
11484 // tail-call.
11485 MachineInstr *Call = &*--MBB.instr_end();
11486 unsigned TailOpcode;
11487 if (Call->getOpcode() == AArch64::BL) {
11488 TailOpcode = AArch64::TCRETURNdi;
11489 } else {
11490 assert(Call->getOpcode() == AArch64::BLR ||
11491 Call->getOpcode() == AArch64::BLRNoIP);
11492 TailOpcode = AArch64::TCRETURNriALL;
11493 }
11494 MachineInstr *TC = BuildMI(MF, DebugLoc(), get(TailOpcode))
11495 .add(Call->getOperand(0))
11496 .addImm(0);
11497 MBB.insert(MBB.end(), TC);
11499
11500 FI->setOutliningStyle("Thunk");
11501 }
11502
11503 bool IsLeafFunction = true;
11504
11505 // Is there a call in the outlined range?
11506 auto IsNonTailCall = [](const MachineInstr &MI) {
11507 return MI.isCall() && !MI.isReturn();
11508 };
11509
11510 if (llvm::any_of(MBB.instrs(), IsNonTailCall)) {
11511 // Fix up the instructions in the range, since we're going to modify the
11512 // stack.
11513
11514 // Bugzilla ID: 46767
11515 // TODO: Check if fixing up twice is safe so we can outline these.
11516 assert(OF.FrameConstructionID != MachineOutlinerDefault &&
11517 "Can only fix up stack references once");
11518 fixupPostOutline(MBB);
11519
11520 IsLeafFunction = false;
11521
11522 // LR has to be a live in so that we can save it.
11523 if (!MBB.isLiveIn(AArch64::LR))
11524 MBB.addLiveIn(AArch64::LR);
11525
11528
11529 if (OF.FrameConstructionID == MachineOutlinerTailCall ||
11530 OF.FrameConstructionID == MachineOutlinerThunk)
11531 Et = std::prev(MBB.end());
11532
11533 // There is a call in the range, so we must save LR. Save it as part of a
11534 // frame record when that gives us a smaller compact unwind encoding.
11536 // FP is saved here, so it must be live-in.
11537 if (!MBB.isLiveIn(AArch64::FP))
11538 MBB.addLiveIn(AArch64::FP);
11539
11540 // stp x29, x30, [sp, #-16]! (the pre-index imm is scaled by 8: -2 * 8)
11541 MachineInstr *STPXpre = BuildMI(MF, DebugLoc(), get(AArch64::STPXpre))
11542 .addReg(AArch64::SP, RegState::Define)
11543 .addReg(AArch64::FP)
11544 .addReg(AArch64::LR)
11545 .addReg(AArch64::SP)
11546 .addImm(-2);
11547 It = MBB.insert(It, STPXpre);
11548
11549 // mov x29, sp (add x29, sp, #0), so x29 points at the frame record.
11550 MachineInstr *SetFP = BuildMI(MF, DebugLoc(), get(AArch64::ADDXri))
11551 .addReg(AArch64::FP, RegState::Define)
11552 .addReg(AArch64::SP)
11553 .addImm(0)
11554 .addImm(0);
11555 MBB.insertAfter(It, SetFP);
11556
11557 // Describe the frame record with FP as the CFA. The encoder needs all
11558 // three to pick FRAME. No need to check for unwind info here: we only
11559 // get here if the function has it.
11560 CFIInstBuilder CFIBuilder(MBB, std::next(SetFP->getIterator()),
11562 CFIBuilder.buildDefCFA(AArch64::FP, 16);
11563 CFIBuilder.buildOffset(AArch64::LR, -8);
11564 CFIBuilder.buildOffset(AArch64::FP, -16);
11565
11566 // ldp x29, x30, [sp], #16
11567 MachineInstr *LDPXpost = BuildMI(MF, DebugLoc(), get(AArch64::LDPXpost))
11568 .addReg(AArch64::SP, RegState::Define)
11569 .addReg(AArch64::FP, RegState::Define)
11570 .addReg(AArch64::LR, RegState::Define)
11571 .addReg(AArch64::SP)
11572 .addImm(2);
11573 Et = MBB.insert(Et, LDPXpost);
11574 } else {
11575 // Insert a save before the outlined region
11576 MachineInstr *STRXpre = BuildMI(MF, DebugLoc(), get(AArch64::STRXpre))
11577 .addReg(AArch64::SP, RegState::Define)
11578 .addReg(AArch64::LR)
11579 .addReg(AArch64::SP)
11580 .addImm(-16);
11581 It = MBB.insert(It, STRXpre);
11582
11583 if (MF.getInfo<AArch64FunctionInfo>()->needsDwarfUnwindInfo(MF)) {
11584 CFIInstBuilder CFIBuilder(MBB, It, MachineInstr::FrameSetup);
11585
11586 // Add a CFI saying the stack was moved 16 B down.
11587 CFIBuilder.buildDefCFAOffset(16);
11588
11589 // Add a CFI saying that the LR that we want to find is now 16 B higher
11590 // than before.
11591 CFIBuilder.buildOffset(AArch64::LR, -16);
11592 }
11593
11594 // Insert a restore before the terminator for the function.
11595 MachineInstr *LDRXpost = BuildMI(MF, DebugLoc(), get(AArch64::LDRXpost))
11596 .addReg(AArch64::SP, RegState::Define)
11597 .addReg(AArch64::LR, RegState::Define)
11598 .addReg(AArch64::SP)
11599 .addImm(16);
11600 Et = MBB.insert(Et, LDRXpost);
11601 }
11602 }
11603
11604 auto RASignCondition = FI->getSignReturnAddressCondition();
11605 bool ShouldSignReturnAddr = AArch64FunctionInfo::shouldSignReturnAddress(
11606 RASignCondition, !IsLeafFunction);
11607
11608 // If this is a tail call outlined function, then there's already a return.
11609 if (OF.FrameConstructionID == MachineOutlinerTailCall ||
11610 OF.FrameConstructionID == MachineOutlinerThunk) {
11611 signOutlinedFunction(MF, MBB, this, ShouldSignReturnAddr);
11612 return;
11613 }
11614
11615 // It's not a tail call, so we have to insert the return ourselves.
11616
11617 // LR has to be a live in so that we can return to it.
11618 if (!MBB.isLiveIn(AArch64::LR))
11619 MBB.addLiveIn(AArch64::LR);
11620
11621 MachineInstr *ret = BuildMI(MF, DebugLoc(), get(AArch64::RET))
11622 .addReg(AArch64::LR);
11623 MBB.insert(MBB.end(), ret);
11624
11625 signOutlinedFunction(MF, MBB, this, ShouldSignReturnAddr);
11626
11627 FI->setOutliningStyle("Function");
11628
11629 // Did we have to modify the stack by saving the link register?
11630 if (OF.FrameConstructionID != MachineOutlinerDefault)
11631 return;
11632
11633 // We modified the stack.
11634 // Walk over the basic block and fix up all the stack accesses.
11635 fixupPostOutline(MBB);
11636}
11637
11638MachineBasicBlock::iterator AArch64InstrInfo::insertOutlinedCall(
11641
11642 // Are we tail calling?
11643 if (C.CallConstructionID == MachineOutlinerTailCall) {
11644 // If yes, then we can just branch to the label.
11645 It = MBB.insert(It, BuildMI(MF, DebugLoc(), get(AArch64::TCRETURNdi))
11646 .addGlobalAddress(M.getNamedValue(MF.getName()))
11647 .addImm(0));
11648 return It;
11649 }
11650
11651 // Are we saving the link register?
11652 if (C.CallConstructionID == MachineOutlinerNoLRSave ||
11653 C.CallConstructionID == MachineOutlinerThunk) {
11654 // No, so just insert the call.
11655 It = MBB.insert(It, BuildMI(MF, DebugLoc(), get(AArch64::BL))
11656 .addGlobalAddress(M.getNamedValue(MF.getName())));
11657 return It;
11658 }
11659
11660 // We want to return the spot where we inserted the call.
11662
11663 // Instructions for saving and restoring LR around the call instruction we're
11664 // going to insert.
11665 MachineInstr *Save;
11666 MachineInstr *Restore;
11667 // Can we save to a register?
11668 if (C.CallConstructionID == MachineOutlinerRegSave) {
11669 // FIXME: This logic should be sunk into a target-specific interface so that
11670 // we don't have to recompute the register.
11671 Register Reg = findRegisterToSaveLRTo(C);
11672 assert(Reg && "No callee-saved register available?");
11673
11674 // LR has to be a live in so that we can save it.
11675 if (!MBB.isLiveIn(AArch64::LR))
11676 MBB.addLiveIn(AArch64::LR);
11677
11678 // Save and restore LR from Reg.
11679 Save = BuildMI(MF, DebugLoc(), get(AArch64::ORRXrs), Reg)
11680 .addReg(AArch64::XZR)
11681 .addReg(AArch64::LR)
11682 .addImm(0);
11683 Restore = BuildMI(MF, DebugLoc(), get(AArch64::ORRXrs), AArch64::LR)
11684 .addReg(AArch64::XZR)
11685 .addReg(Reg)
11686 .addImm(0);
11687 } else {
11688 // We have the default case. Save and restore from SP.
11689 Save = BuildMI(MF, DebugLoc(), get(AArch64::STRXpre))
11690 .addReg(AArch64::SP, RegState::Define)
11691 .addReg(AArch64::LR)
11692 .addReg(AArch64::SP)
11693 .addImm(-16);
11694 Restore = BuildMI(MF, DebugLoc(), get(AArch64::LDRXpost))
11695 .addReg(AArch64::SP, RegState::Define)
11696 .addReg(AArch64::LR, RegState::Define)
11697 .addReg(AArch64::SP)
11698 .addImm(16);
11699 }
11700
11701 It = MBB.insert(It, Save);
11702 It++;
11703
11704 // Insert the call.
11705 It = MBB.insert(It, BuildMI(MF, DebugLoc(), get(AArch64::BL))
11706 .addGlobalAddress(M.getNamedValue(MF.getName())));
11707 CallPt = It;
11708 It++;
11709
11710 It = MBB.insert(It, Restore);
11711 return CallPt;
11712}
11713
11714bool AArch64InstrInfo::shouldOutlineFromFunctionByDefault(
11715 MachineFunction &MF) const {
11716 return MF.getFunction().hasMinSize();
11717}
11718
11719void AArch64InstrInfo::buildClearRegister(Register Reg, MachineBasicBlock &MBB,
11721 DebugLoc &DL,
11722 bool AllowSideEffects) const {
11723 const MachineFunction &MF = *MBB.getParent();
11724 const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
11725 const AArch64RegisterInfo &TRI = *STI.getRegisterInfo();
11726
11727 if (TRI.isGeneralPurposeRegister(MF, Reg)) {
11728 BuildMI(MBB, Iter, DL, get(AArch64::MOVZXi), Reg).addImm(0).addImm(0);
11729 } else if (STI.isSVEorStreamingSVEAvailable()) {
11730 BuildMI(MBB, Iter, DL, get(AArch64::DUP_ZI_D), Reg)
11731 .addImm(0)
11732 .addImm(0);
11733 } else if (STI.isNeonAvailable()) {
11734 BuildMI(MBB, Iter, DL, get(AArch64::MOVIv2d_ns), Reg)
11735 .addImm(0);
11736 } else {
11737 // No Advanced SIMD (streaming-compatible without SVE, or +nosimd), so use
11738 // `fmov d...` instead of `movi v...`; writing `d` also clears the upper
11739 // 64 bits.
11740 assert(STI.hasFPARMv8() && "Expected FP to be available.");
11741 Register Reg64 = TRI.getSubReg(Reg, AArch64::dsub);
11742 BuildMI(MBB, Iter, DL, get(AArch64::FMOVD0), Reg64);
11743 }
11744}
11745
11746std::optional<DestSourcePair>
11748
11749 // AArch64::ORRWrs and AArch64::ORRXrs with WZR/XZR reg
11750 // and zero immediate operands used as an alias for mov instruction.
11751 if ((MI.getOpcode() == AArch64::ORRWrs &&
11752 MI.getOperand(1).getReg() == AArch64::WZR &&
11753 MI.getOperand(3).getImm() == 0x0) ||
11754 (MI.getOpcode() == AArch64::ORRWrr &&
11755 MI.getOperand(1).getReg() == AArch64::WZR)) {
11756 // Check that the w->w move is not a zero-extending w->x mov.
11757 if ((MI.getOperand(0).getReg().isPhysical() &&
11758 MI.findRegisterDefOperandIdx(
11759 getXRegFromWReg(MI.getOperand(0).getReg()),
11760 /*TRI=*/nullptr) == -1) ||
11761 (MI.getOperand(0).getReg().isVirtual() &&
11762 !MI.getOperand(0).getSubReg()))
11763 return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
11764 }
11765
11766 if (MI.getOpcode() == AArch64::ORRXrs &&
11767 MI.getOperand(1).getReg() == AArch64::XZR &&
11768 MI.getOperand(3).getImm() == 0x0)
11769 return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
11770
11771 return std::nullopt;
11772}
11773
11774std::optional<DestSourcePair>
11776 if ((MI.getOpcode() == AArch64::ORRWrs &&
11777 MI.getOperand(1).getReg() == AArch64::WZR &&
11778 MI.getOperand(3).getImm() == 0x0) ||
11779 (MI.getOpcode() == AArch64::ORRWrr &&
11780 MI.getOperand(1).getReg() == AArch64::WZR))
11781 return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
11782 return std::nullopt;
11783}
11784
11785std::optional<RegImmPair>
11786AArch64InstrInfo::isAddImmediate(const MachineInstr &MI, Register Reg) const {
11787 int Sign = 1;
11788 int64_t Offset = 0;
11789
11790 // TODO: Handle cases where Reg is a super- or sub-register of the
11791 // destination register.
11792 const MachineOperand &Op0 = MI.getOperand(0);
11793 if (!Op0.isReg() || Reg != Op0.getReg())
11794 return std::nullopt;
11795
11796 switch (MI.getOpcode()) {
11797 default:
11798 return std::nullopt;
11799 case AArch64::SUBWri:
11800 case AArch64::SUBXri:
11801 case AArch64::SUBSWri:
11802 case AArch64::SUBSXri:
11803 Sign *= -1;
11804 [[fallthrough]];
11805 case AArch64::ADDSWri:
11806 case AArch64::ADDSXri:
11807 case AArch64::ADDWri:
11808 case AArch64::ADDXri: {
11809 // TODO: Third operand can be global address (usually some string).
11810 if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg() ||
11811 !MI.getOperand(2).isImm())
11812 return std::nullopt;
11813 int Shift = MI.getOperand(3).getImm();
11814 assert((Shift == 0 || Shift == 12) && "Shift can be either 0 or 12");
11815 Offset = Sign * (MI.getOperand(2).getImm() << Shift);
11816 }
11817 }
11818 return RegImmPair{MI.getOperand(1).getReg(), Offset};
11819}
11820
11821/// If the given ORR instruction is a copy, and \p DescribedReg overlaps with
11822/// the destination register then, if possible, describe the value in terms of
11823/// the source register.
11824static std::optional<ParamLoadedValue>
11826 const TargetInstrInfo *TII,
11827 const TargetRegisterInfo *TRI) {
11828 auto DestSrc = TII->isCopyLikeInstr(MI);
11829 if (!DestSrc)
11830 return std::nullopt;
11831
11832 Register DestReg = DestSrc->Destination->getReg();
11833 Register SrcReg = DestSrc->Source->getReg();
11834
11835 if (!DestReg.isValid() || !SrcReg.isValid())
11836 return std::nullopt;
11837
11838 auto Expr = DIExpression::get(MI.getMF()->getFunction().getContext(), {});
11839
11840 // If the described register is the destination, just return the source.
11841 if (DestReg == DescribedReg)
11842 return ParamLoadedValue(MachineOperand::CreateReg(SrcReg, false), Expr);
11843
11844 // ORRWrs zero-extends to 64-bits, so we need to consider such cases.
11845 if (MI.getOpcode() == AArch64::ORRWrs &&
11846 TRI->isSuperRegister(DestReg, DescribedReg))
11847 return ParamLoadedValue(MachineOperand::CreateReg(SrcReg, false), Expr);
11848
11849 // We may need to describe the lower part of a ORRXrs move.
11850 if (MI.getOpcode() == AArch64::ORRXrs &&
11851 TRI->isSubRegister(DestReg, DescribedReg)) {
11852 Register SrcSubReg = TRI->getSubReg(SrcReg, AArch64::sub_32);
11853 return ParamLoadedValue(MachineOperand::CreateReg(SrcSubReg, false), Expr);
11854 }
11855
11856 assert(!TRI->isSuperOrSubRegisterEq(DestReg, DescribedReg) &&
11857 "Unhandled ORR[XW]rs copy case");
11858
11859 return std::nullopt;
11860}
11861
11862bool AArch64InstrInfo::isFunctionSafeToSplit(const MachineFunction &MF) const {
11863 // Functions cannot be split to different sections on AArch64 if they have
11864 // a red zone. This is because relaxing a cross-section branch may require
11865 // incrementing the stack pointer to spill a register, which would overwrite
11866 // the red zone.
11867 if (MF.getInfo<AArch64FunctionInfo>()->hasRedZone().value_or(true))
11868 return false;
11869
11871}
11872
11873bool AArch64InstrInfo::isMBBSafeToSplitToCold(
11874 const MachineBasicBlock &MBB) const {
11875 // Asm Goto blocks can contain conditional branches to goto labels, which can
11876 // get moved out of range of the branch instruction.
11877 auto isAsmGoto = [](const MachineInstr &MI) {
11878 return MI.getOpcode() == AArch64::INLINEASM_BR;
11879 };
11880 if (llvm::any_of(MBB, isAsmGoto) || MBB.isInlineAsmBrIndirectTarget())
11881 return false;
11882
11883 // Because jump tables are label-relative instead of table-relative, they all
11884 // must be in the same section or relocation fixup handling will fail.
11885
11886 // Check if MBB is a jump table target
11887 const MachineJumpTableInfo *MJTI = MBB.getParent()->getJumpTableInfo();
11888 auto containsMBB = [&MBB](const MachineJumpTableEntry &JTE) {
11889 return llvm::is_contained(JTE.MBBs, &MBB);
11890 };
11891 if (MJTI != nullptr && llvm::any_of(MJTI->getJumpTables(), containsMBB))
11892 return false;
11893
11894 // Check if MBB contains a jump table lookup
11895 for (const MachineInstr &MI : MBB) {
11896 switch (MI.getOpcode()) {
11897 case TargetOpcode::G_BRJT:
11898 case AArch64::JumpTableDest32:
11899 case AArch64::JumpTableDest16:
11900 case AArch64::JumpTableDest8:
11901 return false;
11902 default:
11903 continue;
11904 }
11905 }
11906
11907 // MBB isn't a special case, so it's safe to be split to the cold section.
11908 return true;
11909}
11910
11911std::optional<ParamLoadedValue>
11912AArch64InstrInfo::describeLoadedValue(const MachineInstr &MI,
11913 Register Reg) const {
11914 const MachineFunction *MF = MI.getMF();
11915 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
11916 switch (MI.getOpcode()) {
11917 case AArch64::MOVZWi:
11918 case AArch64::MOVZXi: {
11919 // MOVZWi may be used for producing zero-extended 32-bit immediates in
11920 // 64-bit parameters, so we need to consider super-registers.
11921 if (!TRI->isSuperRegisterEq(MI.getOperand(0).getReg(), Reg))
11922 return std::nullopt;
11923
11924 if (!MI.getOperand(1).isImm())
11925 return std::nullopt;
11926 int64_t Immediate = MI.getOperand(1).getImm();
11927 int Shift = MI.getOperand(2).getImm();
11928 return ParamLoadedValue(MachineOperand::CreateImm(Immediate << Shift),
11929 nullptr);
11930 }
11931 case AArch64::ORRWrs:
11932 case AArch64::ORRXrs:
11933 return describeORRLoadedValue(MI, Reg, this, TRI);
11934 }
11935
11937}
11938
11939bool AArch64InstrInfo::isExtendLikelyToBeFolded(
11940 MachineInstr &ExtMI, MachineRegisterInfo &MRI) const {
11941 assert(ExtMI.getOpcode() == TargetOpcode::G_SEXT ||
11942 ExtMI.getOpcode() == TargetOpcode::G_ZEXT ||
11943 ExtMI.getOpcode() == TargetOpcode::G_ANYEXT);
11944
11945 // Anyexts are nops.
11946 if (ExtMI.getOpcode() == TargetOpcode::G_ANYEXT)
11947 return true;
11948
11949 Register DefReg = ExtMI.getOperand(0).getReg();
11950 if (!MRI.hasOneNonDBGUse(DefReg))
11951 return false;
11952
11953 // It's likely that a sext/zext as a G_PTR_ADD offset will be folded into an
11954 // addressing mode.
11955 auto *UserMI = &*MRI.use_instr_nodbg_begin(DefReg);
11956 return UserMI->getOpcode() == TargetOpcode::G_PTR_ADD;
11957}
11958
11959uint64_t AArch64InstrInfo::getElementSizeForOpcode(unsigned Opc) const {
11960 return get(Opc).TSFlags & AArch64::ElementSizeMask;
11961}
11962
11963bool AArch64InstrInfo::isPTestLikeOpcode(unsigned Opc) const {
11964 return get(Opc).TSFlags & AArch64::InstrFlagIsPTestLike;
11965}
11966
11967bool AArch64InstrInfo::isWhileOpcode(unsigned Opc) const {
11968 return get(Opc).TSFlags & AArch64::InstrFlagIsWhile;
11969}
11970
11971unsigned int
11972AArch64InstrInfo::getTailDuplicateSize(CodeGenOptLevel OptLevel) const {
11973 return OptLevel >= CodeGenOptLevel::Aggressive ? 6 : 2;
11974}
11975
11976bool AArch64InstrInfo::isLegalAddressingMode(unsigned NumBytes, int64_t Offset,
11977 unsigned Scale) const {
11978 if (Offset && Scale)
11979 return false;
11980
11981 // Check Reg + Imm
11982 if (!Scale) {
11983 // 9-bit signed offset
11984 if (isInt<9>(Offset))
11985 return true;
11986
11987 // 12-bit unsigned offset
11988 unsigned Shift = Log2_64(NumBytes);
11989 if (NumBytes && Offset > 0 && (Offset / NumBytes) <= (1LL << 12) - 1 &&
11990 // Must be a multiple of NumBytes (NumBytes is a power of 2)
11991 (Offset >> Shift) << Shift == Offset)
11992 return true;
11993 return false;
11994 }
11995
11996 // Check reg1 + SIZE_IN_BYTES * reg2 and reg1 + reg2
11997 return Scale == 1 || (Scale > 0 && Scale == NumBytes);
11998}
11999
12001 if (MF.getSubtarget<AArch64Subtarget>().hardenSlsBlr())
12002 return AArch64::BLRNoIP;
12003 else
12004 return AArch64::BLR;
12005}
12006
12008 DebugLoc DL) const {
12009 MachineBasicBlock::iterator InsertPt = MBB.getFirstTerminator();
12010 auto Builder = BuildMI(MBB, InsertPt, DL, get(AArch64::PAUTH_EPILOGUE))
12012
12013 MachineFunction &MF = *MBB.getParent();
12014 const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
12015 auto &AFL = *static_cast<const AArch64FrameLowering *>(
12016 MF.getSubtarget().getFrameLowering());
12017 if (AFL.getArgumentStackToRestore(MF, MBB)) {
12018 Builder.addReg(AArch64::X17, RegState::ImplicitDefine);
12019 Builder.addReg(AArch64::X16, RegState::ImplicitDefine);
12020 if (AFI->branchProtectionPAuthLR())
12021 Builder.addReg(AArch64::X15, RegState::ImplicitDefine);
12022 return;
12023 }
12024
12025 if (AFI->branchProtectionPAuthLR() && !Subtarget.hasPAuthLR())
12026 Builder.addReg(AArch64::X16, RegState::ImplicitDefine);
12027}
12028
12030AArch64InstrInfo::probedStackAlloc(MachineBasicBlock::iterator MBBI,
12031 Register TargetReg, bool FrameSetup) const {
12032 assert(TargetReg != AArch64::SP && "New top of stack cannot already be in SP");
12033
12034 MachineBasicBlock &MBB = *MBBI->getParent();
12035 MachineFunction &MF = *MBB.getParent();
12036 const AArch64InstrInfo *TII =
12037 MF.getSubtarget<AArch64Subtarget>().getInstrInfo();
12038 int64_t ProbeSize = MF.getInfo<AArch64FunctionInfo>()->getStackProbeSize();
12039 DebugLoc DL = MBB.findDebugLoc(MBBI);
12040
12041 MachineFunction::iterator MBBInsertPoint = std::next(MBB.getIterator());
12042 MachineBasicBlock *LoopTestMBB =
12043 MF.CreateMachineBasicBlock(MBB.getBasicBlock());
12044 MF.insert(MBBInsertPoint, LoopTestMBB);
12045 MachineBasicBlock *LoopBodyMBB =
12046 MF.CreateMachineBasicBlock(MBB.getBasicBlock());
12047 MF.insert(MBBInsertPoint, LoopBodyMBB);
12048 MachineBasicBlock *ExitMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
12049 MF.insert(MBBInsertPoint, ExitMBB);
12050 MachineInstr::MIFlag Flags =
12052
12053 // LoopTest:
12054 // SUB SP, SP, #ProbeSize
12055 emitFrameOffset(*LoopTestMBB, LoopTestMBB->end(), DL, AArch64::SP,
12056 AArch64::SP, StackOffset::getFixed(-ProbeSize), TII, Flags);
12057
12058 // CMP SP, TargetReg
12059 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(AArch64::SUBSXrx64),
12060 AArch64::XZR)
12061 .addReg(AArch64::SP)
12062 .addReg(TargetReg)
12064 .setMIFlags(Flags);
12065
12066 // B.<Cond> LoopExit
12067 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(AArch64::Bcc))
12069 .addMBB(ExitMBB)
12070 .setMIFlags(Flags);
12071
12072 // LDR XZR, [SP]
12073 BuildMI(*LoopBodyMBB, LoopBodyMBB->end(), DL, TII->get(AArch64::LDRXui))
12074 .addDef(AArch64::XZR)
12075 .addReg(AArch64::SP)
12076 .addImm(0)
12080 Align(8)))
12081 .setMIFlags(Flags);
12082
12083 // B loop
12084 BuildMI(*LoopBodyMBB, LoopBodyMBB->end(), DL, TII->get(AArch64::B))
12085 .addMBB(LoopTestMBB)
12086 .setMIFlags(Flags);
12087
12088 // LoopExit:
12089 // MOV SP, TargetReg
12090 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(AArch64::ADDXri), AArch64::SP)
12091 .addReg(TargetReg)
12092 .addImm(0)
12094 .setMIFlags(Flags);
12095
12096 // LDR XZR, [SP]
12097 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(AArch64::LDRXui))
12098 .addReg(AArch64::XZR, RegState::Define)
12099 .addReg(AArch64::SP)
12100 .addImm(0)
12101 .setMIFlags(Flags);
12102
12103 ExitMBB->splice(ExitMBB->end(), &MBB, std::next(MBBI), MBB.end());
12105
12106 LoopTestMBB->addSuccessor(ExitMBB);
12107 LoopTestMBB->addSuccessor(LoopBodyMBB);
12108 LoopBodyMBB->addSuccessor(LoopTestMBB);
12109 MBB.addSuccessor(LoopTestMBB);
12110
12111 // Update liveins.
12112 if (MF.getRegInfo().reservedRegsFrozen())
12113 fullyRecomputeLiveIns({ExitMBB, LoopBodyMBB, LoopTestMBB});
12114
12115 return ExitMBB->begin();
12116}
12117
12118namespace {
12119class AArch64PipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo {
12120 MachineFunction *MF;
12121 const TargetInstrInfo *TII;
12122 const TargetRegisterInfo *TRI;
12123 MachineRegisterInfo &MRI;
12124
12125 /// The block of the loop
12126 MachineBasicBlock *LoopBB;
12127 /// The conditional branch of the loop
12128 MachineInstr *CondBranch;
12129 /// The compare instruction for loop control
12130 MachineInstr *Comp;
12131 /// The number of the operand of the loop counter value in Comp
12132 unsigned CompCounterOprNum;
12133 /// The instruction that updates the loop counter value
12134 MachineInstr *Update;
12135 /// The number of the operand of the loop counter value in Update
12136 unsigned UpdateCounterOprNum;
12137 /// The initial value of the loop counter
12138 Register Init;
12139 /// True iff Update is a predecessor of Comp
12140 bool IsUpdatePriorComp;
12141
12142 /// The normalized condition used by createTripCountGreaterCondition()
12143 SmallVector<MachineOperand, 4> Cond;
12144
12145public:
12146 AArch64PipelinerLoopInfo(MachineBasicBlock *LoopBB, MachineInstr *CondBranch,
12147 MachineInstr *Comp, unsigned CompCounterOprNum,
12148 MachineInstr *Update, unsigned UpdateCounterOprNum,
12149 Register Init, bool IsUpdatePriorComp,
12150 const SmallVectorImpl<MachineOperand> &Cond)
12151 : MF(Comp->getParent()->getParent()),
12152 TII(MF->getSubtarget().getInstrInfo()),
12153 TRI(MF->getSubtarget().getRegisterInfo()), MRI(MF->getRegInfo()),
12154 LoopBB(LoopBB), CondBranch(CondBranch), Comp(Comp),
12155 CompCounterOprNum(CompCounterOprNum), Update(Update),
12156 UpdateCounterOprNum(UpdateCounterOprNum), Init(Init),
12157 IsUpdatePriorComp(IsUpdatePriorComp), Cond(Cond.begin(), Cond.end()) {}
12158
12159 bool shouldIgnoreForPipelining(const MachineInstr *MI) const override {
12160 // Make the instructions for loop control be placed in stage 0.
12161 // The predecessors of Comp are considered by the caller.
12162 return MI == Comp;
12163 }
12164
12165 std::optional<bool> createTripCountGreaterCondition(
12166 int TC, MachineBasicBlock &MBB,
12167 SmallVectorImpl<MachineOperand> &CondParam) override {
12168 // A branch instruction will be inserted as "if (Cond) goto epilogue".
12169 // Cond is normalized for such use.
12170 // The predecessors of the branch are assumed to have already been inserted.
12171 CondParam = Cond;
12172 return {};
12173 }
12174
12175 void createRemainingIterationsGreaterCondition(
12176 int TC, MachineBasicBlock &MBB, SmallVectorImpl<MachineOperand> &Cond,
12177 DenseMap<MachineInstr *, MachineInstr *> &LastStage0Insts) override;
12178
12179 void setPreheader(MachineBasicBlock *NewPreheader) override {}
12180
12181 void adjustTripCount(int TripCountAdjust) override {}
12182
12183 bool isMVEExpanderSupported() override { return true; }
12184};
12185} // namespace
12186
12187/// Clone an instruction from MI. The register of ReplaceOprNum-th operand
12188/// is replaced by ReplaceReg. The output register is newly created.
12189/// The other operands are unchanged from MI.
12190static Register cloneInstr(const MachineInstr *MI, unsigned ReplaceOprNum,
12191 Register ReplaceReg, MachineBasicBlock &MBB,
12192 MachineBasicBlock::iterator InsertTo) {
12193 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
12194 const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo();
12195 MachineInstr *NewMI = MBB.getParent()->CloneMachineInstr(MI);
12196 Register Result = 0;
12197 for (unsigned I = 0; I < NewMI->getNumOperands(); ++I) {
12198 if (I == 0 && NewMI->getOperand(0).getReg().isVirtual()) {
12199 Result = MRI.createVirtualRegister(
12200 MRI.getRegClass(NewMI->getOperand(0).getReg()));
12201 NewMI->getOperand(I).setReg(Result);
12202 } else if (I == ReplaceOprNum) {
12203 MRI.constrainRegClass(ReplaceReg, TII->getRegClass(NewMI->getDesc(), I));
12204 NewMI->getOperand(I).setReg(ReplaceReg);
12205 }
12206 }
12207 MBB.insert(InsertTo, NewMI);
12208 return Result;
12209}
12210
12211void AArch64PipelinerLoopInfo::createRemainingIterationsGreaterCondition(
12214 // Create and accumulate conditions for next TC iterations.
12215 // Example:
12216 // SUBSXrr N, counter, implicit-def $nzcv # compare instruction for the last
12217 // # iteration of the kernel
12218 //
12219 // # insert the following instructions
12220 // cond = CSINCXr 0, 0, C, implicit $nzcv
12221 // counter = ADDXri counter, 1 # clone from this->Update
12222 // SUBSXrr n, counter, implicit-def $nzcv # clone from this->Comp
12223 // cond = CSINCXr cond, cond, C, implicit $nzcv
12224 // ... (repeat TC times)
12225 // SUBSXri cond, 0, implicit-def $nzcv
12226
12227 assert(CondBranch->getOpcode() == AArch64::Bcc);
12228 // CondCode to exit the loop
12230 (AArch64CC::CondCode)CondBranch->getOperand(0).getImm();
12231 if (CondBranch->getOperand(1).getMBB() == LoopBB)
12233
12234 // Accumulate conditions to exit the loop
12235 Register AccCond = AArch64::XZR;
12236
12237 // If CC holds, CurCond+1 is returned; otherwise CurCond is returned.
12238 auto AccumulateCond = [&](Register CurCond,
12240 Register NewCond = MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
12241 BuildMI(MBB, MBB.end(), Comp->getDebugLoc(), TII->get(AArch64::CSINCXr))
12242 .addReg(NewCond, RegState::Define)
12243 .addReg(CurCond)
12244 .addReg(CurCond)
12246 return NewCond;
12247 };
12248
12249 if (!LastStage0Insts.empty() && LastStage0Insts[Comp]->getParent() == &MBB) {
12250 // Update and Comp for I==0 are already exists in MBB
12251 // (MBB is an unrolled kernel)
12252 Register Counter;
12253 for (int I = 0; I <= TC; ++I) {
12254 Register NextCounter;
12255 if (I != 0)
12256 NextCounter =
12257 cloneInstr(Comp, CompCounterOprNum, Counter, MBB, MBB.end());
12258
12259 AccCond = AccumulateCond(AccCond, CC);
12260
12261 if (I != TC) {
12262 if (I == 0) {
12263 if (Update != Comp && IsUpdatePriorComp) {
12264 Counter =
12265 LastStage0Insts[Comp]->getOperand(CompCounterOprNum).getReg();
12266 NextCounter = cloneInstr(Update, UpdateCounterOprNum, Counter, MBB,
12267 MBB.end());
12268 } else {
12269 // can use already calculated value
12270 NextCounter = LastStage0Insts[Update]->getOperand(0).getReg();
12271 }
12272 } else if (Update != Comp) {
12273 NextCounter =
12274 cloneInstr(Update, UpdateCounterOprNum, Counter, MBB, MBB.end());
12275 }
12276 }
12277 Counter = NextCounter;
12278 }
12279 } else {
12280 Register Counter;
12281 if (LastStage0Insts.empty()) {
12282 // use initial counter value (testing if the trip count is sufficient to
12283 // be executed by pipelined code)
12284 Counter = Init;
12285 if (IsUpdatePriorComp)
12286 Counter =
12287 cloneInstr(Update, UpdateCounterOprNum, Counter, MBB, MBB.end());
12288 } else {
12289 // MBB is an epilogue block. LastStage0Insts[Comp] is in the kernel block.
12290 Counter = LastStage0Insts[Comp]->getOperand(CompCounterOprNum).getReg();
12291 }
12292
12293 for (int I = 0; I <= TC; ++I) {
12294 Register NextCounter;
12295 NextCounter =
12296 cloneInstr(Comp, CompCounterOprNum, Counter, MBB, MBB.end());
12297 AccCond = AccumulateCond(AccCond, CC);
12298 if (I != TC && Update != Comp)
12299 NextCounter =
12300 cloneInstr(Update, UpdateCounterOprNum, Counter, MBB, MBB.end());
12301 Counter = NextCounter;
12302 }
12303 }
12304
12305 // If AccCond == 0, the remainder is greater than TC.
12306 BuildMI(MBB, MBB.end(), Comp->getDebugLoc(), TII->get(AArch64::SUBSXri))
12307 .addReg(AArch64::XZR, RegState::Define | RegState::Dead)
12308 .addReg(AccCond)
12309 .addImm(0)
12310 .addImm(0);
12311 Cond.clear();
12313}
12314
12315static void extractPhiReg(const MachineInstr &Phi, const MachineBasicBlock *MBB,
12316 Register &RegMBB, Register &RegOther) {
12317 assert(Phi.getNumOperands() == 5);
12318 if (Phi.getOperand(2).getMBB() == MBB) {
12319 RegMBB = Phi.getOperand(1).getReg();
12320 RegOther = Phi.getOperand(3).getReg();
12321 } else {
12322 assert(Phi.getOperand(4).getMBB() == MBB);
12323 RegMBB = Phi.getOperand(3).getReg();
12324 RegOther = Phi.getOperand(1).getReg();
12325 }
12326}
12327
12329 if (!Reg.isVirtual())
12330 return false;
12331 const MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
12332 return MRI.getDefBlock(Reg) != BB;
12333}
12334
12335/// If Reg is an induction variable, return true and set some parameters
12336static bool getIndVarInfo(Register Reg, const MachineBasicBlock *LoopBB,
12337 MachineInstr *&UpdateInst,
12338 unsigned &UpdateCounterOprNum, Register &InitReg,
12339 bool &IsUpdatePriorComp) {
12340 // Example:
12341 //
12342 // Preheader:
12343 // InitReg = ...
12344 // LoopBB:
12345 // Reg0 = PHI (InitReg, Preheader), (Reg1, LoopBB)
12346 // Reg = COPY Reg0 ; COPY is ignored.
12347 // Reg1 = ADD Reg, #1; UpdateInst. Incremented by a loop invariant value.
12348 // ; Reg is the value calculated in the previous
12349 // ; iteration, so IsUpdatePriorComp == false.
12350
12351 if (LoopBB->pred_size() != 2)
12352 return false;
12353 if (!Reg.isVirtual())
12354 return false;
12355 const MachineRegisterInfo &MRI = LoopBB->getParent()->getRegInfo();
12356 UpdateInst = nullptr;
12357 UpdateCounterOprNum = 0;
12358 InitReg = 0;
12359 IsUpdatePriorComp = true;
12360 Register CurReg = Reg;
12361 while (true) {
12362 MachineInstr *Def = MRI.getVRegDef(CurReg);
12363 if (Def->getParent() != LoopBB)
12364 return false;
12365 if (Def->isCopy()) {
12366 // Ignore copy instructions unless they contain subregisters
12367 if (Def->getOperand(0).getSubReg() || Def->getOperand(1).getSubReg())
12368 return false;
12369 CurReg = Def->getOperand(1).getReg();
12370 } else if (Def->isPHI()) {
12371 if (InitReg != 0)
12372 return false;
12373 if (!UpdateInst)
12374 IsUpdatePriorComp = false;
12375 extractPhiReg(*Def, LoopBB, CurReg, InitReg);
12376 } else {
12377 if (UpdateInst)
12378 return false;
12379 switch (Def->getOpcode()) {
12380 case AArch64::ADDSXri:
12381 case AArch64::ADDSWri:
12382 case AArch64::SUBSXri:
12383 case AArch64::SUBSWri:
12384 case AArch64::ADDXri:
12385 case AArch64::ADDWri:
12386 case AArch64::SUBXri:
12387 case AArch64::SUBWri:
12388 UpdateInst = Def;
12389 UpdateCounterOprNum = 1;
12390 break;
12391 case AArch64::ADDSXrr:
12392 case AArch64::ADDSWrr:
12393 case AArch64::SUBSXrr:
12394 case AArch64::SUBSWrr:
12395 case AArch64::ADDXrr:
12396 case AArch64::ADDWrr:
12397 case AArch64::SUBXrr:
12398 case AArch64::SUBWrr:
12399 UpdateInst = Def;
12400 if (isDefinedOutside(Def->getOperand(2).getReg(), LoopBB))
12401 UpdateCounterOprNum = 1;
12402 else if (isDefinedOutside(Def->getOperand(1).getReg(), LoopBB))
12403 UpdateCounterOprNum = 2;
12404 else
12405 return false;
12406 break;
12407 default:
12408 return false;
12409 }
12410 CurReg = Def->getOperand(UpdateCounterOprNum).getReg();
12411 }
12412
12413 if (!CurReg.isVirtual())
12414 return false;
12415 if (Reg == CurReg)
12416 break;
12417 }
12418
12419 if (!UpdateInst)
12420 return false;
12421
12422 return true;
12423}
12424
12425std::unique_ptr<TargetInstrInfo::PipelinerLoopInfo>
12427 // Accept loops that meet the following conditions
12428 // * The conditional branch is BCC
12429 // * The compare instruction is ADDS/SUBS/WHILEXX
12430 // * One operand of the compare is an induction variable and the other is a
12431 // loop invariant value
12432 // * The induction variable is incremented/decremented by a single instruction
12433 // * Does not contain CALL or instructions which have unmodeled side effects
12434
12435 for (MachineInstr &MI : *LoopBB)
12436 if (MI.isCall() || MI.hasUnmodeledSideEffects())
12437 // This instruction may use NZCV, which interferes with the instruction to
12438 // be inserted for loop control.
12439 return nullptr;
12440
12441 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
12443 if (analyzeBranch(*LoopBB, TBB, FBB, Cond))
12444 return nullptr;
12445
12446 // Infinite loops are not supported
12447 if (TBB == LoopBB && FBB == LoopBB)
12448 return nullptr;
12449
12450 // Must be conditional branch
12451 if (TBB != LoopBB && FBB == nullptr)
12452 return nullptr;
12453
12454 assert((TBB == LoopBB || FBB == LoopBB) &&
12455 "The Loop must be a single-basic-block loop");
12456
12457 MachineInstr *CondBranch = &*LoopBB->getFirstTerminator();
12459
12460 if (CondBranch->getOpcode() != AArch64::Bcc)
12461 return nullptr;
12462
12463 // Normalization for createTripCountGreaterCondition()
12464 if (TBB == LoopBB)
12466
12467 MachineInstr *Comp = nullptr;
12468 unsigned CompCounterOprNum = 0;
12469 for (MachineInstr &MI : reverse(*LoopBB)) {
12470 if (MI.modifiesRegister(AArch64::NZCV, &TRI)) {
12471 // Guarantee that the compare is SUBS/ADDS/WHILEXX and that one of the
12472 // operands is a loop invariant value
12473
12474 switch (MI.getOpcode()) {
12475 case AArch64::SUBSXri:
12476 case AArch64::SUBSWri:
12477 case AArch64::ADDSXri:
12478 case AArch64::ADDSWri:
12479 Comp = &MI;
12480 CompCounterOprNum = 1;
12481 break;
12482 case AArch64::ADDSWrr:
12483 case AArch64::ADDSXrr:
12484 case AArch64::SUBSWrr:
12485 case AArch64::SUBSXrr:
12486 Comp = &MI;
12487 break;
12488 default:
12489 if (isWhileOpcode(MI.getOpcode())) {
12490 Comp = &MI;
12491 break;
12492 }
12493 return nullptr;
12494 }
12495
12496 if (CompCounterOprNum == 0) {
12497 if (isDefinedOutside(Comp->getOperand(1).getReg(), LoopBB))
12498 CompCounterOprNum = 2;
12499 else if (isDefinedOutside(Comp->getOperand(2).getReg(), LoopBB))
12500 CompCounterOprNum = 1;
12501 else
12502 return nullptr;
12503 }
12504 break;
12505 }
12506 }
12507 if (!Comp)
12508 return nullptr;
12509
12510 MachineInstr *Update = nullptr;
12511 Register Init;
12512 bool IsUpdatePriorComp;
12513 unsigned UpdateCounterOprNum;
12514 if (!getIndVarInfo(Comp->getOperand(CompCounterOprNum).getReg(), LoopBB,
12515 Update, UpdateCounterOprNum, Init, IsUpdatePriorComp))
12516 return nullptr;
12517
12518 return std::make_unique<AArch64PipelinerLoopInfo>(
12519 LoopBB, CondBranch, Comp, CompCounterOprNum, Update, UpdateCounterOprNum,
12520 Init, IsUpdatePriorComp, Cond);
12521}
12522
12523/// verifyInstruction - Perform target specific instruction verification.
12524bool AArch64InstrInfo::verifyInstruction(const MachineInstr &MI,
12525 StringRef &ErrInfo) const {
12526 // Verify that immediate offsets on load/store instructions are within range.
12527 // Stack objects with an FI operand are excluded as they can be fixed up
12528 // during PEI.
12529 TypeSize Scale(0U, false), Width(0U, false);
12530 int64_t MinOffset, MaxOffset;
12531 if (getMemOpInfo(MI.getOpcode(), Scale, Width, MinOffset, MaxOffset)) {
12532 unsigned ImmIdx = getLoadStoreImmIdx(MI.getOpcode());
12533 if (MI.getOperand(ImmIdx).isImm() && !MI.getOperand(ImmIdx - 1).isFI()) {
12534 int64_t Imm = MI.getOperand(ImmIdx).getImm();
12535 if (Imm < MinOffset || Imm > MaxOffset) {
12536 ErrInfo = "Unexpected immediate on load/store instruction";
12537 return false;
12538 }
12539 }
12540 }
12541
12542 const MCInstrDesc &MCID = MI.getDesc();
12543 for (unsigned Op = 0; Op < MCID.getNumOperands(); Op++) {
12544 const MachineOperand &MO = MI.getOperand(Op);
12545 switch (MCID.operands()[Op].OperandType) {
12547 if (!MO.isImm() || MO.getImm() != 0) {
12548 ErrInfo = "OPERAND_IMPLICIT_IMM_0 should be 0";
12549 return false;
12550 }
12551 break;
12553 if (!MO.isImm() ||
12555 (AArch64_AM::getShiftValue(MO.getImm()) != 8 &&
12556 AArch64_AM::getShiftValue(MO.getImm()) != 16)) {
12557 ErrInfo = "OPERAND_SHIFT_MSL should be msl shift of 8 or 16";
12558 return false;
12559 }
12560 break;
12562 if (!MO.isImm() || (MO.getImm() != 0 && MO.getImm() != 1)) {
12563 ErrInfo = "OPERAND_IMM_UINT1 should be 0 or 1";
12564 return false;
12565 }
12566 break;
12568 if (!MO.isImm() || MO.getImm() <= 0 || MO.getImm() > 16) {
12569 ErrInfo = "OPERAND_IMM_UINT4plus1 should be in the range 1 to 16";
12570 return false;
12571 }
12572 break;
12574 if (!MO.isImm() || !isUInt<5>(MO.getImm())) {
12575 ErrInfo = "OPERAND_IMM_UINT5 should be in the range 0 to 31";
12576 return false;
12577 }
12578 break;
12580 if (!MO.isImm() || !isUInt<8>(MO.getImm())) {
12581 ErrInfo = "OPERAND_IMM_UINT8 should be in the range 0 to 255";
12582 return false;
12583 }
12584 break;
12585 default:
12586 break;
12587 }
12588 }
12589 return true;
12590}
12591
12592#define GET_INSTRINFO_HELPERS
12593#define GET_INSTRMAP_INFO
12594#include "AArch64GenInstrInfo.inc"
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
const AArch64Subtarget & Subtarget
SDValue Pred
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 outliningCandidatesPAuthLRConsensus(const outliner::Candidate &a, const outliner::Candidate &b)
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:479
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,...
AArch64PAuth::AuthCheckMethod getAuthenticatedLRCheckMethod(const MachineFunction &MF) const
Choose a method of checking LR before performing a tail call.
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.
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 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.
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
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
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.