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