xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- AArch64ExpandPseudoInsts.cpp - Expand pseudo instructions ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a pass that expands pseudo instructions into target
100b57cec5SDimitry Andric // instructions to allow proper scheduling and other late optimizations.  This
110b57cec5SDimitry Andric // pass should be run after register allocation but before the post-regalloc
120b57cec5SDimitry Andric // scheduling pass.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "AArch64ExpandImm.h"
170b57cec5SDimitry Andric #include "AArch64InstrInfo.h"
180b57cec5SDimitry Andric #include "AArch64MachineFunctionInfo.h"
190b57cec5SDimitry Andric #include "AArch64Subtarget.h"
200b57cec5SDimitry Andric #include "MCTargetDesc/AArch64AddressingModes.h"
210b57cec5SDimitry Andric #include "Utils/AArch64BaseInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
24fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
310b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
320b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
330b57cec5SDimitry Andric #include "llvm/Pass.h"
340b57cec5SDimitry Andric #include "llvm/Support/CodeGen.h"
350b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
360b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
3706c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
380b57cec5SDimitry Andric #include <cassert>
390b57cec5SDimitry Andric #include <cstdint>
400b57cec5SDimitry Andric #include <iterator>
410b57cec5SDimitry Andric #include <utility>
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric using namespace llvm;
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric #define AARCH64_EXPAND_PSEUDO_NAME "AArch64 pseudo instruction expansion pass"
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric namespace {
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric class AArch64ExpandPseudo : public MachineFunctionPass {
500b57cec5SDimitry Andric public:
510b57cec5SDimitry Andric   const AArch64InstrInfo *TII;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   static char ID;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   AArch64ExpandPseudo() : MachineFunctionPass(ID) {
560b57cec5SDimitry Andric     initializeAArch64ExpandPseudoPass(*PassRegistry::getPassRegistry());
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &Fn) override;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   StringRef getPassName() const override { return AARCH64_EXPAND_PSEUDO_NAME; }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric private:
640b57cec5SDimitry Andric   bool expandMBB(MachineBasicBlock &MBB);
650b57cec5SDimitry Andric   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
660b57cec5SDimitry Andric                 MachineBasicBlock::iterator &NextMBBI);
675f757f3fSDimitry Andric   bool expandMultiVecPseudo(MachineBasicBlock &MBB,
685f757f3fSDimitry Andric                             MachineBasicBlock::iterator MBBI,
695f757f3fSDimitry Andric                             TargetRegisterClass ContiguousClass,
705f757f3fSDimitry Andric                             TargetRegisterClass StridedClass,
715f757f3fSDimitry Andric                             unsigned ContiguousOpc, unsigned StridedOpc);
720b57cec5SDimitry Andric   bool expandMOVImm(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
730b57cec5SDimitry Andric                     unsigned BitSize);
740b57cec5SDimitry Andric 
755ffd83dbSDimitry Andric   bool expand_DestructiveOp(MachineInstr &MI, MachineBasicBlock &MBB,
765ffd83dbSDimitry Andric                             MachineBasicBlock::iterator MBBI);
770b57cec5SDimitry Andric   bool expandCMP_SWAP(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
780b57cec5SDimitry Andric                       unsigned LdarOp, unsigned StlrOp, unsigned CmpOp,
790b57cec5SDimitry Andric                       unsigned ExtendImm, unsigned ZeroReg,
800b57cec5SDimitry Andric                       MachineBasicBlock::iterator &NextMBBI);
810b57cec5SDimitry Andric   bool expandCMP_SWAP_128(MachineBasicBlock &MBB,
820b57cec5SDimitry Andric                           MachineBasicBlock::iterator MBBI,
830b57cec5SDimitry Andric                           MachineBasicBlock::iterator &NextMBBI);
840b57cec5SDimitry Andric   bool expandSetTagLoop(MachineBasicBlock &MBB,
850b57cec5SDimitry Andric                         MachineBasicBlock::iterator MBBI,
860b57cec5SDimitry Andric                         MachineBasicBlock::iterator &NextMBBI);
875ffd83dbSDimitry Andric   bool expandSVESpillFill(MachineBasicBlock &MBB,
885ffd83dbSDimitry Andric                           MachineBasicBlock::iterator MBBI, unsigned Opc,
895ffd83dbSDimitry Andric                           unsigned N);
90e8d8bef9SDimitry Andric   bool expandCALL_RVMARKER(MachineBasicBlock &MBB,
91e8d8bef9SDimitry Andric                            MachineBasicBlock::iterator MBBI);
923a9a9c0cSDimitry Andric   bool expandCALL_BTI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
93fe6060f1SDimitry Andric   bool expandStoreSwiftAsyncContext(MachineBasicBlock &MBB,
94fe6060f1SDimitry Andric                                     MachineBasicBlock::iterator MBBI);
95bdd1243dSDimitry Andric   MachineBasicBlock *expandRestoreZA(MachineBasicBlock &MBB,
96bdd1243dSDimitry Andric                                      MachineBasicBlock::iterator MBBI);
97bdd1243dSDimitry Andric   MachineBasicBlock *expandCondSMToggle(MachineBasicBlock &MBB,
98bdd1243dSDimitry Andric                                         MachineBasicBlock::iterator MBBI);
990b57cec5SDimitry Andric };
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric } // end anonymous namespace
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric char AArch64ExpandPseudo::ID = 0;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric INITIALIZE_PASS(AArch64ExpandPseudo, "aarch64-expand-pseudo",
1060b57cec5SDimitry Andric                 AARCH64_EXPAND_PSEUDO_NAME, false, false)
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric /// Transfer implicit operands on the pseudo instruction to the
1090b57cec5SDimitry Andric /// instructions created from the expansion.
1100b57cec5SDimitry Andric static void transferImpOps(MachineInstr &OldMI, MachineInstrBuilder &UseMI,
1110b57cec5SDimitry Andric                            MachineInstrBuilder &DefMI) {
1120b57cec5SDimitry Andric   const MCInstrDesc &Desc = OldMI.getDesc();
1134824e7fdSDimitry Andric   for (const MachineOperand &MO :
1144824e7fdSDimitry Andric        llvm::drop_begin(OldMI.operands(), Desc.getNumOperands())) {
1150b57cec5SDimitry Andric     assert(MO.isReg() && MO.getReg());
1160b57cec5SDimitry Andric     if (MO.isUse())
1170b57cec5SDimitry Andric       UseMI.add(MO);
1180b57cec5SDimitry Andric     else
1190b57cec5SDimitry Andric       DefMI.add(MO);
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric /// Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more
1240b57cec5SDimitry Andric /// real move-immediate instructions to synthesize the immediate.
1250b57cec5SDimitry Andric bool AArch64ExpandPseudo::expandMOVImm(MachineBasicBlock &MBB,
1260b57cec5SDimitry Andric                                        MachineBasicBlock::iterator MBBI,
1270b57cec5SDimitry Andric                                        unsigned BitSize) {
1280b57cec5SDimitry Andric   MachineInstr &MI = *MBBI;
1298bcb0991SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
130480093f4SDimitry Andric   uint64_t RenamableState =
131480093f4SDimitry Andric       MI.getOperand(0).isRenamable() ? RegState::Renamable : 0;
1320b57cec5SDimitry Andric   uint64_t Imm = MI.getOperand(1).getImm();
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   if (DstReg == AArch64::XZR || DstReg == AArch64::WZR) {
1350b57cec5SDimitry Andric     // Useless def, and we don't want to risk creating an invalid ORR (which
1360b57cec5SDimitry Andric     // would really write to sp).
1370b57cec5SDimitry Andric     MI.eraseFromParent();
1380b57cec5SDimitry Andric     return true;
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
1420b57cec5SDimitry Andric   AArch64_IMM::expandMOVImm(Imm, BitSize, Insn);
1430b57cec5SDimitry Andric   assert(Insn.size() != 0);
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   SmallVector<MachineInstrBuilder, 4> MIBS;
1460b57cec5SDimitry Andric   for (auto I = Insn.begin(), E = Insn.end(); I != E; ++I) {
1470b57cec5SDimitry Andric     bool LastItem = std::next(I) == E;
1480b57cec5SDimitry Andric     switch (I->Opcode)
1490b57cec5SDimitry Andric     {
1500b57cec5SDimitry Andric     default: llvm_unreachable("unhandled!"); break;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric     case AArch64::ORRWri:
1530b57cec5SDimitry Andric     case AArch64::ORRXri:
15406c3fb27SDimitry Andric       if (I->Op1 == 0) {
1550b57cec5SDimitry Andric         MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
1560b57cec5SDimitry Andric                            .add(MI.getOperand(0))
1570b57cec5SDimitry Andric                            .addReg(BitSize == 32 ? AArch64::WZR : AArch64::XZR)
1580b57cec5SDimitry Andric                            .addImm(I->Op2));
15906c3fb27SDimitry Andric       } else {
16006c3fb27SDimitry Andric         Register DstReg = MI.getOperand(0).getReg();
16106c3fb27SDimitry Andric         bool DstIsDead = MI.getOperand(0).isDead();
16206c3fb27SDimitry Andric         MIBS.push_back(
16306c3fb27SDimitry Andric             BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
16406c3fb27SDimitry Andric                 .addReg(DstReg, RegState::Define |
16506c3fb27SDimitry Andric                                     getDeadRegState(DstIsDead && LastItem) |
16606c3fb27SDimitry Andric                                     RenamableState)
16706c3fb27SDimitry Andric                 .addReg(DstReg)
16806c3fb27SDimitry Andric                 .addImm(I->Op2));
16906c3fb27SDimitry Andric       }
17006c3fb27SDimitry Andric       break;
171*0fca6ea1SDimitry Andric     case AArch64::ORRWrs:
172*0fca6ea1SDimitry Andric     case AArch64::ORRXrs: {
173*0fca6ea1SDimitry Andric       Register DstReg = MI.getOperand(0).getReg();
174*0fca6ea1SDimitry Andric       bool DstIsDead = MI.getOperand(0).isDead();
175*0fca6ea1SDimitry Andric       MIBS.push_back(
176*0fca6ea1SDimitry Andric           BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
177*0fca6ea1SDimitry Andric               .addReg(DstReg, RegState::Define |
178*0fca6ea1SDimitry Andric                                   getDeadRegState(DstIsDead && LastItem) |
179*0fca6ea1SDimitry Andric                                   RenamableState)
180*0fca6ea1SDimitry Andric               .addReg(DstReg)
181*0fca6ea1SDimitry Andric               .addReg(DstReg)
182*0fca6ea1SDimitry Andric               .addImm(I->Op2));
183*0fca6ea1SDimitry Andric     } break;
18406c3fb27SDimitry Andric     case AArch64::ANDXri:
1855f757f3fSDimitry Andric     case AArch64::EORXri:
18606c3fb27SDimitry Andric       if (I->Op1 == 0) {
18706c3fb27SDimitry Andric         MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
18806c3fb27SDimitry Andric                            .add(MI.getOperand(0))
18906c3fb27SDimitry Andric                            .addReg(BitSize == 32 ? AArch64::WZR : AArch64::XZR)
19006c3fb27SDimitry Andric                            .addImm(I->Op2));
19106c3fb27SDimitry Andric       } else {
19206c3fb27SDimitry Andric         Register DstReg = MI.getOperand(0).getReg();
19306c3fb27SDimitry Andric         bool DstIsDead = MI.getOperand(0).isDead();
19406c3fb27SDimitry Andric         MIBS.push_back(
19506c3fb27SDimitry Andric             BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
19606c3fb27SDimitry Andric                 .addReg(DstReg, RegState::Define |
19706c3fb27SDimitry Andric                                     getDeadRegState(DstIsDead && LastItem) |
19806c3fb27SDimitry Andric                                     RenamableState)
19906c3fb27SDimitry Andric                 .addReg(DstReg)
20006c3fb27SDimitry Andric                 .addImm(I->Op2));
20106c3fb27SDimitry Andric       }
2020b57cec5SDimitry Andric       break;
2030b57cec5SDimitry Andric     case AArch64::MOVNWi:
2040b57cec5SDimitry Andric     case AArch64::MOVNXi:
2050b57cec5SDimitry Andric     case AArch64::MOVZWi:
2060b57cec5SDimitry Andric     case AArch64::MOVZXi: {
2070b57cec5SDimitry Andric       bool DstIsDead = MI.getOperand(0).isDead();
2080b57cec5SDimitry Andric       MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
2090b57cec5SDimitry Andric         .addReg(DstReg, RegState::Define |
210480093f4SDimitry Andric                 getDeadRegState(DstIsDead && LastItem) |
211480093f4SDimitry Andric                 RenamableState)
2120b57cec5SDimitry Andric         .addImm(I->Op1)
2130b57cec5SDimitry Andric         .addImm(I->Op2));
2140b57cec5SDimitry Andric       } break;
2150b57cec5SDimitry Andric     case AArch64::MOVKWi:
2160b57cec5SDimitry Andric     case AArch64::MOVKXi: {
2178bcb0991SDimitry Andric       Register DstReg = MI.getOperand(0).getReg();
2180b57cec5SDimitry Andric       bool DstIsDead = MI.getOperand(0).isDead();
2190b57cec5SDimitry Andric       MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
2200b57cec5SDimitry Andric         .addReg(DstReg,
2210b57cec5SDimitry Andric                 RegState::Define |
222480093f4SDimitry Andric                 getDeadRegState(DstIsDead && LastItem) |
223480093f4SDimitry Andric                 RenamableState)
2240b57cec5SDimitry Andric         .addReg(DstReg)
2250b57cec5SDimitry Andric         .addImm(I->Op1)
2260b57cec5SDimitry Andric         .addImm(I->Op2));
2270b57cec5SDimitry Andric       } break;
2280b57cec5SDimitry Andric     }
2290b57cec5SDimitry Andric   }
2300b57cec5SDimitry Andric   transferImpOps(MI, MIBS.front(), MIBS.back());
2310b57cec5SDimitry Andric   MI.eraseFromParent();
2320b57cec5SDimitry Andric   return true;
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric bool AArch64ExpandPseudo::expandCMP_SWAP(
2360b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned LdarOp,
2370b57cec5SDimitry Andric     unsigned StlrOp, unsigned CmpOp, unsigned ExtendImm, unsigned ZeroReg,
2380b57cec5SDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
2390b57cec5SDimitry Andric   MachineInstr &MI = *MBBI;
240bdd1243dSDimitry Andric   MIMetadata MIMD(MI);
2410b57cec5SDimitry Andric   const MachineOperand &Dest = MI.getOperand(0);
2428bcb0991SDimitry Andric   Register StatusReg = MI.getOperand(1).getReg();
2430b57cec5SDimitry Andric   bool StatusDead = MI.getOperand(1).isDead();
2440b57cec5SDimitry Andric   // Duplicating undef operands into 2 instructions does not guarantee the same
2450b57cec5SDimitry Andric   // value on both; However undef should be replaced by xzr anyway.
2460b57cec5SDimitry Andric   assert(!MI.getOperand(2).isUndef() && "cannot handle undef");
2478bcb0991SDimitry Andric   Register AddrReg = MI.getOperand(2).getReg();
2488bcb0991SDimitry Andric   Register DesiredReg = MI.getOperand(3).getReg();
2498bcb0991SDimitry Andric   Register NewReg = MI.getOperand(4).getReg();
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   MachineFunction *MF = MBB.getParent();
2520b57cec5SDimitry Andric   auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
2530b57cec5SDimitry Andric   auto StoreBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
2540b57cec5SDimitry Andric   auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   MF->insert(++MBB.getIterator(), LoadCmpBB);
2570b57cec5SDimitry Andric   MF->insert(++LoadCmpBB->getIterator(), StoreBB);
2580b57cec5SDimitry Andric   MF->insert(++StoreBB->getIterator(), DoneBB);
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   // .Lloadcmp:
2610b57cec5SDimitry Andric   //     mov wStatus, 0
2620b57cec5SDimitry Andric   //     ldaxr xDest, [xAddr]
2630b57cec5SDimitry Andric   //     cmp xDest, xDesired
2640b57cec5SDimitry Andric   //     b.ne .Ldone
2650b57cec5SDimitry Andric   if (!StatusDead)
266bdd1243dSDimitry Andric     BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::MOVZWi), StatusReg)
2670b57cec5SDimitry Andric       .addImm(0).addImm(0);
268bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(LdarOp), Dest.getReg())
2690b57cec5SDimitry Andric       .addReg(AddrReg);
270bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(CmpOp), ZeroReg)
2710b57cec5SDimitry Andric       .addReg(Dest.getReg(), getKillRegState(Dest.isDead()))
2720b57cec5SDimitry Andric       .addReg(DesiredReg)
2730b57cec5SDimitry Andric       .addImm(ExtendImm);
274bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::Bcc))
2750b57cec5SDimitry Andric       .addImm(AArch64CC::NE)
2760b57cec5SDimitry Andric       .addMBB(DoneBB)
2770b57cec5SDimitry Andric       .addReg(AArch64::NZCV, RegState::Implicit | RegState::Kill);
2780b57cec5SDimitry Andric   LoadCmpBB->addSuccessor(DoneBB);
2790b57cec5SDimitry Andric   LoadCmpBB->addSuccessor(StoreBB);
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   // .Lstore:
2820b57cec5SDimitry Andric   //     stlxr wStatus, xNew, [xAddr]
2830b57cec5SDimitry Andric   //     cbnz wStatus, .Lloadcmp
284bdd1243dSDimitry Andric   BuildMI(StoreBB, MIMD, TII->get(StlrOp), StatusReg)
2850b57cec5SDimitry Andric       .addReg(NewReg)
2860b57cec5SDimitry Andric       .addReg(AddrReg);
287bdd1243dSDimitry Andric   BuildMI(StoreBB, MIMD, TII->get(AArch64::CBNZW))
2880b57cec5SDimitry Andric       .addReg(StatusReg, getKillRegState(StatusDead))
2890b57cec5SDimitry Andric       .addMBB(LoadCmpBB);
2900b57cec5SDimitry Andric   StoreBB->addSuccessor(LoadCmpBB);
2910b57cec5SDimitry Andric   StoreBB->addSuccessor(DoneBB);
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
2940b57cec5SDimitry Andric   DoneBB->transferSuccessors(&MBB);
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric   MBB.addSuccessor(LoadCmpBB);
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric   NextMBBI = MBB.end();
2990b57cec5SDimitry Andric   MI.eraseFromParent();
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   // Recompute livein lists.
3020b57cec5SDimitry Andric   LivePhysRegs LiveRegs;
3030b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneBB);
3040b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *StoreBB);
3050b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
3060b57cec5SDimitry Andric   // Do an extra pass around the loop to get loop carried registers right.
3070b57cec5SDimitry Andric   StoreBB->clearLiveIns();
3080b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *StoreBB);
3090b57cec5SDimitry Andric   LoadCmpBB->clearLiveIns();
3100b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   return true;
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric bool AArch64ExpandPseudo::expandCMP_SWAP_128(
3160b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
3170b57cec5SDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
3180b57cec5SDimitry Andric   MachineInstr &MI = *MBBI;
319bdd1243dSDimitry Andric   MIMetadata MIMD(MI);
3200b57cec5SDimitry Andric   MachineOperand &DestLo = MI.getOperand(0);
3210b57cec5SDimitry Andric   MachineOperand &DestHi = MI.getOperand(1);
3228bcb0991SDimitry Andric   Register StatusReg = MI.getOperand(2).getReg();
3230b57cec5SDimitry Andric   bool StatusDead = MI.getOperand(2).isDead();
3240b57cec5SDimitry Andric   // Duplicating undef operands into 2 instructions does not guarantee the same
3250b57cec5SDimitry Andric   // value on both; However undef should be replaced by xzr anyway.
3260b57cec5SDimitry Andric   assert(!MI.getOperand(3).isUndef() && "cannot handle undef");
3278bcb0991SDimitry Andric   Register AddrReg = MI.getOperand(3).getReg();
3288bcb0991SDimitry Andric   Register DesiredLoReg = MI.getOperand(4).getReg();
3298bcb0991SDimitry Andric   Register DesiredHiReg = MI.getOperand(5).getReg();
3308bcb0991SDimitry Andric   Register NewLoReg = MI.getOperand(6).getReg();
3318bcb0991SDimitry Andric   Register NewHiReg = MI.getOperand(7).getReg();
3320b57cec5SDimitry Andric 
333fe6060f1SDimitry Andric   unsigned LdxpOp, StxpOp;
334fe6060f1SDimitry Andric 
335fe6060f1SDimitry Andric   switch (MI.getOpcode()) {
336fe6060f1SDimitry Andric   case AArch64::CMP_SWAP_128_MONOTONIC:
337fe6060f1SDimitry Andric     LdxpOp = AArch64::LDXPX;
338fe6060f1SDimitry Andric     StxpOp = AArch64::STXPX;
339fe6060f1SDimitry Andric     break;
340fe6060f1SDimitry Andric   case AArch64::CMP_SWAP_128_RELEASE:
341fe6060f1SDimitry Andric     LdxpOp = AArch64::LDXPX;
342fe6060f1SDimitry Andric     StxpOp = AArch64::STLXPX;
343fe6060f1SDimitry Andric     break;
344fe6060f1SDimitry Andric   case AArch64::CMP_SWAP_128_ACQUIRE:
345fe6060f1SDimitry Andric     LdxpOp = AArch64::LDAXPX;
346fe6060f1SDimitry Andric     StxpOp = AArch64::STXPX;
347fe6060f1SDimitry Andric     break;
348fe6060f1SDimitry Andric   case AArch64::CMP_SWAP_128:
349fe6060f1SDimitry Andric     LdxpOp = AArch64::LDAXPX;
350fe6060f1SDimitry Andric     StxpOp = AArch64::STLXPX;
351fe6060f1SDimitry Andric     break;
352fe6060f1SDimitry Andric   default:
353fe6060f1SDimitry Andric     llvm_unreachable("Unexpected opcode");
354fe6060f1SDimitry Andric   }
355fe6060f1SDimitry Andric 
3560b57cec5SDimitry Andric   MachineFunction *MF = MBB.getParent();
3570b57cec5SDimitry Andric   auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
3580b57cec5SDimitry Andric   auto StoreBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
359fe6060f1SDimitry Andric   auto FailBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
3600b57cec5SDimitry Andric   auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric   MF->insert(++MBB.getIterator(), LoadCmpBB);
3630b57cec5SDimitry Andric   MF->insert(++LoadCmpBB->getIterator(), StoreBB);
364fe6060f1SDimitry Andric   MF->insert(++StoreBB->getIterator(), FailBB);
365fe6060f1SDimitry Andric   MF->insert(++FailBB->getIterator(), DoneBB);
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric   // .Lloadcmp:
3680b57cec5SDimitry Andric   //     ldaxp xDestLo, xDestHi, [xAddr]
3690b57cec5SDimitry Andric   //     cmp xDestLo, xDesiredLo
3700b57cec5SDimitry Andric   //     sbcs xDestHi, xDesiredHi
3710b57cec5SDimitry Andric   //     b.ne .Ldone
372bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(LdxpOp))
3730b57cec5SDimitry Andric       .addReg(DestLo.getReg(), RegState::Define)
3740b57cec5SDimitry Andric       .addReg(DestHi.getReg(), RegState::Define)
3750b57cec5SDimitry Andric       .addReg(AddrReg);
376bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::SUBSXrs), AArch64::XZR)
3770b57cec5SDimitry Andric       .addReg(DestLo.getReg(), getKillRegState(DestLo.isDead()))
3780b57cec5SDimitry Andric       .addReg(DesiredLoReg)
3790b57cec5SDimitry Andric       .addImm(0);
380bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CSINCWr), StatusReg)
3810b57cec5SDimitry Andric     .addUse(AArch64::WZR)
3820b57cec5SDimitry Andric     .addUse(AArch64::WZR)
3830b57cec5SDimitry Andric     .addImm(AArch64CC::EQ);
384bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::SUBSXrs), AArch64::XZR)
3850b57cec5SDimitry Andric       .addReg(DestHi.getReg(), getKillRegState(DestHi.isDead()))
3860b57cec5SDimitry Andric       .addReg(DesiredHiReg)
3870b57cec5SDimitry Andric       .addImm(0);
388bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CSINCWr), StatusReg)
3890b57cec5SDimitry Andric       .addUse(StatusReg, RegState::Kill)
3900b57cec5SDimitry Andric       .addUse(StatusReg, RegState::Kill)
3910b57cec5SDimitry Andric       .addImm(AArch64CC::EQ);
392bdd1243dSDimitry Andric   BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CBNZW))
3930b57cec5SDimitry Andric       .addUse(StatusReg, getKillRegState(StatusDead))
394fe6060f1SDimitry Andric       .addMBB(FailBB);
395fe6060f1SDimitry Andric   LoadCmpBB->addSuccessor(FailBB);
3960b57cec5SDimitry Andric   LoadCmpBB->addSuccessor(StoreBB);
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   // .Lstore:
3990b57cec5SDimitry Andric   //     stlxp wStatus, xNewLo, xNewHi, [xAddr]
4000b57cec5SDimitry Andric   //     cbnz wStatus, .Lloadcmp
401bdd1243dSDimitry Andric   BuildMI(StoreBB, MIMD, TII->get(StxpOp), StatusReg)
4020b57cec5SDimitry Andric       .addReg(NewLoReg)
4030b57cec5SDimitry Andric       .addReg(NewHiReg)
4040b57cec5SDimitry Andric       .addReg(AddrReg);
405bdd1243dSDimitry Andric   BuildMI(StoreBB, MIMD, TII->get(AArch64::CBNZW))
4060b57cec5SDimitry Andric       .addReg(StatusReg, getKillRegState(StatusDead))
4070b57cec5SDimitry Andric       .addMBB(LoadCmpBB);
408bdd1243dSDimitry Andric   BuildMI(StoreBB, MIMD, TII->get(AArch64::B)).addMBB(DoneBB);
4090b57cec5SDimitry Andric   StoreBB->addSuccessor(LoadCmpBB);
4100b57cec5SDimitry Andric   StoreBB->addSuccessor(DoneBB);
4110b57cec5SDimitry Andric 
412fe6060f1SDimitry Andric   // .Lfail:
413fe6060f1SDimitry Andric   //     stlxp wStatus, xDestLo, xDestHi, [xAddr]
414fe6060f1SDimitry Andric   //     cbnz wStatus, .Lloadcmp
415bdd1243dSDimitry Andric   BuildMI(FailBB, MIMD, TII->get(StxpOp), StatusReg)
416fe6060f1SDimitry Andric       .addReg(DestLo.getReg())
417fe6060f1SDimitry Andric       .addReg(DestHi.getReg())
418fe6060f1SDimitry Andric       .addReg(AddrReg);
419bdd1243dSDimitry Andric   BuildMI(FailBB, MIMD, TII->get(AArch64::CBNZW))
420fe6060f1SDimitry Andric       .addReg(StatusReg, getKillRegState(StatusDead))
421fe6060f1SDimitry Andric       .addMBB(LoadCmpBB);
422fe6060f1SDimitry Andric   FailBB->addSuccessor(LoadCmpBB);
423fe6060f1SDimitry Andric   FailBB->addSuccessor(DoneBB);
424fe6060f1SDimitry Andric 
4250b57cec5SDimitry Andric   DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
4260b57cec5SDimitry Andric   DoneBB->transferSuccessors(&MBB);
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   MBB.addSuccessor(LoadCmpBB);
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric   NextMBBI = MBB.end();
4310b57cec5SDimitry Andric   MI.eraseFromParent();
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric   // Recompute liveness bottom up.
4340b57cec5SDimitry Andric   LivePhysRegs LiveRegs;
4350b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneBB);
436fe6060f1SDimitry Andric   computeAndAddLiveIns(LiveRegs, *FailBB);
4370b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *StoreBB);
4380b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
439fe6060f1SDimitry Andric 
4400b57cec5SDimitry Andric   // Do an extra pass in the loop to get the loop carried dependencies right.
441fe6060f1SDimitry Andric   FailBB->clearLiveIns();
442fe6060f1SDimitry Andric   computeAndAddLiveIns(LiveRegs, *FailBB);
4430b57cec5SDimitry Andric   StoreBB->clearLiveIns();
4440b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *StoreBB);
4450b57cec5SDimitry Andric   LoadCmpBB->clearLiveIns();
4460b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   return true;
4490b57cec5SDimitry Andric }
4500b57cec5SDimitry Andric 
4515ffd83dbSDimitry Andric /// \brief Expand Pseudos to Instructions with destructive operands.
4525ffd83dbSDimitry Andric ///
4535ffd83dbSDimitry Andric /// This mechanism uses MOVPRFX instructions for zeroing the false lanes
4545ffd83dbSDimitry Andric /// or for fixing relaxed register allocation conditions to comply with
4555ffd83dbSDimitry Andric /// the instructions register constraints. The latter case may be cheaper
4565ffd83dbSDimitry Andric /// than setting the register constraints in the register allocator,
4575ffd83dbSDimitry Andric /// since that will insert regular MOV instructions rather than MOVPRFX.
4585ffd83dbSDimitry Andric ///
4595ffd83dbSDimitry Andric /// Example (after register allocation):
4605ffd83dbSDimitry Andric ///
4615ffd83dbSDimitry Andric ///   FSUB_ZPZZ_ZERO_B Z0, Pg, Z1, Z0
4625ffd83dbSDimitry Andric ///
4635ffd83dbSDimitry Andric /// * The Pseudo FSUB_ZPZZ_ZERO_B maps to FSUB_ZPmZ_B.
4645ffd83dbSDimitry Andric /// * We cannot map directly to FSUB_ZPmZ_B because the register
4655ffd83dbSDimitry Andric ///   constraints of the instruction are not met.
4665ffd83dbSDimitry Andric /// * Also the _ZERO specifies the false lanes need to be zeroed.
4675ffd83dbSDimitry Andric ///
4685ffd83dbSDimitry Andric /// We first try to see if the destructive operand == result operand,
4695ffd83dbSDimitry Andric /// if not, we try to swap the operands, e.g.
4705ffd83dbSDimitry Andric ///
4715ffd83dbSDimitry Andric ///   FSUB_ZPmZ_B  Z0, Pg/m, Z0, Z1
4725ffd83dbSDimitry Andric ///
4735ffd83dbSDimitry Andric /// But because FSUB_ZPmZ is not commutative, this is semantically
4745ffd83dbSDimitry Andric /// different, so we need a reverse instruction:
4755ffd83dbSDimitry Andric ///
4765ffd83dbSDimitry Andric ///   FSUBR_ZPmZ_B  Z0, Pg/m, Z0, Z1
4775ffd83dbSDimitry Andric ///
4785ffd83dbSDimitry Andric /// Then we implement the zeroing of the false lanes of Z0 by adding
4795ffd83dbSDimitry Andric /// a zeroing MOVPRFX instruction:
4805ffd83dbSDimitry Andric ///
4815ffd83dbSDimitry Andric ///   MOVPRFX_ZPzZ_B Z0, Pg/z, Z0
4825ffd83dbSDimitry Andric ///   FSUBR_ZPmZ_B   Z0, Pg/m, Z0, Z1
4835ffd83dbSDimitry Andric ///
4845ffd83dbSDimitry Andric /// Note that this can only be done for _ZERO or _UNDEF variants where
4855ffd83dbSDimitry Andric /// we can guarantee the false lanes to be zeroed (by implementing this)
4865ffd83dbSDimitry Andric /// or that they are undef (don't care / not used), otherwise the
4875ffd83dbSDimitry Andric /// swapping of operands is illegal because the operation is not
4885ffd83dbSDimitry Andric /// (or cannot be emulated to be) fully commutative.
4895ffd83dbSDimitry Andric bool AArch64ExpandPseudo::expand_DestructiveOp(
4905ffd83dbSDimitry Andric                             MachineInstr &MI,
4915ffd83dbSDimitry Andric                             MachineBasicBlock &MBB,
4925ffd83dbSDimitry Andric                             MachineBasicBlock::iterator MBBI) {
4935ffd83dbSDimitry Andric   unsigned Opcode = AArch64::getSVEPseudoMap(MI.getOpcode());
4945ffd83dbSDimitry Andric   uint64_t DType = TII->get(Opcode).TSFlags & AArch64::DestructiveInstTypeMask;
4955ffd83dbSDimitry Andric   uint64_t FalseLanes = MI.getDesc().TSFlags & AArch64::FalseLanesMask;
4965ffd83dbSDimitry Andric   bool FalseZero = FalseLanes == AArch64::FalseLanesZero;
49704eeddc0SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
4985ffd83dbSDimitry Andric   bool DstIsDead = MI.getOperand(0).isDead();
4995ffd83dbSDimitry Andric   bool UseRev = false;
500fe6060f1SDimitry Andric   unsigned PredIdx, DOPIdx, SrcIdx, Src2Idx;
501bdd1243dSDimitry Andric 
5025ffd83dbSDimitry Andric   switch (DType) {
5035ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryComm:
5045ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryCommWithRev:
5055ffd83dbSDimitry Andric     if (DstReg == MI.getOperand(3).getReg()) {
5065ffd83dbSDimitry Andric       // FSUB Zd, Pg, Zs1, Zd  ==> FSUBR   Zd, Pg/m, Zd, Zs1
5075ffd83dbSDimitry Andric       std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(1, 3, 2);
5085ffd83dbSDimitry Andric       UseRev = true;
5095ffd83dbSDimitry Andric       break;
5105ffd83dbSDimitry Andric     }
511bdd1243dSDimitry Andric     [[fallthrough]];
5125ffd83dbSDimitry Andric   case AArch64::DestructiveBinary:
5135ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryImm:
5145ffd83dbSDimitry Andric     std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(1, 2, 3);
5155ffd83dbSDimitry Andric     break;
516fe6060f1SDimitry Andric   case AArch64::DestructiveUnaryPassthru:
517fe6060f1SDimitry Andric     std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(2, 3, 3);
518fe6060f1SDimitry Andric     break;
519fe6060f1SDimitry Andric   case AArch64::DestructiveTernaryCommWithRev:
520fe6060f1SDimitry Andric     std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 2, 3, 4);
521fe6060f1SDimitry Andric     if (DstReg == MI.getOperand(3).getReg()) {
522fe6060f1SDimitry Andric       // FMLA Zd, Pg, Za, Zd, Zm ==> FMAD Zdn, Pg, Zm, Za
523fe6060f1SDimitry Andric       std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 3, 4, 2);
524fe6060f1SDimitry Andric       UseRev = true;
525fe6060f1SDimitry Andric     } else if (DstReg == MI.getOperand(4).getReg()) {
526fe6060f1SDimitry Andric       // FMLA Zd, Pg, Za, Zm, Zd ==> FMAD Zdn, Pg, Zm, Za
527fe6060f1SDimitry Andric       std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 4, 3, 2);
528fe6060f1SDimitry Andric       UseRev = true;
529fe6060f1SDimitry Andric     }
530fe6060f1SDimitry Andric     break;
5315ffd83dbSDimitry Andric   default:
5325ffd83dbSDimitry Andric     llvm_unreachable("Unsupported Destructive Operand type");
5335ffd83dbSDimitry Andric   }
5345ffd83dbSDimitry Andric 
5355ffd83dbSDimitry Andric   // MOVPRFX can only be used if the destination operand
5365ffd83dbSDimitry Andric   // is the destructive operand, not as any other operand,
5375ffd83dbSDimitry Andric   // so the Destructive Operand must be unique.
5385ffd83dbSDimitry Andric   bool DOPRegIsUnique = false;
5395ffd83dbSDimitry Andric   switch (DType) {
540bdd1243dSDimitry Andric   case AArch64::DestructiveBinary:
541bdd1243dSDimitry Andric     DOPRegIsUnique = DstReg != MI.getOperand(SrcIdx).getReg();
542bdd1243dSDimitry Andric     break;
5435ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryComm:
5445ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryCommWithRev:
5455ffd83dbSDimitry Andric     DOPRegIsUnique =
5465ffd83dbSDimitry Andric       DstReg != MI.getOperand(DOPIdx).getReg() ||
5475ffd83dbSDimitry Andric       MI.getOperand(DOPIdx).getReg() != MI.getOperand(SrcIdx).getReg();
5485ffd83dbSDimitry Andric     break;
549fe6060f1SDimitry Andric   case AArch64::DestructiveUnaryPassthru:
5505ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryImm:
5515ffd83dbSDimitry Andric     DOPRegIsUnique = true;
5525ffd83dbSDimitry Andric     break;
553fe6060f1SDimitry Andric   case AArch64::DestructiveTernaryCommWithRev:
554fe6060f1SDimitry Andric     DOPRegIsUnique =
555fe6060f1SDimitry Andric         DstReg != MI.getOperand(DOPIdx).getReg() ||
556fe6060f1SDimitry Andric         (MI.getOperand(DOPIdx).getReg() != MI.getOperand(SrcIdx).getReg() &&
557fe6060f1SDimitry Andric          MI.getOperand(DOPIdx).getReg() != MI.getOperand(Src2Idx).getReg());
558fe6060f1SDimitry Andric     break;
5595ffd83dbSDimitry Andric   }
5605ffd83dbSDimitry Andric 
5615ffd83dbSDimitry Andric   // Resolve the reverse opcode
5625ffd83dbSDimitry Andric   if (UseRev) {
5635ffd83dbSDimitry Andric     int NewOpcode;
5645ffd83dbSDimitry Andric     // e.g. DIV -> DIVR
5655ffd83dbSDimitry Andric     if ((NewOpcode = AArch64::getSVERevInstr(Opcode)) != -1)
5665ffd83dbSDimitry Andric       Opcode = NewOpcode;
5675ffd83dbSDimitry Andric     // e.g. DIVR -> DIV
5685ffd83dbSDimitry Andric     else if ((NewOpcode = AArch64::getSVENonRevInstr(Opcode)) != -1)
5695ffd83dbSDimitry Andric       Opcode = NewOpcode;
5705ffd83dbSDimitry Andric   }
5715ffd83dbSDimitry Andric 
5725ffd83dbSDimitry Andric   // Get the right MOVPRFX
5735ffd83dbSDimitry Andric   uint64_t ElementSize = TII->getElementSizeForOpcode(Opcode);
574bdd1243dSDimitry Andric   unsigned MovPrfx, LSLZero, MovPrfxZero;
5755ffd83dbSDimitry Andric   switch (ElementSize) {
5765ffd83dbSDimitry Andric   case AArch64::ElementSizeNone:
5775ffd83dbSDimitry Andric   case AArch64::ElementSizeB:
5785ffd83dbSDimitry Andric     MovPrfx = AArch64::MOVPRFX_ZZ;
579bdd1243dSDimitry Andric     LSLZero = AArch64::LSL_ZPmI_B;
5805ffd83dbSDimitry Andric     MovPrfxZero = AArch64::MOVPRFX_ZPzZ_B;
5815ffd83dbSDimitry Andric     break;
5825ffd83dbSDimitry Andric   case AArch64::ElementSizeH:
5835ffd83dbSDimitry Andric     MovPrfx = AArch64::MOVPRFX_ZZ;
584bdd1243dSDimitry Andric     LSLZero = AArch64::LSL_ZPmI_H;
5855ffd83dbSDimitry Andric     MovPrfxZero = AArch64::MOVPRFX_ZPzZ_H;
5865ffd83dbSDimitry Andric     break;
5875ffd83dbSDimitry Andric   case AArch64::ElementSizeS:
5885ffd83dbSDimitry Andric     MovPrfx = AArch64::MOVPRFX_ZZ;
589bdd1243dSDimitry Andric     LSLZero = AArch64::LSL_ZPmI_S;
5905ffd83dbSDimitry Andric     MovPrfxZero = AArch64::MOVPRFX_ZPzZ_S;
5915ffd83dbSDimitry Andric     break;
5925ffd83dbSDimitry Andric   case AArch64::ElementSizeD:
5935ffd83dbSDimitry Andric     MovPrfx = AArch64::MOVPRFX_ZZ;
594bdd1243dSDimitry Andric     LSLZero = AArch64::LSL_ZPmI_D;
5955ffd83dbSDimitry Andric     MovPrfxZero = AArch64::MOVPRFX_ZPzZ_D;
5965ffd83dbSDimitry Andric     break;
5975ffd83dbSDimitry Andric   default:
5985ffd83dbSDimitry Andric     llvm_unreachable("Unsupported ElementSize");
5995ffd83dbSDimitry Andric   }
6005ffd83dbSDimitry Andric 
6015ffd83dbSDimitry Andric   //
6025ffd83dbSDimitry Andric   // Create the destructive operation (if required)
6035ffd83dbSDimitry Andric   //
6045ffd83dbSDimitry Andric   MachineInstrBuilder PRFX, DOP;
6055ffd83dbSDimitry Andric   if (FalseZero) {
606bdd1243dSDimitry Andric     // If we cannot prefix the requested instruction we'll instead emit a
607bdd1243dSDimitry Andric     // prefixed_zeroing_mov for DestructiveBinary.
608bdd1243dSDimitry Andric     assert((DOPRegIsUnique || DType == AArch64::DestructiveBinary ||
60906c3fb27SDimitry Andric             DType == AArch64::DestructiveBinaryComm ||
61006c3fb27SDimitry Andric             DType == AArch64::DestructiveBinaryCommWithRev) &&
611bdd1243dSDimitry Andric            "The destructive operand should be unique");
6125ffd83dbSDimitry Andric     assert(ElementSize != AArch64::ElementSizeNone &&
6135ffd83dbSDimitry Andric            "This instruction is unpredicated");
6145ffd83dbSDimitry Andric 
6155ffd83dbSDimitry Andric     // Merge source operand into destination register
6165ffd83dbSDimitry Andric     PRFX = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(MovPrfxZero))
6175ffd83dbSDimitry Andric                .addReg(DstReg, RegState::Define)
6185ffd83dbSDimitry Andric                .addReg(MI.getOperand(PredIdx).getReg())
6195ffd83dbSDimitry Andric                .addReg(MI.getOperand(DOPIdx).getReg());
6205ffd83dbSDimitry Andric 
6215ffd83dbSDimitry Andric     // After the movprfx, the destructive operand is same as Dst
6225ffd83dbSDimitry Andric     DOPIdx = 0;
623bdd1243dSDimitry Andric 
624bdd1243dSDimitry Andric     // Create the additional LSL to zero the lanes when the DstReg is not
625bdd1243dSDimitry Andric     // unique. Zeros the lanes in z0 that aren't active in p0 with sequence
626bdd1243dSDimitry Andric     // movprfx z0.b, p0/z, z0.b; lsl z0.b, p0/m, z0.b, #0;
627bdd1243dSDimitry Andric     if ((DType == AArch64::DestructiveBinary ||
62806c3fb27SDimitry Andric          DType == AArch64::DestructiveBinaryComm ||
62906c3fb27SDimitry Andric          DType == AArch64::DestructiveBinaryCommWithRev) &&
630bdd1243dSDimitry Andric         !DOPRegIsUnique) {
631bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(LSLZero))
632bdd1243dSDimitry Andric           .addReg(DstReg, RegState::Define)
633bdd1243dSDimitry Andric           .add(MI.getOperand(PredIdx))
634bdd1243dSDimitry Andric           .addReg(DstReg)
635bdd1243dSDimitry Andric           .addImm(0);
636bdd1243dSDimitry Andric     }
6375ffd83dbSDimitry Andric   } else if (DstReg != MI.getOperand(DOPIdx).getReg()) {
6385ffd83dbSDimitry Andric     assert(DOPRegIsUnique && "The destructive operand should be unique");
6395ffd83dbSDimitry Andric     PRFX = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(MovPrfx))
6405ffd83dbSDimitry Andric                .addReg(DstReg, RegState::Define)
6415ffd83dbSDimitry Andric                .addReg(MI.getOperand(DOPIdx).getReg());
6425ffd83dbSDimitry Andric     DOPIdx = 0;
6435ffd83dbSDimitry Andric   }
6445ffd83dbSDimitry Andric 
6455ffd83dbSDimitry Andric   //
6465ffd83dbSDimitry Andric   // Create the destructive operation
6475ffd83dbSDimitry Andric   //
6485ffd83dbSDimitry Andric   DOP = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opcode))
6495ffd83dbSDimitry Andric     .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead));
6505ffd83dbSDimitry Andric 
6515ffd83dbSDimitry Andric   switch (DType) {
652fe6060f1SDimitry Andric   case AArch64::DestructiveUnaryPassthru:
653fe6060f1SDimitry Andric     DOP.addReg(MI.getOperand(DOPIdx).getReg(), RegState::Kill)
654fe6060f1SDimitry Andric         .add(MI.getOperand(PredIdx))
655fe6060f1SDimitry Andric         .add(MI.getOperand(SrcIdx));
656fe6060f1SDimitry Andric     break;
657bdd1243dSDimitry Andric   case AArch64::DestructiveBinary:
6585ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryImm:
6595ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryComm:
6605ffd83dbSDimitry Andric   case AArch64::DestructiveBinaryCommWithRev:
6615ffd83dbSDimitry Andric     DOP.add(MI.getOperand(PredIdx))
6625ffd83dbSDimitry Andric        .addReg(MI.getOperand(DOPIdx).getReg(), RegState::Kill)
6635ffd83dbSDimitry Andric        .add(MI.getOperand(SrcIdx));
6645ffd83dbSDimitry Andric     break;
665fe6060f1SDimitry Andric   case AArch64::DestructiveTernaryCommWithRev:
666fe6060f1SDimitry Andric     DOP.add(MI.getOperand(PredIdx))
667fe6060f1SDimitry Andric         .addReg(MI.getOperand(DOPIdx).getReg(), RegState::Kill)
668fe6060f1SDimitry Andric         .add(MI.getOperand(SrcIdx))
669fe6060f1SDimitry Andric         .add(MI.getOperand(Src2Idx));
670fe6060f1SDimitry Andric     break;
6715ffd83dbSDimitry Andric   }
6725ffd83dbSDimitry Andric 
6735ffd83dbSDimitry Andric   if (PRFX) {
6745ffd83dbSDimitry Andric     finalizeBundle(MBB, PRFX->getIterator(), MBBI->getIterator());
6755ffd83dbSDimitry Andric     transferImpOps(MI, PRFX, DOP);
6765ffd83dbSDimitry Andric   } else
6775ffd83dbSDimitry Andric     transferImpOps(MI, DOP, DOP);
6785ffd83dbSDimitry Andric 
6795ffd83dbSDimitry Andric   MI.eraseFromParent();
6805ffd83dbSDimitry Andric   return true;
6815ffd83dbSDimitry Andric }
6825ffd83dbSDimitry Andric 
6830b57cec5SDimitry Andric bool AArch64ExpandPseudo::expandSetTagLoop(
6840b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
6850b57cec5SDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
6860b57cec5SDimitry Andric   MachineInstr &MI = *MBBI;
6870b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
6885ffd83dbSDimitry Andric   Register SizeReg = MI.getOperand(0).getReg();
6895ffd83dbSDimitry Andric   Register AddressReg = MI.getOperand(1).getReg();
6900b57cec5SDimitry Andric 
6910b57cec5SDimitry Andric   MachineFunction *MF = MBB.getParent();
6920b57cec5SDimitry Andric 
6935ffd83dbSDimitry Andric   bool ZeroData = MI.getOpcode() == AArch64::STZGloop_wback;
6945ffd83dbSDimitry Andric   const unsigned OpCode1 =
6955ffd83dbSDimitry Andric       ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex;
6965ffd83dbSDimitry Andric   const unsigned OpCode2 =
6970b57cec5SDimitry Andric       ZeroData ? AArch64::STZ2GPostIndex : AArch64::ST2GPostIndex;
6980b57cec5SDimitry Andric 
6995ffd83dbSDimitry Andric   unsigned Size = MI.getOperand(2).getImm();
7005ffd83dbSDimitry Andric   assert(Size > 0 && Size % 16 == 0);
7015ffd83dbSDimitry Andric   if (Size % (16 * 2) != 0) {
7025ffd83dbSDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(OpCode1), AddressReg)
7035ffd83dbSDimitry Andric         .addReg(AddressReg)
7045ffd83dbSDimitry Andric         .addReg(AddressReg)
7055ffd83dbSDimitry Andric         .addImm(1);
7065ffd83dbSDimitry Andric     Size -= 16;
7075ffd83dbSDimitry Andric   }
7085ffd83dbSDimitry Andric   MachineBasicBlock::iterator I =
7095ffd83dbSDimitry Andric       BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm), SizeReg)
7105ffd83dbSDimitry Andric           .addImm(Size);
7115ffd83dbSDimitry Andric   expandMOVImm(MBB, I, 64);
7125ffd83dbSDimitry Andric 
7130b57cec5SDimitry Andric   auto LoopBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
7140b57cec5SDimitry Andric   auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric   MF->insert(++MBB.getIterator(), LoopBB);
7170b57cec5SDimitry Andric   MF->insert(++LoopBB->getIterator(), DoneBB);
7180b57cec5SDimitry Andric 
7195ffd83dbSDimitry Andric   BuildMI(LoopBB, DL, TII->get(OpCode2))
7200b57cec5SDimitry Andric       .addDef(AddressReg)
7210b57cec5SDimitry Andric       .addReg(AddressReg)
7220b57cec5SDimitry Andric       .addReg(AddressReg)
7230b57cec5SDimitry Andric       .addImm(2)
7240b57cec5SDimitry Andric       .cloneMemRefs(MI)
7250b57cec5SDimitry Andric       .setMIFlags(MI.getFlags());
72606c3fb27SDimitry Andric   BuildMI(LoopBB, DL, TII->get(AArch64::SUBSXri))
7270b57cec5SDimitry Andric       .addDef(SizeReg)
7280b57cec5SDimitry Andric       .addReg(SizeReg)
7290b57cec5SDimitry Andric       .addImm(16 * 2)
7300b57cec5SDimitry Andric       .addImm(0);
73106c3fb27SDimitry Andric   BuildMI(LoopBB, DL, TII->get(AArch64::Bcc))
73206c3fb27SDimitry Andric       .addImm(AArch64CC::NE)
73306c3fb27SDimitry Andric       .addMBB(LoopBB)
73406c3fb27SDimitry Andric       .addReg(AArch64::NZCV, RegState::Implicit | RegState::Kill);
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric   LoopBB->addSuccessor(LoopBB);
7370b57cec5SDimitry Andric   LoopBB->addSuccessor(DoneBB);
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric   DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
7400b57cec5SDimitry Andric   DoneBB->transferSuccessors(&MBB);
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric   MBB.addSuccessor(LoopBB);
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric   NextMBBI = MBB.end();
7450b57cec5SDimitry Andric   MI.eraseFromParent();
7460b57cec5SDimitry Andric   // Recompute liveness bottom up.
7470b57cec5SDimitry Andric   LivePhysRegs LiveRegs;
7480b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneBB);
7490b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopBB);
7500b57cec5SDimitry Andric   // Do an extra pass in the loop to get the loop carried dependencies right.
7510b57cec5SDimitry Andric   // FIXME: is this necessary?
7520b57cec5SDimitry Andric   LoopBB->clearLiveIns();
7530b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *LoopBB);
7540b57cec5SDimitry Andric   DoneBB->clearLiveIns();
7550b57cec5SDimitry Andric   computeAndAddLiveIns(LiveRegs, *DoneBB);
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric   return true;
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric 
7605ffd83dbSDimitry Andric bool AArch64ExpandPseudo::expandSVESpillFill(MachineBasicBlock &MBB,
7615ffd83dbSDimitry Andric                                              MachineBasicBlock::iterator MBBI,
7625ffd83dbSDimitry Andric                                              unsigned Opc, unsigned N) {
763cb14a3feSDimitry Andric   assert((Opc == AArch64::LDR_ZXI || Opc == AArch64::STR_ZXI ||
764cb14a3feSDimitry Andric           Opc == AArch64::LDR_PXI || Opc == AArch64::STR_PXI) &&
765cb14a3feSDimitry Andric          "Unexpected opcode");
766cb14a3feSDimitry Andric   unsigned RState = (Opc == AArch64::LDR_ZXI || Opc == AArch64::LDR_PXI)
767cb14a3feSDimitry Andric                         ? RegState::Define
768cb14a3feSDimitry Andric                         : 0;
769cb14a3feSDimitry Andric   unsigned sub0 = (Opc == AArch64::LDR_ZXI || Opc == AArch64::STR_ZXI)
770cb14a3feSDimitry Andric                       ? AArch64::zsub0
771cb14a3feSDimitry Andric                       : AArch64::psub0;
7725ffd83dbSDimitry Andric   const TargetRegisterInfo *TRI =
7735ffd83dbSDimitry Andric       MBB.getParent()->getSubtarget().getRegisterInfo();
7745ffd83dbSDimitry Andric   MachineInstr &MI = *MBBI;
7755ffd83dbSDimitry Andric   for (unsigned Offset = 0; Offset < N; ++Offset) {
7765ffd83dbSDimitry Andric     int ImmOffset = MI.getOperand(2).getImm() + Offset;
7775ffd83dbSDimitry Andric     bool Kill = (Offset + 1 == N) ? MI.getOperand(1).isKill() : false;
7785ffd83dbSDimitry Andric     assert(ImmOffset >= -256 && ImmOffset < 256 &&
7795ffd83dbSDimitry Andric            "Immediate spill offset out of range");
7805ffd83dbSDimitry Andric     BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc))
781cb14a3feSDimitry Andric         .addReg(TRI->getSubReg(MI.getOperand(0).getReg(), sub0 + Offset),
782cb14a3feSDimitry Andric                 RState)
7835ffd83dbSDimitry Andric         .addReg(MI.getOperand(1).getReg(), getKillRegState(Kill))
7845ffd83dbSDimitry Andric         .addImm(ImmOffset);
7855ffd83dbSDimitry Andric   }
7865ffd83dbSDimitry Andric   MI.eraseFromParent();
7875ffd83dbSDimitry Andric   return true;
7885ffd83dbSDimitry Andric }
7895ffd83dbSDimitry Andric 
790*0fca6ea1SDimitry Andric // Create a call with the passed opcode and explicit operands, copying over all
791*0fca6ea1SDimitry Andric // the implicit operands from *MBBI, starting at the regmask.
792*0fca6ea1SDimitry Andric static MachineInstr *createCallWithOps(MachineBasicBlock &MBB,
793*0fca6ea1SDimitry Andric                                        MachineBasicBlock::iterator MBBI,
794*0fca6ea1SDimitry Andric                                        const AArch64InstrInfo *TII,
795*0fca6ea1SDimitry Andric                                        unsigned Opcode,
796*0fca6ea1SDimitry Andric                                        ArrayRef<MachineOperand> ExplicitOps,
797*0fca6ea1SDimitry Andric                                        unsigned RegMaskStartIdx) {
798*0fca6ea1SDimitry Andric   // Build the MI, with explicit operands first (including the call target).
799*0fca6ea1SDimitry Andric   MachineInstr *Call = BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode))
800*0fca6ea1SDimitry Andric                            .add(ExplicitOps)
801*0fca6ea1SDimitry Andric                            .getInstr();
802*0fca6ea1SDimitry Andric 
803*0fca6ea1SDimitry Andric   // Register arguments are added during ISel, but cannot be added as explicit
804*0fca6ea1SDimitry Andric   // operands of the branch as it expects to be B <target> which is only one
805*0fca6ea1SDimitry Andric   // operand. Instead they are implicit operands used by the branch.
806*0fca6ea1SDimitry Andric   while (!MBBI->getOperand(RegMaskStartIdx).isRegMask()) {
807*0fca6ea1SDimitry Andric     const MachineOperand &MOP = MBBI->getOperand(RegMaskStartIdx);
808*0fca6ea1SDimitry Andric     assert(MOP.isReg() && "can only add register operands");
809*0fca6ea1SDimitry Andric     Call->addOperand(MachineOperand::CreateReg(
810*0fca6ea1SDimitry Andric         MOP.getReg(), /*Def=*/false, /*Implicit=*/true, /*isKill=*/false,
811*0fca6ea1SDimitry Andric         /*isDead=*/false, /*isUndef=*/MOP.isUndef()));
812*0fca6ea1SDimitry Andric     RegMaskStartIdx++;
813*0fca6ea1SDimitry Andric   }
814*0fca6ea1SDimitry Andric   for (const MachineOperand &MO :
815*0fca6ea1SDimitry Andric        llvm::drop_begin(MBBI->operands(), RegMaskStartIdx))
816*0fca6ea1SDimitry Andric     Call->addOperand(MO);
817*0fca6ea1SDimitry Andric 
818*0fca6ea1SDimitry Andric   return Call;
819*0fca6ea1SDimitry Andric }
820*0fca6ea1SDimitry Andric 
821*0fca6ea1SDimitry Andric // Create a call to CallTarget, copying over all the operands from *MBBI,
822*0fca6ea1SDimitry Andric // starting at the regmask.
823*0fca6ea1SDimitry Andric static MachineInstr *createCall(MachineBasicBlock &MBB,
824*0fca6ea1SDimitry Andric                                 MachineBasicBlock::iterator MBBI,
825*0fca6ea1SDimitry Andric                                 const AArch64InstrInfo *TII,
826*0fca6ea1SDimitry Andric                                 MachineOperand &CallTarget,
827*0fca6ea1SDimitry Andric                                 unsigned RegMaskStartIdx) {
828*0fca6ea1SDimitry Andric   unsigned Opc = CallTarget.isGlobal() ? AArch64::BL : AArch64::BLR;
829*0fca6ea1SDimitry Andric 
830*0fca6ea1SDimitry Andric   assert((CallTarget.isGlobal() || CallTarget.isReg()) &&
831*0fca6ea1SDimitry Andric          "invalid operand for regular call");
832*0fca6ea1SDimitry Andric   return createCallWithOps(MBB, MBBI, TII, Opc, CallTarget, RegMaskStartIdx);
833*0fca6ea1SDimitry Andric }
834*0fca6ea1SDimitry Andric 
835e8d8bef9SDimitry Andric bool AArch64ExpandPseudo::expandCALL_RVMARKER(
836e8d8bef9SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
8371fd87a68SDimitry Andric   // Expand CALL_RVMARKER pseudo to:
8381fd87a68SDimitry Andric   // - a branch to the call target, followed by
8391fd87a68SDimitry Andric   // - the special `mov x29, x29` marker, and
8401fd87a68SDimitry Andric   // - another branch, to the runtime function
8411fd87a68SDimitry Andric   // Mark the sequence as bundle, to avoid passes moving other code in between.
842e8d8bef9SDimitry Andric   MachineInstr &MI = *MBBI;
8431fd87a68SDimitry Andric   MachineOperand &RVTarget = MI.getOperand(0);
8441fd87a68SDimitry Andric   assert(RVTarget.isGlobal() && "invalid operand for attached call");
845e8d8bef9SDimitry Andric 
846*0fca6ea1SDimitry Andric   MachineInstr *OriginalCall = nullptr;
847*0fca6ea1SDimitry Andric 
848*0fca6ea1SDimitry Andric   if (MI.getOpcode() == AArch64::BLRA_RVMARKER) {
849*0fca6ea1SDimitry Andric     // ptrauth call.
850*0fca6ea1SDimitry Andric     const MachineOperand &CallTarget = MI.getOperand(1);
851*0fca6ea1SDimitry Andric     const MachineOperand &Key = MI.getOperand(2);
852*0fca6ea1SDimitry Andric     const MachineOperand &IntDisc = MI.getOperand(3);
853*0fca6ea1SDimitry Andric     const MachineOperand &AddrDisc = MI.getOperand(4);
854*0fca6ea1SDimitry Andric 
855*0fca6ea1SDimitry Andric     assert((Key.getImm() == AArch64PACKey::IA ||
856*0fca6ea1SDimitry Andric             Key.getImm() == AArch64PACKey::IB) &&
857*0fca6ea1SDimitry Andric            "Invalid auth call key");
858*0fca6ea1SDimitry Andric 
859*0fca6ea1SDimitry Andric     MachineOperand Ops[] = {CallTarget, Key, IntDisc, AddrDisc};
860*0fca6ea1SDimitry Andric 
861*0fca6ea1SDimitry Andric     OriginalCall = createCallWithOps(MBB, MBBI, TII, AArch64::BLRA, Ops,
862*0fca6ea1SDimitry Andric                                      /*RegMaskStartIdx=*/5);
863*0fca6ea1SDimitry Andric   } else {
864*0fca6ea1SDimitry Andric     assert(MI.getOpcode() == AArch64::BLR_RVMARKER && "unknown rvmarker MI");
865*0fca6ea1SDimitry Andric     OriginalCall = createCall(MBB, MBBI, TII, MI.getOperand(1),
866*0fca6ea1SDimitry Andric                               // Regmask starts after the RV and call targets.
867*0fca6ea1SDimitry Andric                               /*RegMaskStartIdx=*/2);
868e8d8bef9SDimitry Andric   }
869e8d8bef9SDimitry Andric 
8701fd87a68SDimitry Andric   BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORRXrs))
871e8d8bef9SDimitry Andric                      .addReg(AArch64::FP, RegState::Define)
872e8d8bef9SDimitry Andric                      .addReg(AArch64::XZR)
873e8d8bef9SDimitry Andric                      .addReg(AArch64::FP)
8741fd87a68SDimitry Andric                      .addImm(0);
8751fd87a68SDimitry Andric 
8761fd87a68SDimitry Andric   auto *RVCall = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BL))
8771fd87a68SDimitry Andric                      .add(RVTarget)
878e8d8bef9SDimitry Andric                      .getInstr();
8791fd87a68SDimitry Andric 
880e8d8bef9SDimitry Andric   if (MI.shouldUpdateCallSiteInfo())
8811fd87a68SDimitry Andric     MBB.getParent()->moveCallSiteInfo(&MI, OriginalCall);
8821fd87a68SDimitry Andric 
883e8d8bef9SDimitry Andric   MI.eraseFromParent();
884e8d8bef9SDimitry Andric   finalizeBundle(MBB, OriginalCall->getIterator(),
8851fd87a68SDimitry Andric                  std::next(RVCall->getIterator()));
886e8d8bef9SDimitry Andric   return true;
887e8d8bef9SDimitry Andric }
888e8d8bef9SDimitry Andric 
8893a9a9c0cSDimitry Andric bool AArch64ExpandPseudo::expandCALL_BTI(MachineBasicBlock &MBB,
8903a9a9c0cSDimitry Andric                                          MachineBasicBlock::iterator MBBI) {
8913a9a9c0cSDimitry Andric   // Expand CALL_BTI pseudo to:
8923a9a9c0cSDimitry Andric   // - a branch to the call target
8933a9a9c0cSDimitry Andric   // - a BTI instruction
8943a9a9c0cSDimitry Andric   // Mark the sequence as a bundle, to avoid passes moving other code in
8953a9a9c0cSDimitry Andric   // between.
8963a9a9c0cSDimitry Andric   MachineInstr &MI = *MBBI;
897*0fca6ea1SDimitry Andric   MachineInstr *Call = createCall(MBB, MBBI, TII, MI.getOperand(0),
898*0fca6ea1SDimitry Andric                                   // Regmask starts after the call target.
899*0fca6ea1SDimitry Andric                                   /*RegMaskStartIdx=*/1);
9007a6dacacSDimitry Andric 
901bdd1243dSDimitry Andric   Call->setCFIType(*MBB.getParent(), MI.getCFIType());
9023a9a9c0cSDimitry Andric 
9033a9a9c0cSDimitry Andric   MachineInstr *BTI =
9043a9a9c0cSDimitry Andric       BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::HINT))
9053a9a9c0cSDimitry Andric           // BTI J so that setjmp can to BR to this.
9063a9a9c0cSDimitry Andric           .addImm(36)
9073a9a9c0cSDimitry Andric           .getInstr();
9083a9a9c0cSDimitry Andric 
9093a9a9c0cSDimitry Andric   if (MI.shouldUpdateCallSiteInfo())
9103a9a9c0cSDimitry Andric     MBB.getParent()->moveCallSiteInfo(&MI, Call);
9113a9a9c0cSDimitry Andric 
9123a9a9c0cSDimitry Andric   MI.eraseFromParent();
9133a9a9c0cSDimitry Andric   finalizeBundle(MBB, Call->getIterator(), std::next(BTI->getIterator()));
9143a9a9c0cSDimitry Andric   return true;
9153a9a9c0cSDimitry Andric }
9163a9a9c0cSDimitry Andric 
917fe6060f1SDimitry Andric bool AArch64ExpandPseudo::expandStoreSwiftAsyncContext(
918fe6060f1SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
919fe6060f1SDimitry Andric   Register CtxReg = MBBI->getOperand(0).getReg();
920fe6060f1SDimitry Andric   Register BaseReg = MBBI->getOperand(1).getReg();
921fe6060f1SDimitry Andric   int Offset = MBBI->getOperand(2).getImm();
922fe6060f1SDimitry Andric   DebugLoc DL(MBBI->getDebugLoc());
923fe6060f1SDimitry Andric   auto &STI = MBB.getParent()->getSubtarget<AArch64Subtarget>();
924fe6060f1SDimitry Andric 
925fe6060f1SDimitry Andric   if (STI.getTargetTriple().getArchName() != "arm64e") {
926fe6060f1SDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui))
927fe6060f1SDimitry Andric         .addUse(CtxReg)
928fe6060f1SDimitry Andric         .addUse(BaseReg)
929fe6060f1SDimitry Andric         .addImm(Offset / 8)
930fe6060f1SDimitry Andric         .setMIFlag(MachineInstr::FrameSetup);
931fe6060f1SDimitry Andric     MBBI->eraseFromParent();
932fe6060f1SDimitry Andric     return true;
933fe6060f1SDimitry Andric   }
934fe6060f1SDimitry Andric 
935fe6060f1SDimitry Andric   // We need to sign the context in an address-discriminated way. 0xc31a is a
936fe6060f1SDimitry Andric   // fixed random value, chosen as part of the ABI.
937fe6060f1SDimitry Andric   //     add x16, xBase, #Offset
938fe6060f1SDimitry Andric   //     movk x16, #0xc31a, lsl #48
939fe6060f1SDimitry Andric   //     mov x17, x22/xzr
940fe6060f1SDimitry Andric   //     pacdb x17, x16
941fe6060f1SDimitry Andric   //     str x17, [xBase, #Offset]
942fe6060f1SDimitry Andric   unsigned Opc = Offset >= 0 ? AArch64::ADDXri : AArch64::SUBXri;
943fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(Opc), AArch64::X16)
944fe6060f1SDimitry Andric       .addUse(BaseReg)
945fe6060f1SDimitry Andric       .addImm(abs(Offset))
946fe6060f1SDimitry Andric       .addImm(0)
947fe6060f1SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
948fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), AArch64::X16)
949fe6060f1SDimitry Andric       .addUse(AArch64::X16)
950fe6060f1SDimitry Andric       .addImm(0xc31a)
951fe6060f1SDimitry Andric       .addImm(48)
952fe6060f1SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
953fe6060f1SDimitry Andric   // We're not allowed to clobber X22 (and couldn't clobber XZR if we tried), so
954fe6060f1SDimitry Andric   // move it somewhere before signing.
955fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), AArch64::X17)
956fe6060f1SDimitry Andric       .addUse(AArch64::XZR)
957fe6060f1SDimitry Andric       .addUse(CtxReg)
958fe6060f1SDimitry Andric       .addImm(0)
959fe6060f1SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
960fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACDB), AArch64::X17)
961fe6060f1SDimitry Andric       .addUse(AArch64::X17)
962fe6060f1SDimitry Andric       .addUse(AArch64::X16)
963fe6060f1SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
964fe6060f1SDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui))
965fe6060f1SDimitry Andric       .addUse(AArch64::X17)
966fe6060f1SDimitry Andric       .addUse(BaseReg)
967fe6060f1SDimitry Andric       .addImm(Offset / 8)
968fe6060f1SDimitry Andric       .setMIFlag(MachineInstr::FrameSetup);
969fe6060f1SDimitry Andric 
970fe6060f1SDimitry Andric   MBBI->eraseFromParent();
971fe6060f1SDimitry Andric   return true;
972fe6060f1SDimitry Andric }
973fe6060f1SDimitry Andric 
974bdd1243dSDimitry Andric MachineBasicBlock *
975bdd1243dSDimitry Andric AArch64ExpandPseudo::expandRestoreZA(MachineBasicBlock &MBB,
976bdd1243dSDimitry Andric                                      MachineBasicBlock::iterator MBBI) {
977bdd1243dSDimitry Andric   MachineInstr &MI = *MBBI;
978bdd1243dSDimitry Andric   assert((std::next(MBBI) != MBB.end() ||
979bdd1243dSDimitry Andric           MI.getParent()->successors().begin() !=
980bdd1243dSDimitry Andric               MI.getParent()->successors().end()) &&
981bdd1243dSDimitry Andric          "Unexpected unreachable in block that restores ZA");
982bdd1243dSDimitry Andric 
983bdd1243dSDimitry Andric   // Compare TPIDR2_EL0 value against 0.
984bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
985bdd1243dSDimitry Andric   MachineInstrBuilder Cbz = BuildMI(MBB, MBBI, DL, TII->get(AArch64::CBZX))
986bdd1243dSDimitry Andric                                 .add(MI.getOperand(0));
987bdd1243dSDimitry Andric 
988bdd1243dSDimitry Andric   // Split MBB and create two new blocks:
989bdd1243dSDimitry Andric   //  - MBB now contains all instructions before RestoreZAPseudo.
990bdd1243dSDimitry Andric   //  - SMBB contains the RestoreZAPseudo instruction only.
991bdd1243dSDimitry Andric   //  - EndBB contains all instructions after RestoreZAPseudo.
992bdd1243dSDimitry Andric   MachineInstr &PrevMI = *std::prev(MBBI);
993bdd1243dSDimitry Andric   MachineBasicBlock *SMBB = MBB.splitAt(PrevMI, /*UpdateLiveIns*/ true);
994bdd1243dSDimitry Andric   MachineBasicBlock *EndBB = std::next(MI.getIterator()) == SMBB->end()
995bdd1243dSDimitry Andric                                  ? *SMBB->successors().begin()
996bdd1243dSDimitry Andric                                  : SMBB->splitAt(MI, /*UpdateLiveIns*/ true);
997bdd1243dSDimitry Andric 
998bdd1243dSDimitry Andric   // Add the SMBB label to the TB[N]Z instruction & create a branch to EndBB.
999bdd1243dSDimitry Andric   Cbz.addMBB(SMBB);
1000bdd1243dSDimitry Andric   BuildMI(&MBB, DL, TII->get(AArch64::B))
1001bdd1243dSDimitry Andric       .addMBB(EndBB);
1002bdd1243dSDimitry Andric   MBB.addSuccessor(EndBB);
1003bdd1243dSDimitry Andric 
1004bdd1243dSDimitry Andric   // Replace the pseudo with a call (BL).
1005bdd1243dSDimitry Andric   MachineInstrBuilder MIB =
1006bdd1243dSDimitry Andric       BuildMI(*SMBB, SMBB->end(), DL, TII->get(AArch64::BL));
1007bdd1243dSDimitry Andric   MIB.addReg(MI.getOperand(1).getReg(), RegState::Implicit);
1008bdd1243dSDimitry Andric   for (unsigned I = 2; I < MI.getNumOperands(); ++I)
1009bdd1243dSDimitry Andric     MIB.add(MI.getOperand(I));
1010bdd1243dSDimitry Andric   BuildMI(SMBB, DL, TII->get(AArch64::B)).addMBB(EndBB);
1011bdd1243dSDimitry Andric 
1012bdd1243dSDimitry Andric   MI.eraseFromParent();
1013bdd1243dSDimitry Andric   return EndBB;
1014bdd1243dSDimitry Andric }
1015bdd1243dSDimitry Andric 
1016bdd1243dSDimitry Andric MachineBasicBlock *
1017bdd1243dSDimitry Andric AArch64ExpandPseudo::expandCondSMToggle(MachineBasicBlock &MBB,
1018bdd1243dSDimitry Andric                                         MachineBasicBlock::iterator MBBI) {
1019bdd1243dSDimitry Andric   MachineInstr &MI = *MBBI;
1020bdd1243dSDimitry Andric   // In the case of a smstart/smstop before a unreachable, just remove the pseudo.
1021bdd1243dSDimitry Andric   // Exception handling code generated by Clang may introduce unreachables and it
1022bdd1243dSDimitry Andric   // seems unnecessary to restore pstate.sm when that happens. Note that it is
1023bdd1243dSDimitry Andric   // not just an optimisation, the code below expects a successor instruction/block
1024bdd1243dSDimitry Andric   // in order to split the block at MBBI.
1025bdd1243dSDimitry Andric   if (std::next(MBBI) == MBB.end() &&
1026bdd1243dSDimitry Andric       MI.getParent()->successors().begin() ==
1027bdd1243dSDimitry Andric           MI.getParent()->successors().end()) {
1028bdd1243dSDimitry Andric     MI.eraseFromParent();
1029bdd1243dSDimitry Andric     return &MBB;
1030bdd1243dSDimitry Andric   }
1031bdd1243dSDimitry Andric 
1032bdd1243dSDimitry Andric   // Expand the pseudo into smstart or smstop instruction. The pseudo has the
1033bdd1243dSDimitry Andric   // following operands:
1034bdd1243dSDimitry Andric   //
1035*0fca6ea1SDimitry Andric   //   MSRpstatePseudo <za|sm|both>, <0|1>, condition[, pstate.sm], <regmask>
1036bdd1243dSDimitry Andric   //
1037bdd1243dSDimitry Andric   // The pseudo is expanded into a conditional smstart/smstop, with a
1038bdd1243dSDimitry Andric   // check if pstate.sm (register) equals the expected value, and if not,
1039bdd1243dSDimitry Andric   // invokes the smstart/smstop.
1040bdd1243dSDimitry Andric   //
1041bdd1243dSDimitry Andric   // As an example, the following block contains a normal call from a
1042bdd1243dSDimitry Andric   // streaming-compatible function:
1043bdd1243dSDimitry Andric   //
1044bdd1243dSDimitry Andric   // OrigBB:
1045*0fca6ea1SDimitry Andric   //   MSRpstatePseudo 3, 0, IfCallerIsStreaming, %0, <regmask>  <- Cond SMSTOP
1046bdd1243dSDimitry Andric   //   bl @normal_callee
1047*0fca6ea1SDimitry Andric   //   MSRpstatePseudo 3, 1, IfCallerIsStreaming, %0, <regmask>  <- Cond SMSTART
1048bdd1243dSDimitry Andric   //
1049bdd1243dSDimitry Andric   // ...which will be transformed into:
1050bdd1243dSDimitry Andric   //
1051bdd1243dSDimitry Andric   // OrigBB:
1052bdd1243dSDimitry Andric   //   TBNZx %0:gpr64, 0, SMBB
1053bdd1243dSDimitry Andric   //   b EndBB
1054bdd1243dSDimitry Andric   //
1055bdd1243dSDimitry Andric   // SMBB:
1056bdd1243dSDimitry Andric   //   MSRpstatesvcrImm1 3, 0, <regmask>                  <- SMSTOP
1057bdd1243dSDimitry Andric   //
1058bdd1243dSDimitry Andric   // EndBB:
1059bdd1243dSDimitry Andric   //   bl @normal_callee
1060bdd1243dSDimitry Andric   //   MSRcond_pstatesvcrImm1 3, 1, <regmask>             <- SMSTART
1061bdd1243dSDimitry Andric   //
1062bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
1063bdd1243dSDimitry Andric 
1064bdd1243dSDimitry Andric   // Create the conditional branch based on the third operand of the
1065bdd1243dSDimitry Andric   // instruction, which tells us if we are wrapping a normal or streaming
1066bdd1243dSDimitry Andric   // function.
1067bdd1243dSDimitry Andric   // We test the live value of pstate.sm and toggle pstate.sm if this is not the
1068bdd1243dSDimitry Andric   // expected value for the callee (0 for a normal callee and 1 for a streaming
1069bdd1243dSDimitry Andric   // callee).
1070*0fca6ea1SDimitry Andric   unsigned Opc;
1071*0fca6ea1SDimitry Andric   switch (MI.getOperand(2).getImm()) {
1072*0fca6ea1SDimitry Andric   case AArch64SME::Always:
1073*0fca6ea1SDimitry Andric     llvm_unreachable("Should have matched to instruction directly");
1074*0fca6ea1SDimitry Andric   case AArch64SME::IfCallerIsStreaming:
1075*0fca6ea1SDimitry Andric     Opc = AArch64::TBNZW;
1076*0fca6ea1SDimitry Andric     break;
1077*0fca6ea1SDimitry Andric   case AArch64SME::IfCallerIsNonStreaming:
1078*0fca6ea1SDimitry Andric     Opc = AArch64::TBZW;
1079*0fca6ea1SDimitry Andric     break;
1080*0fca6ea1SDimitry Andric   }
1081*0fca6ea1SDimitry Andric   auto PStateSM = MI.getOperand(3).getReg();
10825f757f3fSDimitry Andric   auto TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
10835f757f3fSDimitry Andric   unsigned SMReg32 = TRI->getSubReg(PStateSM, AArch64::sub_32);
1084bdd1243dSDimitry Andric   MachineInstrBuilder Tbx =
10855f757f3fSDimitry Andric       BuildMI(MBB, MBBI, DL, TII->get(Opc)).addReg(SMReg32).addImm(0);
1086bdd1243dSDimitry Andric 
1087bdd1243dSDimitry Andric   // Split MBB and create two new blocks:
1088bdd1243dSDimitry Andric   //  - MBB now contains all instructions before MSRcond_pstatesvcrImm1.
1089bdd1243dSDimitry Andric   //  - SMBB contains the MSRcond_pstatesvcrImm1 instruction only.
1090bdd1243dSDimitry Andric   //  - EndBB contains all instructions after MSRcond_pstatesvcrImm1.
1091bdd1243dSDimitry Andric   MachineInstr &PrevMI = *std::prev(MBBI);
1092bdd1243dSDimitry Andric   MachineBasicBlock *SMBB = MBB.splitAt(PrevMI, /*UpdateLiveIns*/ true);
1093bdd1243dSDimitry Andric   MachineBasicBlock *EndBB = std::next(MI.getIterator()) == SMBB->end()
1094bdd1243dSDimitry Andric                                  ? *SMBB->successors().begin()
1095bdd1243dSDimitry Andric                                  : SMBB->splitAt(MI, /*UpdateLiveIns*/ true);
1096bdd1243dSDimitry Andric 
1097bdd1243dSDimitry Andric   // Add the SMBB label to the TB[N]Z instruction & create a branch to EndBB.
1098bdd1243dSDimitry Andric   Tbx.addMBB(SMBB);
1099bdd1243dSDimitry Andric   BuildMI(&MBB, DL, TII->get(AArch64::B))
1100bdd1243dSDimitry Andric       .addMBB(EndBB);
1101bdd1243dSDimitry Andric   MBB.addSuccessor(EndBB);
1102bdd1243dSDimitry Andric 
1103bdd1243dSDimitry Andric   // Create the SMSTART/SMSTOP (MSRpstatesvcrImm1) instruction in SMBB.
1104bdd1243dSDimitry Andric   MachineInstrBuilder MIB = BuildMI(*SMBB, SMBB->begin(), MI.getDebugLoc(),
1105bdd1243dSDimitry Andric                                     TII->get(AArch64::MSRpstatesvcrImm1));
1106bdd1243dSDimitry Andric   // Copy all but the second and third operands of MSRcond_pstatesvcrImm1 (as
1107bdd1243dSDimitry Andric   // these contain the CopyFromReg for the first argument and the flag to
1108bdd1243dSDimitry Andric   // indicate whether the callee is streaming or normal).
1109bdd1243dSDimitry Andric   MIB.add(MI.getOperand(0));
1110bdd1243dSDimitry Andric   MIB.add(MI.getOperand(1));
1111bdd1243dSDimitry Andric   for (unsigned i = 4; i < MI.getNumOperands(); ++i)
1112bdd1243dSDimitry Andric     MIB.add(MI.getOperand(i));
1113bdd1243dSDimitry Andric 
1114bdd1243dSDimitry Andric   BuildMI(SMBB, DL, TII->get(AArch64::B)).addMBB(EndBB);
1115bdd1243dSDimitry Andric 
1116bdd1243dSDimitry Andric   MI.eraseFromParent();
1117bdd1243dSDimitry Andric   return EndBB;
1118bdd1243dSDimitry Andric }
1119bdd1243dSDimitry Andric 
11205f757f3fSDimitry Andric bool AArch64ExpandPseudo::expandMultiVecPseudo(
11215f757f3fSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
11225f757f3fSDimitry Andric     TargetRegisterClass ContiguousClass, TargetRegisterClass StridedClass,
11235f757f3fSDimitry Andric     unsigned ContiguousOp, unsigned StridedOpc) {
11245f757f3fSDimitry Andric   MachineInstr &MI = *MBBI;
11255f757f3fSDimitry Andric   Register Tuple = MI.getOperand(0).getReg();
11265f757f3fSDimitry Andric 
11275f757f3fSDimitry Andric   auto ContiguousRange = ContiguousClass.getRegisters();
11285f757f3fSDimitry Andric   auto StridedRange = StridedClass.getRegisters();
11295f757f3fSDimitry Andric   unsigned Opc;
11305f757f3fSDimitry Andric   if (llvm::is_contained(ContiguousRange, Tuple.asMCReg())) {
11315f757f3fSDimitry Andric     Opc = ContiguousOp;
11325f757f3fSDimitry Andric   } else if (llvm::is_contained(StridedRange, Tuple.asMCReg())) {
11335f757f3fSDimitry Andric     Opc = StridedOpc;
11345f757f3fSDimitry Andric   } else
11355f757f3fSDimitry Andric     llvm_unreachable("Cannot expand Multi-Vector pseudo");
11365f757f3fSDimitry Andric 
11375f757f3fSDimitry Andric   MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc))
11385f757f3fSDimitry Andric                                 .add(MI.getOperand(0))
11395f757f3fSDimitry Andric                                 .add(MI.getOperand(1))
11405f757f3fSDimitry Andric                                 .add(MI.getOperand(2))
11415f757f3fSDimitry Andric                                 .add(MI.getOperand(3));
11425f757f3fSDimitry Andric   transferImpOps(MI, MIB, MIB);
11435f757f3fSDimitry Andric   MI.eraseFromParent();
11445f757f3fSDimitry Andric   return true;
11455f757f3fSDimitry Andric }
11465f757f3fSDimitry Andric 
11470b57cec5SDimitry Andric /// If MBBI references a pseudo instruction that should be expanded here,
11480b57cec5SDimitry Andric /// do the expansion and return true.  Otherwise return false.
11490b57cec5SDimitry Andric bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
11500b57cec5SDimitry Andric                                    MachineBasicBlock::iterator MBBI,
11510b57cec5SDimitry Andric                                    MachineBasicBlock::iterator &NextMBBI) {
11520b57cec5SDimitry Andric   MachineInstr &MI = *MBBI;
11530b57cec5SDimitry Andric   unsigned Opcode = MI.getOpcode();
11545ffd83dbSDimitry Andric 
11555ffd83dbSDimitry Andric   // Check if we can expand the destructive op
11565ffd83dbSDimitry Andric   int OrigInstr = AArch64::getSVEPseudoMap(MI.getOpcode());
11575ffd83dbSDimitry Andric   if (OrigInstr != -1) {
11585ffd83dbSDimitry Andric     auto &Orig = TII->get(OrigInstr);
115906c3fb27SDimitry Andric     if ((Orig.TSFlags & AArch64::DestructiveInstTypeMask) !=
116006c3fb27SDimitry Andric         AArch64::NotDestructive) {
11615ffd83dbSDimitry Andric       return expand_DestructiveOp(MI, MBB, MBBI);
11625ffd83dbSDimitry Andric     }
11635ffd83dbSDimitry Andric   }
11645ffd83dbSDimitry Andric 
11650b57cec5SDimitry Andric   switch (Opcode) {
11660b57cec5SDimitry Andric   default:
11670b57cec5SDimitry Andric     break;
11680b57cec5SDimitry Andric 
11695ffd83dbSDimitry Andric   case AArch64::BSPv8i8:
11705ffd83dbSDimitry Andric   case AArch64::BSPv16i8: {
11715ffd83dbSDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
11725ffd83dbSDimitry Andric     if (DstReg == MI.getOperand(3).getReg()) {
11735ffd83dbSDimitry Andric       // Expand to BIT
11745ffd83dbSDimitry Andric       BuildMI(MBB, MBBI, MI.getDebugLoc(),
11755ffd83dbSDimitry Andric               TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BITv8i8
11765ffd83dbSDimitry Andric                                                   : AArch64::BITv16i8))
11775ffd83dbSDimitry Andric           .add(MI.getOperand(0))
11785ffd83dbSDimitry Andric           .add(MI.getOperand(3))
11795ffd83dbSDimitry Andric           .add(MI.getOperand(2))
11805ffd83dbSDimitry Andric           .add(MI.getOperand(1));
11815ffd83dbSDimitry Andric     } else if (DstReg == MI.getOperand(2).getReg()) {
11825ffd83dbSDimitry Andric       // Expand to BIF
11835ffd83dbSDimitry Andric       BuildMI(MBB, MBBI, MI.getDebugLoc(),
11845ffd83dbSDimitry Andric               TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BIFv8i8
11855ffd83dbSDimitry Andric                                                   : AArch64::BIFv16i8))
11865ffd83dbSDimitry Andric           .add(MI.getOperand(0))
11875ffd83dbSDimitry Andric           .add(MI.getOperand(2))
11885ffd83dbSDimitry Andric           .add(MI.getOperand(3))
11895ffd83dbSDimitry Andric           .add(MI.getOperand(1));
11905ffd83dbSDimitry Andric     } else {
11915ffd83dbSDimitry Andric       // Expand to BSL, use additional move if required
11925ffd83dbSDimitry Andric       if (DstReg == MI.getOperand(1).getReg()) {
11935ffd83dbSDimitry Andric         BuildMI(MBB, MBBI, MI.getDebugLoc(),
11945ffd83dbSDimitry Andric                 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BSLv8i8
11955ffd83dbSDimitry Andric                                                     : AArch64::BSLv16i8))
11965ffd83dbSDimitry Andric             .add(MI.getOperand(0))
11975ffd83dbSDimitry Andric             .add(MI.getOperand(1))
11985ffd83dbSDimitry Andric             .add(MI.getOperand(2))
11995ffd83dbSDimitry Andric             .add(MI.getOperand(3));
12005ffd83dbSDimitry Andric       } else {
12015ffd83dbSDimitry Andric         BuildMI(MBB, MBBI, MI.getDebugLoc(),
12025ffd83dbSDimitry Andric                 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::ORRv8i8
12035ffd83dbSDimitry Andric                                                     : AArch64::ORRv16i8))
12045ffd83dbSDimitry Andric             .addReg(DstReg,
12055ffd83dbSDimitry Andric                     RegState::Define |
12065ffd83dbSDimitry Andric                         getRenamableRegState(MI.getOperand(0).isRenamable()))
12075ffd83dbSDimitry Andric             .add(MI.getOperand(1))
12085ffd83dbSDimitry Andric             .add(MI.getOperand(1));
12095ffd83dbSDimitry Andric         BuildMI(MBB, MBBI, MI.getDebugLoc(),
12105ffd83dbSDimitry Andric                 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BSLv8i8
12115ffd83dbSDimitry Andric                                                     : AArch64::BSLv16i8))
12125ffd83dbSDimitry Andric             .add(MI.getOperand(0))
12135ffd83dbSDimitry Andric             .addReg(DstReg,
12145ffd83dbSDimitry Andric                     RegState::Kill |
12155ffd83dbSDimitry Andric                         getRenamableRegState(MI.getOperand(0).isRenamable()))
12165ffd83dbSDimitry Andric             .add(MI.getOperand(2))
12175ffd83dbSDimitry Andric             .add(MI.getOperand(3));
12185ffd83dbSDimitry Andric       }
12195ffd83dbSDimitry Andric     }
12205ffd83dbSDimitry Andric     MI.eraseFromParent();
12215ffd83dbSDimitry Andric     return true;
12225ffd83dbSDimitry Andric   }
12235ffd83dbSDimitry Andric 
12240b57cec5SDimitry Andric   case AArch64::ADDWrr:
12250b57cec5SDimitry Andric   case AArch64::SUBWrr:
12260b57cec5SDimitry Andric   case AArch64::ADDXrr:
12270b57cec5SDimitry Andric   case AArch64::SUBXrr:
12280b57cec5SDimitry Andric   case AArch64::ADDSWrr:
12290b57cec5SDimitry Andric   case AArch64::SUBSWrr:
12300b57cec5SDimitry Andric   case AArch64::ADDSXrr:
12310b57cec5SDimitry Andric   case AArch64::SUBSXrr:
12320b57cec5SDimitry Andric   case AArch64::ANDWrr:
12330b57cec5SDimitry Andric   case AArch64::ANDXrr:
12340b57cec5SDimitry Andric   case AArch64::BICWrr:
12350b57cec5SDimitry Andric   case AArch64::BICXrr:
12360b57cec5SDimitry Andric   case AArch64::ANDSWrr:
12370b57cec5SDimitry Andric   case AArch64::ANDSXrr:
12380b57cec5SDimitry Andric   case AArch64::BICSWrr:
12390b57cec5SDimitry Andric   case AArch64::BICSXrr:
12400b57cec5SDimitry Andric   case AArch64::EONWrr:
12410b57cec5SDimitry Andric   case AArch64::EONXrr:
12420b57cec5SDimitry Andric   case AArch64::EORWrr:
12430b57cec5SDimitry Andric   case AArch64::EORXrr:
12440b57cec5SDimitry Andric   case AArch64::ORNWrr:
12450b57cec5SDimitry Andric   case AArch64::ORNXrr:
12460b57cec5SDimitry Andric   case AArch64::ORRWrr:
12470b57cec5SDimitry Andric   case AArch64::ORRXrr: {
12480b57cec5SDimitry Andric     unsigned Opcode;
12490b57cec5SDimitry Andric     switch (MI.getOpcode()) {
12500b57cec5SDimitry Andric     default:
12510b57cec5SDimitry Andric       return false;
12520b57cec5SDimitry Andric     case AArch64::ADDWrr:      Opcode = AArch64::ADDWrs; break;
12530b57cec5SDimitry Andric     case AArch64::SUBWrr:      Opcode = AArch64::SUBWrs; break;
12540b57cec5SDimitry Andric     case AArch64::ADDXrr:      Opcode = AArch64::ADDXrs; break;
12550b57cec5SDimitry Andric     case AArch64::SUBXrr:      Opcode = AArch64::SUBXrs; break;
12560b57cec5SDimitry Andric     case AArch64::ADDSWrr:     Opcode = AArch64::ADDSWrs; break;
12570b57cec5SDimitry Andric     case AArch64::SUBSWrr:     Opcode = AArch64::SUBSWrs; break;
12580b57cec5SDimitry Andric     case AArch64::ADDSXrr:     Opcode = AArch64::ADDSXrs; break;
12590b57cec5SDimitry Andric     case AArch64::SUBSXrr:     Opcode = AArch64::SUBSXrs; break;
12600b57cec5SDimitry Andric     case AArch64::ANDWrr:      Opcode = AArch64::ANDWrs; break;
12610b57cec5SDimitry Andric     case AArch64::ANDXrr:      Opcode = AArch64::ANDXrs; break;
12620b57cec5SDimitry Andric     case AArch64::BICWrr:      Opcode = AArch64::BICWrs; break;
12630b57cec5SDimitry Andric     case AArch64::BICXrr:      Opcode = AArch64::BICXrs; break;
12640b57cec5SDimitry Andric     case AArch64::ANDSWrr:     Opcode = AArch64::ANDSWrs; break;
12650b57cec5SDimitry Andric     case AArch64::ANDSXrr:     Opcode = AArch64::ANDSXrs; break;
12660b57cec5SDimitry Andric     case AArch64::BICSWrr:     Opcode = AArch64::BICSWrs; break;
12670b57cec5SDimitry Andric     case AArch64::BICSXrr:     Opcode = AArch64::BICSXrs; break;
12680b57cec5SDimitry Andric     case AArch64::EONWrr:      Opcode = AArch64::EONWrs; break;
12690b57cec5SDimitry Andric     case AArch64::EONXrr:      Opcode = AArch64::EONXrs; break;
12700b57cec5SDimitry Andric     case AArch64::EORWrr:      Opcode = AArch64::EORWrs; break;
12710b57cec5SDimitry Andric     case AArch64::EORXrr:      Opcode = AArch64::EORXrs; break;
12720b57cec5SDimitry Andric     case AArch64::ORNWrr:      Opcode = AArch64::ORNWrs; break;
12730b57cec5SDimitry Andric     case AArch64::ORNXrr:      Opcode = AArch64::ORNXrs; break;
12740b57cec5SDimitry Andric     case AArch64::ORRWrr:      Opcode = AArch64::ORRWrs; break;
12750b57cec5SDimitry Andric     case AArch64::ORRXrr:      Opcode = AArch64::ORRXrs; break;
12760b57cec5SDimitry Andric     }
1277349cc55cSDimitry Andric     MachineFunction &MF = *MBB.getParent();
1278349cc55cSDimitry Andric     // Try to create new inst without implicit operands added.
1279349cc55cSDimitry Andric     MachineInstr *NewMI = MF.CreateMachineInstr(
1280349cc55cSDimitry Andric         TII->get(Opcode), MI.getDebugLoc(), /*NoImplicit=*/true);
1281349cc55cSDimitry Andric     MBB.insert(MBBI, NewMI);
1282349cc55cSDimitry Andric     MachineInstrBuilder MIB1(MF, NewMI);
1283bdd1243dSDimitry Andric     MIB1->setPCSections(MF, MI.getPCSections());
1284349cc55cSDimitry Andric     MIB1.addReg(MI.getOperand(0).getReg(), RegState::Define)
12850b57cec5SDimitry Andric         .add(MI.getOperand(1))
12860b57cec5SDimitry Andric         .add(MI.getOperand(2))
12870b57cec5SDimitry Andric         .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, 0));
12880b57cec5SDimitry Andric     transferImpOps(MI, MIB1, MIB1);
128906c3fb27SDimitry Andric     if (auto DebugNumber = MI.peekDebugInstrNum())
129006c3fb27SDimitry Andric       NewMI->setDebugInstrNum(DebugNumber);
12910b57cec5SDimitry Andric     MI.eraseFromParent();
12920b57cec5SDimitry Andric     return true;
12930b57cec5SDimitry Andric   }
12940b57cec5SDimitry Andric 
12950b57cec5SDimitry Andric   case AArch64::LOADgot: {
12960b57cec5SDimitry Andric     MachineFunction *MF = MBB.getParent();
12978bcb0991SDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
12980b57cec5SDimitry Andric     const MachineOperand &MO1 = MI.getOperand(1);
12990b57cec5SDimitry Andric     unsigned Flags = MO1.getTargetFlags();
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric     if (MF->getTarget().getCodeModel() == CodeModel::Tiny) {
13020b57cec5SDimitry Andric       // Tiny codemodel expand to LDR
13030b57cec5SDimitry Andric       MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(),
13040b57cec5SDimitry Andric                                         TII->get(AArch64::LDRXl), DstReg);
13050b57cec5SDimitry Andric 
13060b57cec5SDimitry Andric       if (MO1.isGlobal()) {
13070b57cec5SDimitry Andric         MIB.addGlobalAddress(MO1.getGlobal(), 0, Flags);
13080b57cec5SDimitry Andric       } else if (MO1.isSymbol()) {
13090b57cec5SDimitry Andric         MIB.addExternalSymbol(MO1.getSymbolName(), Flags);
13100b57cec5SDimitry Andric       } else {
13110b57cec5SDimitry Andric         assert(MO1.isCPI() &&
13120b57cec5SDimitry Andric                "Only expect globals, externalsymbols, or constant pools");
13130b57cec5SDimitry Andric         MIB.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(), Flags);
13140b57cec5SDimitry Andric       }
13150b57cec5SDimitry Andric     } else {
13160b57cec5SDimitry Andric       // Small codemodel expand into ADRP + LDR.
13178bcb0991SDimitry Andric       MachineFunction &MF = *MI.getParent()->getParent();
13188bcb0991SDimitry Andric       DebugLoc DL = MI.getDebugLoc();
13190b57cec5SDimitry Andric       MachineInstrBuilder MIB1 =
13200b57cec5SDimitry Andric           BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg);
13218bcb0991SDimitry Andric 
13228bcb0991SDimitry Andric       MachineInstrBuilder MIB2;
13238bcb0991SDimitry Andric       if (MF.getSubtarget<AArch64Subtarget>().isTargetILP32()) {
13248bcb0991SDimitry Andric         auto TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
13258bcb0991SDimitry Andric         unsigned Reg32 = TRI->getSubReg(DstReg, AArch64::sub_32);
13268bcb0991SDimitry Andric         unsigned DstFlags = MI.getOperand(0).getTargetFlags();
13278bcb0991SDimitry Andric         MIB2 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::LDRWui))
13288bcb0991SDimitry Andric                    .addDef(Reg32)
13298bcb0991SDimitry Andric                    .addReg(DstReg, RegState::Kill)
13308bcb0991SDimitry Andric                    .addReg(DstReg, DstFlags | RegState::Implicit);
13318bcb0991SDimitry Andric       } else {
133204eeddc0SDimitry Andric         Register DstReg = MI.getOperand(0).getReg();
13338bcb0991SDimitry Andric         MIB2 = BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXui))
13340b57cec5SDimitry Andric                    .add(MI.getOperand(0))
13358bcb0991SDimitry Andric                    .addUse(DstReg, RegState::Kill);
13368bcb0991SDimitry Andric       }
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric       if (MO1.isGlobal()) {
13390b57cec5SDimitry Andric         MIB1.addGlobalAddress(MO1.getGlobal(), 0, Flags | AArch64II::MO_PAGE);
13400b57cec5SDimitry Andric         MIB2.addGlobalAddress(MO1.getGlobal(), 0,
13410b57cec5SDimitry Andric                               Flags | AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
13420b57cec5SDimitry Andric       } else if (MO1.isSymbol()) {
13430b57cec5SDimitry Andric         MIB1.addExternalSymbol(MO1.getSymbolName(), Flags | AArch64II::MO_PAGE);
13440b57cec5SDimitry Andric         MIB2.addExternalSymbol(MO1.getSymbolName(), Flags |
13450b57cec5SDimitry Andric                                                         AArch64II::MO_PAGEOFF |
13460b57cec5SDimitry Andric                                                         AArch64II::MO_NC);
13470b57cec5SDimitry Andric       } else {
13480b57cec5SDimitry Andric         assert(MO1.isCPI() &&
13490b57cec5SDimitry Andric                "Only expect globals, externalsymbols, or constant pools");
13500b57cec5SDimitry Andric         MIB1.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(),
13510b57cec5SDimitry Andric                                   Flags | AArch64II::MO_PAGE);
13520b57cec5SDimitry Andric         MIB2.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(),
13530b57cec5SDimitry Andric                                   Flags | AArch64II::MO_PAGEOFF |
13540b57cec5SDimitry Andric                                       AArch64II::MO_NC);
13550b57cec5SDimitry Andric       }
13560b57cec5SDimitry Andric 
13570b57cec5SDimitry Andric       transferImpOps(MI, MIB1, MIB2);
13580b57cec5SDimitry Andric     }
13590b57cec5SDimitry Andric     MI.eraseFromParent();
13600b57cec5SDimitry Andric     return true;
13610b57cec5SDimitry Andric   }
1362fe6060f1SDimitry Andric   case AArch64::MOVaddrBA: {
1363fe6060f1SDimitry Andric     MachineFunction &MF = *MI.getParent()->getParent();
1364fe6060f1SDimitry Andric     if (MF.getSubtarget<AArch64Subtarget>().isTargetMachO()) {
1365fe6060f1SDimitry Andric       // blockaddress expressions have to come from a constant pool because the
1366fe6060f1SDimitry Andric       // largest addend (and hence offset within a function) allowed for ADRP is
1367fe6060f1SDimitry Andric       // only 8MB.
1368fe6060f1SDimitry Andric       const BlockAddress *BA = MI.getOperand(1).getBlockAddress();
1369fe6060f1SDimitry Andric       assert(MI.getOperand(1).getOffset() == 0 && "unexpected offset");
13700b57cec5SDimitry Andric 
1371fe6060f1SDimitry Andric       MachineConstantPool *MCP = MF.getConstantPool();
1372fe6060f1SDimitry Andric       unsigned CPIdx = MCP->getConstantPoolIndex(BA, Align(8));
1373fe6060f1SDimitry Andric 
1374fe6060f1SDimitry Andric       Register DstReg = MI.getOperand(0).getReg();
1375fe6060f1SDimitry Andric       auto MIB1 =
1376fe6060f1SDimitry Andric           BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg)
1377fe6060f1SDimitry Andric               .addConstantPoolIndex(CPIdx, 0, AArch64II::MO_PAGE);
1378fe6060f1SDimitry Andric       auto MIB2 = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1379fe6060f1SDimitry Andric                           TII->get(AArch64::LDRXui), DstReg)
1380fe6060f1SDimitry Andric                       .addUse(DstReg)
1381fe6060f1SDimitry Andric                       .addConstantPoolIndex(
1382fe6060f1SDimitry Andric                           CPIdx, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
1383fe6060f1SDimitry Andric       transferImpOps(MI, MIB1, MIB2);
1384fe6060f1SDimitry Andric       MI.eraseFromParent();
1385fe6060f1SDimitry Andric       return true;
1386fe6060f1SDimitry Andric     }
1387fe6060f1SDimitry Andric   }
1388bdd1243dSDimitry Andric     [[fallthrough]];
13890b57cec5SDimitry Andric   case AArch64::MOVaddr:
13900b57cec5SDimitry Andric   case AArch64::MOVaddrJT:
13910b57cec5SDimitry Andric   case AArch64::MOVaddrCP:
13920b57cec5SDimitry Andric   case AArch64::MOVaddrTLS:
13930b57cec5SDimitry Andric   case AArch64::MOVaddrEXT: {
13940b57cec5SDimitry Andric     // Expand into ADRP + ADD.
13958bcb0991SDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
1396349cc55cSDimitry Andric     assert(DstReg != AArch64::XZR);
13970b57cec5SDimitry Andric     MachineInstrBuilder MIB1 =
13980b57cec5SDimitry Andric         BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg)
13990b57cec5SDimitry Andric             .add(MI.getOperand(1));
14000b57cec5SDimitry Andric 
14018bcb0991SDimitry Andric     if (MI.getOperand(1).getTargetFlags() & AArch64II::MO_TAGGED) {
14028bcb0991SDimitry Andric       // MO_TAGGED on the page indicates a tagged address. Set the tag now.
14038bcb0991SDimitry Andric       // We do so by creating a MOVK that sets bits 48-63 of the register to
14048bcb0991SDimitry Andric       // (global address + 0x100000000 - PC) >> 48. This assumes that we're in
14058bcb0991SDimitry Andric       // the small code model so we can assume a binary size of <= 4GB, which
14068bcb0991SDimitry Andric       // makes the untagged PC relative offset positive. The binary must also be
14078bcb0991SDimitry Andric       // loaded into address range [0, 2^48). Both of these properties need to
14088bcb0991SDimitry Andric       // be ensured at runtime when using tagged addresses.
14098bcb0991SDimitry Andric       auto Tag = MI.getOperand(1);
14108bcb0991SDimitry Andric       Tag.setTargetFlags(AArch64II::MO_PREL | AArch64II::MO_G3);
14118bcb0991SDimitry Andric       Tag.setOffset(0x100000000);
14128bcb0991SDimitry Andric       BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MOVKXi), DstReg)
14138bcb0991SDimitry Andric           .addReg(DstReg)
14148bcb0991SDimitry Andric           .add(Tag)
14158bcb0991SDimitry Andric           .addImm(48);
14168bcb0991SDimitry Andric     }
14178bcb0991SDimitry Andric 
14180b57cec5SDimitry Andric     MachineInstrBuilder MIB2 =
14190b57cec5SDimitry Andric         BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADDXri))
14200b57cec5SDimitry Andric             .add(MI.getOperand(0))
14210b57cec5SDimitry Andric             .addReg(DstReg)
14220b57cec5SDimitry Andric             .add(MI.getOperand(2))
14230b57cec5SDimitry Andric             .addImm(0);
14240b57cec5SDimitry Andric 
14250b57cec5SDimitry Andric     transferImpOps(MI, MIB1, MIB2);
14260b57cec5SDimitry Andric     MI.eraseFromParent();
14270b57cec5SDimitry Andric     return true;
14280b57cec5SDimitry Andric   }
14290b57cec5SDimitry Andric   case AArch64::ADDlowTLS:
14300b57cec5SDimitry Andric     // Produce a plain ADD
14310b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADDXri))
14320b57cec5SDimitry Andric         .add(MI.getOperand(0))
14330b57cec5SDimitry Andric         .add(MI.getOperand(1))
14340b57cec5SDimitry Andric         .add(MI.getOperand(2))
14350b57cec5SDimitry Andric         .addImm(0);
14360b57cec5SDimitry Andric     MI.eraseFromParent();
14370b57cec5SDimitry Andric     return true;
14380b57cec5SDimitry Andric 
14390b57cec5SDimitry Andric   case AArch64::MOVbaseTLS: {
14408bcb0991SDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
14410b57cec5SDimitry Andric     auto SysReg = AArch64SysReg::TPIDR_EL0;
14420b57cec5SDimitry Andric     MachineFunction *MF = MBB.getParent();
14435ffd83dbSDimitry Andric     if (MF->getSubtarget<AArch64Subtarget>().useEL3ForTP())
14440b57cec5SDimitry Andric       SysReg = AArch64SysReg::TPIDR_EL3;
14450b57cec5SDimitry Andric     else if (MF->getSubtarget<AArch64Subtarget>().useEL2ForTP())
14460b57cec5SDimitry Andric       SysReg = AArch64SysReg::TPIDR_EL2;
14470b57cec5SDimitry Andric     else if (MF->getSubtarget<AArch64Subtarget>().useEL1ForTP())
14480b57cec5SDimitry Andric       SysReg = AArch64SysReg::TPIDR_EL1;
144906c3fb27SDimitry Andric     else if (MF->getSubtarget<AArch64Subtarget>().useROEL0ForTP())
145006c3fb27SDimitry Andric       SysReg = AArch64SysReg::TPIDRRO_EL0;
14510b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MRS), DstReg)
14520b57cec5SDimitry Andric         .addImm(SysReg);
14530b57cec5SDimitry Andric     MI.eraseFromParent();
14540b57cec5SDimitry Andric     return true;
14550b57cec5SDimitry Andric   }
14560b57cec5SDimitry Andric 
14570b57cec5SDimitry Andric   case AArch64::MOVi32imm:
14580b57cec5SDimitry Andric     return expandMOVImm(MBB, MBBI, 32);
14590b57cec5SDimitry Andric   case AArch64::MOVi64imm:
14600b57cec5SDimitry Andric     return expandMOVImm(MBB, MBBI, 64);
14610b57cec5SDimitry Andric   case AArch64::RET_ReallyLR: {
14620b57cec5SDimitry Andric     // Hiding the LR use with RET_ReallyLR may lead to extra kills in the
14630b57cec5SDimitry Andric     // function and missing live-ins. We are fine in practice because callee
14640b57cec5SDimitry Andric     // saved register handling ensures the register value is restored before
14650b57cec5SDimitry Andric     // RET, but we need the undef flag here to appease the MachineVerifier
14660b57cec5SDimitry Andric     // liveness checks.
14670b57cec5SDimitry Andric     MachineInstrBuilder MIB =
14680b57cec5SDimitry Andric         BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::RET))
14690b57cec5SDimitry Andric           .addReg(AArch64::LR, RegState::Undef);
14700b57cec5SDimitry Andric     transferImpOps(MI, MIB, MIB);
14710b57cec5SDimitry Andric     MI.eraseFromParent();
14720b57cec5SDimitry Andric     return true;
14730b57cec5SDimitry Andric   }
14740b57cec5SDimitry Andric   case AArch64::CMP_SWAP_8:
14750b57cec5SDimitry Andric     return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRB, AArch64::STLXRB,
14760b57cec5SDimitry Andric                           AArch64::SUBSWrx,
14770b57cec5SDimitry Andric                           AArch64_AM::getArithExtendImm(AArch64_AM::UXTB, 0),
14780b57cec5SDimitry Andric                           AArch64::WZR, NextMBBI);
14790b57cec5SDimitry Andric   case AArch64::CMP_SWAP_16:
14800b57cec5SDimitry Andric     return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRH, AArch64::STLXRH,
14810b57cec5SDimitry Andric                           AArch64::SUBSWrx,
14820b57cec5SDimitry Andric                           AArch64_AM::getArithExtendImm(AArch64_AM::UXTH, 0),
14830b57cec5SDimitry Andric                           AArch64::WZR, NextMBBI);
14840b57cec5SDimitry Andric   case AArch64::CMP_SWAP_32:
14850b57cec5SDimitry Andric     return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRW, AArch64::STLXRW,
14860b57cec5SDimitry Andric                           AArch64::SUBSWrs,
14870b57cec5SDimitry Andric                           AArch64_AM::getShifterImm(AArch64_AM::LSL, 0),
14880b57cec5SDimitry Andric                           AArch64::WZR, NextMBBI);
14890b57cec5SDimitry Andric   case AArch64::CMP_SWAP_64:
14900b57cec5SDimitry Andric     return expandCMP_SWAP(MBB, MBBI,
14910b57cec5SDimitry Andric                           AArch64::LDAXRX, AArch64::STLXRX, AArch64::SUBSXrs,
14920b57cec5SDimitry Andric                           AArch64_AM::getShifterImm(AArch64_AM::LSL, 0),
14930b57cec5SDimitry Andric                           AArch64::XZR, NextMBBI);
14940b57cec5SDimitry Andric   case AArch64::CMP_SWAP_128:
1495fe6060f1SDimitry Andric   case AArch64::CMP_SWAP_128_RELEASE:
1496fe6060f1SDimitry Andric   case AArch64::CMP_SWAP_128_ACQUIRE:
1497fe6060f1SDimitry Andric   case AArch64::CMP_SWAP_128_MONOTONIC:
14980b57cec5SDimitry Andric     return expandCMP_SWAP_128(MBB, MBBI, NextMBBI);
14990b57cec5SDimitry Andric 
15000b57cec5SDimitry Andric   case AArch64::AESMCrrTied:
15010b57cec5SDimitry Andric   case AArch64::AESIMCrrTied: {
15020b57cec5SDimitry Andric     MachineInstrBuilder MIB =
15030b57cec5SDimitry Andric     BuildMI(MBB, MBBI, MI.getDebugLoc(),
15040b57cec5SDimitry Andric             TII->get(Opcode == AArch64::AESMCrrTied ? AArch64::AESMCrr :
15050b57cec5SDimitry Andric                                                       AArch64::AESIMCrr))
15060b57cec5SDimitry Andric       .add(MI.getOperand(0))
15070b57cec5SDimitry Andric       .add(MI.getOperand(1));
15080b57cec5SDimitry Andric     transferImpOps(MI, MIB, MIB);
15090b57cec5SDimitry Andric     MI.eraseFromParent();
15100b57cec5SDimitry Andric     return true;
15110b57cec5SDimitry Andric    }
15120b57cec5SDimitry Andric    case AArch64::IRGstack: {
15130b57cec5SDimitry Andric      MachineFunction &MF = *MBB.getParent();
15140b57cec5SDimitry Andric      const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
15150b57cec5SDimitry Andric      const AArch64FrameLowering *TFI =
15160b57cec5SDimitry Andric          MF.getSubtarget<AArch64Subtarget>().getFrameLowering();
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric      // IRG does not allow immediate offset. getTaggedBasePointerOffset should
15190b57cec5SDimitry Andric      // almost always point to SP-after-prologue; if not, emit a longer
15200b57cec5SDimitry Andric      // instruction sequence.
15210b57cec5SDimitry Andric      int BaseOffset = -AFI->getTaggedBasePointerOffset();
15225ffd83dbSDimitry Andric      Register FrameReg;
15238bcb0991SDimitry Andric      StackOffset FrameRegOffset = TFI->resolveFrameOffsetReference(
15248bcb0991SDimitry Andric          MF, BaseOffset, false /*isFixed*/, false /*isSVE*/, FrameReg,
15258bcb0991SDimitry Andric          /*PreferFP=*/false,
15260b57cec5SDimitry Andric          /*ForSimm=*/true);
15270b57cec5SDimitry Andric      Register SrcReg = FrameReg;
15288bcb0991SDimitry Andric      if (FrameRegOffset) {
15290b57cec5SDimitry Andric        // Use output register as temporary.
15300b57cec5SDimitry Andric        SrcReg = MI.getOperand(0).getReg();
15310b57cec5SDimitry Andric        emitFrameOffset(MBB, &MI, MI.getDebugLoc(), SrcReg, FrameReg,
15320b57cec5SDimitry Andric                        FrameRegOffset, TII);
15330b57cec5SDimitry Andric      }
15340b57cec5SDimitry Andric      BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::IRG))
15350b57cec5SDimitry Andric          .add(MI.getOperand(0))
15360b57cec5SDimitry Andric          .addUse(SrcReg)
15370b57cec5SDimitry Andric          .add(MI.getOperand(2));
15380b57cec5SDimitry Andric      MI.eraseFromParent();
15390b57cec5SDimitry Andric      return true;
15400b57cec5SDimitry Andric    }
15410b57cec5SDimitry Andric    case AArch64::TAGPstack: {
1542480093f4SDimitry Andric      int64_t Offset = MI.getOperand(2).getImm();
1543480093f4SDimitry Andric      BuildMI(MBB, MBBI, MI.getDebugLoc(),
1544480093f4SDimitry Andric              TII->get(Offset >= 0 ? AArch64::ADDG : AArch64::SUBG))
15450b57cec5SDimitry Andric          .add(MI.getOperand(0))
15460b57cec5SDimitry Andric          .add(MI.getOperand(1))
1547480093f4SDimitry Andric          .addImm(std::abs(Offset))
15480b57cec5SDimitry Andric          .add(MI.getOperand(4));
15490b57cec5SDimitry Andric      MI.eraseFromParent();
15500b57cec5SDimitry Andric      return true;
15510b57cec5SDimitry Andric    }
15525ffd83dbSDimitry Andric    case AArch64::STGloop_wback:
15535ffd83dbSDimitry Andric    case AArch64::STZGloop_wback:
15545ffd83dbSDimitry Andric      return expandSetTagLoop(MBB, MBBI, NextMBBI);
15550b57cec5SDimitry Andric    case AArch64::STGloop:
15560b57cec5SDimitry Andric    case AArch64::STZGloop:
15575ffd83dbSDimitry Andric      report_fatal_error(
15585ffd83dbSDimitry Andric          "Non-writeback variants of STGloop / STZGloop should not "
15595ffd83dbSDimitry Andric          "survive past PrologEpilogInserter.");
15605ffd83dbSDimitry Andric    case AArch64::STR_ZZZZXI:
15615ffd83dbSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 4);
15625ffd83dbSDimitry Andric    case AArch64::STR_ZZZXI:
15635ffd83dbSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 3);
15645ffd83dbSDimitry Andric    case AArch64::STR_ZZXI:
15655ffd83dbSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 2);
1566cb14a3feSDimitry Andric    case AArch64::STR_PPXI:
1567cb14a3feSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::STR_PXI, 2);
15685ffd83dbSDimitry Andric    case AArch64::LDR_ZZZZXI:
15695ffd83dbSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 4);
15705ffd83dbSDimitry Andric    case AArch64::LDR_ZZZXI:
15715ffd83dbSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 3);
15725ffd83dbSDimitry Andric    case AArch64::LDR_ZZXI:
15735ffd83dbSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 2);
1574cb14a3feSDimitry Andric    case AArch64::LDR_PPXI:
1575cb14a3feSDimitry Andric      return expandSVESpillFill(MBB, MBBI, AArch64::LDR_PXI, 2);
1576e8d8bef9SDimitry Andric    case AArch64::BLR_RVMARKER:
1577*0fca6ea1SDimitry Andric    case AArch64::BLRA_RVMARKER:
1578e8d8bef9SDimitry Andric      return expandCALL_RVMARKER(MBB, MBBI);
15793a9a9c0cSDimitry Andric    case AArch64::BLR_BTI:
15803a9a9c0cSDimitry Andric      return expandCALL_BTI(MBB, MBBI);
1581fe6060f1SDimitry Andric    case AArch64::StoreSwiftAsyncContext:
1582fe6060f1SDimitry Andric      return expandStoreSwiftAsyncContext(MBB, MBBI);
1583bdd1243dSDimitry Andric    case AArch64::RestoreZAPseudo: {
1584bdd1243dSDimitry Andric      auto *NewMBB = expandRestoreZA(MBB, MBBI);
1585bdd1243dSDimitry Andric      if (NewMBB != &MBB)
1586bdd1243dSDimitry Andric        NextMBBI = MBB.end(); // The NextMBBI iterator is invalidated.
1587bdd1243dSDimitry Andric      return true;
1588bdd1243dSDimitry Andric    }
1589bdd1243dSDimitry Andric    case AArch64::MSRpstatePseudo: {
1590bdd1243dSDimitry Andric      auto *NewMBB = expandCondSMToggle(MBB, MBBI);
1591bdd1243dSDimitry Andric      if (NewMBB != &MBB)
1592bdd1243dSDimitry Andric        NextMBBI = MBB.end(); // The NextMBBI iterator is invalidated.
1593bdd1243dSDimitry Andric      return true;
1594bdd1243dSDimitry Andric    }
1595b3edf446SDimitry Andric    case AArch64::COALESCER_BARRIER_FPR16:
1596b3edf446SDimitry Andric    case AArch64::COALESCER_BARRIER_FPR32:
1597b3edf446SDimitry Andric    case AArch64::COALESCER_BARRIER_FPR64:
1598b3edf446SDimitry Andric    case AArch64::COALESCER_BARRIER_FPR128:
1599b3edf446SDimitry Andric      MI.eraseFromParent();
1600b3edf446SDimitry Andric      return true;
16015f757f3fSDimitry Andric    case AArch64::LD1B_2Z_IMM_PSEUDO:
16025f757f3fSDimitry Andric      return expandMultiVecPseudo(
16035f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16045f757f3fSDimitry Andric          AArch64::LD1B_2Z_IMM, AArch64::LD1B_2Z_STRIDED_IMM);
16055f757f3fSDimitry Andric    case AArch64::LD1H_2Z_IMM_PSEUDO:
16065f757f3fSDimitry Andric      return expandMultiVecPseudo(
16075f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16085f757f3fSDimitry Andric          AArch64::LD1H_2Z_IMM, AArch64::LD1H_2Z_STRIDED_IMM);
16095f757f3fSDimitry Andric    case AArch64::LD1W_2Z_IMM_PSEUDO:
16105f757f3fSDimitry Andric      return expandMultiVecPseudo(
16115f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16125f757f3fSDimitry Andric          AArch64::LD1W_2Z_IMM, AArch64::LD1W_2Z_STRIDED_IMM);
16135f757f3fSDimitry Andric    case AArch64::LD1D_2Z_IMM_PSEUDO:
16145f757f3fSDimitry Andric      return expandMultiVecPseudo(
16155f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16165f757f3fSDimitry Andric          AArch64::LD1D_2Z_IMM, AArch64::LD1D_2Z_STRIDED_IMM);
16175f757f3fSDimitry Andric    case AArch64::LDNT1B_2Z_IMM_PSEUDO:
16185f757f3fSDimitry Andric      return expandMultiVecPseudo(
16195f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16205f757f3fSDimitry Andric          AArch64::LDNT1B_2Z_IMM, AArch64::LDNT1B_2Z_STRIDED_IMM);
16215f757f3fSDimitry Andric    case AArch64::LDNT1H_2Z_IMM_PSEUDO:
16225f757f3fSDimitry Andric      return expandMultiVecPseudo(
16235f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16245f757f3fSDimitry Andric          AArch64::LDNT1H_2Z_IMM, AArch64::LDNT1H_2Z_STRIDED_IMM);
16255f757f3fSDimitry Andric    case AArch64::LDNT1W_2Z_IMM_PSEUDO:
16265f757f3fSDimitry Andric      return expandMultiVecPseudo(
16275f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16285f757f3fSDimitry Andric          AArch64::LDNT1W_2Z_IMM, AArch64::LDNT1W_2Z_STRIDED_IMM);
16295f757f3fSDimitry Andric    case AArch64::LDNT1D_2Z_IMM_PSEUDO:
16305f757f3fSDimitry Andric      return expandMultiVecPseudo(
16315f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16325f757f3fSDimitry Andric          AArch64::LDNT1D_2Z_IMM, AArch64::LDNT1D_2Z_STRIDED_IMM);
16335f757f3fSDimitry Andric    case AArch64::LD1B_2Z_PSEUDO:
16345f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
16355f757f3fSDimitry Andric                                  AArch64::ZPR2StridedRegClass, AArch64::LD1B_2Z,
16365f757f3fSDimitry Andric                                  AArch64::LD1B_2Z_STRIDED);
16375f757f3fSDimitry Andric    case AArch64::LD1H_2Z_PSEUDO:
16385f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
16395f757f3fSDimitry Andric                                  AArch64::ZPR2StridedRegClass, AArch64::LD1H_2Z,
16405f757f3fSDimitry Andric                                  AArch64::LD1H_2Z_STRIDED);
16415f757f3fSDimitry Andric    case AArch64::LD1W_2Z_PSEUDO:
16425f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
16435f757f3fSDimitry Andric                                  AArch64::ZPR2StridedRegClass, AArch64::LD1W_2Z,
16445f757f3fSDimitry Andric                                  AArch64::LD1W_2Z_STRIDED);
16455f757f3fSDimitry Andric    case AArch64::LD1D_2Z_PSEUDO:
16465f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
16475f757f3fSDimitry Andric                                  AArch64::ZPR2StridedRegClass, AArch64::LD1D_2Z,
16485f757f3fSDimitry Andric                                  AArch64::LD1D_2Z_STRIDED);
16495f757f3fSDimitry Andric    case AArch64::LDNT1B_2Z_PSEUDO:
16505f757f3fSDimitry Andric      return expandMultiVecPseudo(
16515f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16525f757f3fSDimitry Andric          AArch64::LDNT1B_2Z, AArch64::LDNT1B_2Z_STRIDED);
16535f757f3fSDimitry Andric    case AArch64::LDNT1H_2Z_PSEUDO:
16545f757f3fSDimitry Andric      return expandMultiVecPseudo(
16555f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16565f757f3fSDimitry Andric          AArch64::LDNT1H_2Z, AArch64::LDNT1H_2Z_STRIDED);
16575f757f3fSDimitry Andric    case AArch64::LDNT1W_2Z_PSEUDO:
16585f757f3fSDimitry Andric      return expandMultiVecPseudo(
16595f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16605f757f3fSDimitry Andric          AArch64::LDNT1W_2Z, AArch64::LDNT1W_2Z_STRIDED);
16615f757f3fSDimitry Andric    case AArch64::LDNT1D_2Z_PSEUDO:
16625f757f3fSDimitry Andric      return expandMultiVecPseudo(
16635f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
16645f757f3fSDimitry Andric          AArch64::LDNT1D_2Z, AArch64::LDNT1D_2Z_STRIDED);
16655f757f3fSDimitry Andric    case AArch64::LD1B_4Z_IMM_PSEUDO:
16665f757f3fSDimitry Andric      return expandMultiVecPseudo(
16675f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16685f757f3fSDimitry Andric          AArch64::LD1B_4Z_IMM, AArch64::LD1B_4Z_STRIDED_IMM);
16695f757f3fSDimitry Andric    case AArch64::LD1H_4Z_IMM_PSEUDO:
16705f757f3fSDimitry Andric      return expandMultiVecPseudo(
16715f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16725f757f3fSDimitry Andric          AArch64::LD1H_4Z_IMM, AArch64::LD1H_4Z_STRIDED_IMM);
16735f757f3fSDimitry Andric    case AArch64::LD1W_4Z_IMM_PSEUDO:
16745f757f3fSDimitry Andric      return expandMultiVecPseudo(
16755f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16765f757f3fSDimitry Andric          AArch64::LD1W_4Z_IMM, AArch64::LD1W_4Z_STRIDED_IMM);
16775f757f3fSDimitry Andric    case AArch64::LD1D_4Z_IMM_PSEUDO:
16785f757f3fSDimitry Andric      return expandMultiVecPseudo(
16795f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16805f757f3fSDimitry Andric          AArch64::LD1D_4Z_IMM, AArch64::LD1D_4Z_STRIDED_IMM);
16815f757f3fSDimitry Andric    case AArch64::LDNT1B_4Z_IMM_PSEUDO:
16825f757f3fSDimitry Andric      return expandMultiVecPseudo(
16835f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16845f757f3fSDimitry Andric          AArch64::LDNT1B_4Z_IMM, AArch64::LDNT1B_4Z_STRIDED_IMM);
16855f757f3fSDimitry Andric    case AArch64::LDNT1H_4Z_IMM_PSEUDO:
16865f757f3fSDimitry Andric      return expandMultiVecPseudo(
16875f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16885f757f3fSDimitry Andric          AArch64::LDNT1H_4Z_IMM, AArch64::LDNT1H_4Z_STRIDED_IMM);
16895f757f3fSDimitry Andric    case AArch64::LDNT1W_4Z_IMM_PSEUDO:
16905f757f3fSDimitry Andric      return expandMultiVecPseudo(
16915f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16925f757f3fSDimitry Andric          AArch64::LDNT1W_4Z_IMM, AArch64::LDNT1W_4Z_STRIDED_IMM);
16935f757f3fSDimitry Andric    case AArch64::LDNT1D_4Z_IMM_PSEUDO:
16945f757f3fSDimitry Andric      return expandMultiVecPseudo(
16955f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
16965f757f3fSDimitry Andric          AArch64::LDNT1D_4Z_IMM, AArch64::LDNT1D_4Z_STRIDED_IMM);
16975f757f3fSDimitry Andric    case AArch64::LD1B_4Z_PSEUDO:
16985f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
16995f757f3fSDimitry Andric                                  AArch64::ZPR4StridedRegClass, AArch64::LD1B_4Z,
17005f757f3fSDimitry Andric                                  AArch64::LD1B_4Z_STRIDED);
17015f757f3fSDimitry Andric    case AArch64::LD1H_4Z_PSEUDO:
17025f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
17035f757f3fSDimitry Andric                                  AArch64::ZPR4StridedRegClass, AArch64::LD1H_4Z,
17045f757f3fSDimitry Andric                                  AArch64::LD1H_4Z_STRIDED);
17055f757f3fSDimitry Andric    case AArch64::LD1W_4Z_PSEUDO:
17065f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
17075f757f3fSDimitry Andric                                  AArch64::ZPR4StridedRegClass, AArch64::LD1W_4Z,
17085f757f3fSDimitry Andric                                  AArch64::LD1W_4Z_STRIDED);
17095f757f3fSDimitry Andric    case AArch64::LD1D_4Z_PSEUDO:
17105f757f3fSDimitry Andric      return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
17115f757f3fSDimitry Andric                                  AArch64::ZPR4StridedRegClass, AArch64::LD1D_4Z,
17125f757f3fSDimitry Andric                                  AArch64::LD1D_4Z_STRIDED);
17135f757f3fSDimitry Andric    case AArch64::LDNT1B_4Z_PSEUDO:
17145f757f3fSDimitry Andric      return expandMultiVecPseudo(
17155f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
17165f757f3fSDimitry Andric          AArch64::LDNT1B_4Z, AArch64::LDNT1B_4Z_STRIDED);
17175f757f3fSDimitry Andric    case AArch64::LDNT1H_4Z_PSEUDO:
17185f757f3fSDimitry Andric      return expandMultiVecPseudo(
17195f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
17205f757f3fSDimitry Andric          AArch64::LDNT1H_4Z, AArch64::LDNT1H_4Z_STRIDED);
17215f757f3fSDimitry Andric    case AArch64::LDNT1W_4Z_PSEUDO:
17225f757f3fSDimitry Andric      return expandMultiVecPseudo(
17235f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
17245f757f3fSDimitry Andric          AArch64::LDNT1W_4Z, AArch64::LDNT1W_4Z_STRIDED);
17255f757f3fSDimitry Andric    case AArch64::LDNT1D_4Z_PSEUDO:
17265f757f3fSDimitry Andric      return expandMultiVecPseudo(
17275f757f3fSDimitry Andric          MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
17285f757f3fSDimitry Andric          AArch64::LDNT1D_4Z, AArch64::LDNT1D_4Z_STRIDED);
17290b57cec5SDimitry Andric   }
17300b57cec5SDimitry Andric   return false;
17310b57cec5SDimitry Andric }
17320b57cec5SDimitry Andric 
17330b57cec5SDimitry Andric /// Iterate over the instructions in basic block MBB and expand any
17340b57cec5SDimitry Andric /// pseudo instructions.  Return true if anything was modified.
17350b57cec5SDimitry Andric bool AArch64ExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
17360b57cec5SDimitry Andric   bool Modified = false;
17370b57cec5SDimitry Andric 
17380b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
17390b57cec5SDimitry Andric   while (MBBI != E) {
17400b57cec5SDimitry Andric     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
17410b57cec5SDimitry Andric     Modified |= expandMI(MBB, MBBI, NMBBI);
17420b57cec5SDimitry Andric     MBBI = NMBBI;
17430b57cec5SDimitry Andric   }
17440b57cec5SDimitry Andric 
17450b57cec5SDimitry Andric   return Modified;
17460b57cec5SDimitry Andric }
17470b57cec5SDimitry Andric 
17480b57cec5SDimitry Andric bool AArch64ExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
17490b57cec5SDimitry Andric   TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
17500b57cec5SDimitry Andric 
17510b57cec5SDimitry Andric   bool Modified = false;
17520b57cec5SDimitry Andric   for (auto &MBB : MF)
17530b57cec5SDimitry Andric     Modified |= expandMBB(MBB);
17540b57cec5SDimitry Andric   return Modified;
17550b57cec5SDimitry Andric }
17560b57cec5SDimitry Andric 
17570b57cec5SDimitry Andric /// Returns an instance of the pseudo instruction expansion pass.
17580b57cec5SDimitry Andric FunctionPass *llvm::createAArch64ExpandPseudoPass() {
17590b57cec5SDimitry Andric   return new AArch64ExpandPseudo();
17600b57cec5SDimitry Andric }
1761