| //===- AArch64PostCoalescerPass.cpp - AArch64 Post Coalescer pass ---------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "AArch64.h" | |
| #include "AArch64MachineFunctionInfo.h" | |
| #include "llvm/CodeGen/LiveIntervals.h" | |
| #include "llvm/CodeGen/MachineFunctionPass.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/InitializePasses.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "aarch64-post-coalescer" | |
| namespace { | |
| /// Expands FORM_TRANSPOSED_REG_TUPLE_{X2|X4}_PSEUDO instructions into copy | |
| /// sequences. Note: This expansion occurs immediately before greedy regalloc | |
| /// and after the coalescer and pre-RA scheduler. | |
| /// | |
| /// Example: | |
| /// | |
| /// %v2:zpr2 = FORM_TRANSPOSED_REG_TUPLE_X2_PSEUDO %v0.zsub0, %v1.zsub0 | |
| /// | |
| /// Expands to: | |
| /// | |
| /// undef %v2.zsub0:zpr2 = COPY_INTO_TRANSPOSED_TUPLE %v0.zsub0, 2 | |
| /// %v2.zsub1:zpr2 = COPY_INTO_TRANSPOSED_TUPLE %v1.zsub0, 2 | |
| static bool expandFormTransposedRegTuple(MachineBasicBlock &MBB, | |
| MachineInstr &MI, LiveIntervals *LIS) { | |
| const TargetInstrInfo *TII = | |
| MBB.getParent()->getSubtarget<AArch64Subtarget>().getInstrInfo(); | |
| unsigned TupleSize = | |
| MI.getOpcode() == AArch64::FORM_TRANSPOSED_REG_TUPLE_X2_PSEUDO ? 2 : 4; | |
| DebugLoc DL = MI.getDebugLoc(); | |
| Register TupleReg = MI.getOperand(0).getReg(); | |
| SmallVector<Register, 5> OrigRegs{TupleReg}; | |
| MachineBasicBlock::iterator FirstCopyMBBI; | |
| for (unsigned I = 0; I < TupleSize; ++I) { | |
| MachineOperand &SrcOp = MI.getOperand(I + 1); | |
| OrigRegs.push_back(SrcOp.getReg()); | |
| // Ensure that if operand is killed, the kill flag is placed on the final | |
| // copy for that operand. | |
| if (SrcOp.isKill()) { | |
| for (unsigned J = I + 2; J < MI.getNumOperands(); ++J) { | |
| MachineOperand &LaterOp = MI.getOperand(J); | |
| if (LaterOp.getReg() == SrcOp.getReg()) { | |
| LaterOp.setIsKill(); | |
| SrcOp.setIsKill(false); | |
| } | |
| } | |
| } | |
| RegState DefState = I == 0 ? RegState::Undef : RegState::NoFlags; | |
| MachineInstr *CopyMI = | |
| BuildMI(MBB, MI, DL, TII->get(AArch64::COPY_INTO_TRANSPOSED_TUPLE)) | |
| .addDef(TupleReg, DefState, AArch64::zsub0 + I) | |
| .add(SrcOp) | |
| .addImm(TupleSize); | |
| if (I == 0) | |
| FirstCopyMBBI = CopyMI; | |
| } | |
| MachineBasicBlock::iterator EndMBBI = std::next(MI.getIterator()); | |
| if (LIS) | |
| LIS->RemoveMachineInstrFromMaps(MI); | |
| MI.eraseFromParent(); | |
| if (LIS) | |
| LIS->repairIntervalsInRange(&MBB, FirstCopyMBBI, EndMBBI, OrigRegs); | |
| return true; | |
| } | |
| bool runAArch64PostCoalescer(MachineFunction &MF, LiveIntervals *LIS) { | |
| AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>(); | |
| if (!FuncInfo->hasStreamingModeChanges() && | |
| !MF.getSubtarget<AArch64Subtarget>().isStreaming()) | |
| return false; | |
| MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| bool Changed = false; | |
| for (MachineBasicBlock &MBB : MF) { | |
| for (MachineInstr &MI : make_early_inc_range(MBB)) { | |
| switch (MI.getOpcode()) { | |
| default: | |
| break; | |
| case AArch64::FORM_TRANSPOSED_REG_TUPLE_X2_PSEUDO: | |
| case AArch64::FORM_TRANSPOSED_REG_TUPLE_X4_PSEUDO: | |
| Changed |= expandFormTransposedRegTuple(MBB, MI, LIS); | |
| break; | |
| case AArch64::COALESCER_BARRIER_FPR16: | |
| case AArch64::COALESCER_BARRIER_FPR32: | |
| case AArch64::COALESCER_BARRIER_FPR64: | |
| case AArch64::COALESCER_BARRIER_FPR128: { | |
| Register Src = MI.getOperand(1).getReg(); | |
| Register Dst = MI.getOperand(0).getReg(); | |
| if (Src != Dst) | |
| MRI.replaceRegWith(Dst, Src); | |
| if (MI.getOperand(1).isUndef()) | |
| for (MachineOperand &MO : MRI.use_operands(Dst)) | |
| MO.setIsUndef(); | |
| // MI must be erased from the basic block before recalculating the live | |
| // interval. | |
| if (LIS) | |
| LIS->RemoveMachineInstrFromMaps(MI); | |
| MI.eraseFromParent(); | |
| if (LIS) { | |
| LIS->removeInterval(Src); | |
| LIS->createAndComputeVirtRegInterval(Src); | |
| } | |
| Changed = true; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| return Changed; | |
| } | |
| struct AArch64PostCoalescerLegacy : public MachineFunctionPass { | |
| static char ID; | |
| AArch64PostCoalescerLegacy() : MachineFunctionPass(ID) {} | |
| bool runOnMachineFunction(MachineFunction &MF) override; | |
| StringRef getPassName() const override { | |
| return "AArch64 Post Coalescer pass"; | |
| } | |
| void getAnalysisUsage(AnalysisUsage &AU) const override { | |
| AU.setPreservesCFG(); | |
| AU.addUsedIfAvailable<LiveIntervalsWrapperPass>(); | |
| AU.addPreserved<LiveIntervalsWrapperPass>(); | |
| AU.addPreserved<SlotIndexesWrapperPass>(); | |
| MachineFunctionPass::getAnalysisUsage(AU); | |
| } | |
| }; | |
| char AArch64PostCoalescerLegacy::ID = 0; | |
| } // end anonymous namespace | |
| INITIALIZE_PASS_BEGIN(AArch64PostCoalescerLegacy, "aarch64-post-coalescer", | |
| "AArch64 Post Coalescer Pass", false, false) | |
| INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass) | |
| INITIALIZE_PASS_END(AArch64PostCoalescerLegacy, "aarch64-post-coalescer", | |
| "AArch64 Post Coalescer Pass", false, false) | |
| bool AArch64PostCoalescerLegacy::runOnMachineFunction(MachineFunction &MF) { | |
| if (skipFunction(MF.getFunction())) | |
| return false; | |
| auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>(); | |
| auto *LIS = LISWrapper ? &LISWrapper->getLIS() : nullptr; | |
| return runAArch64PostCoalescer(MF, LIS); | |
| } | |
| PreservedAnalyses | |
| AArch64PostCoalescerPass::run(MachineFunction &MF, | |
| MachineFunctionAnalysisManager &MFAM) { | |
| auto *LIS = MFAM.getCachedResult<LiveIntervalsAnalysis>(MF); | |
| const bool Changed = runAArch64PostCoalescer(MF, LIS); | |
| if (!Changed) | |
| return PreservedAnalyses::all(); | |
| PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses(); | |
| PA.preserveSet<CFGAnalyses>(); | |
| PA.preserve<LiveIntervalsAnalysis>(); | |
| PA.preserve<SlotIndexesAnalysis>(); | |
| return PA; | |
| } | |
| FunctionPass *llvm::createAArch64PostCoalescerPass() { | |
| return new AArch64PostCoalescerLegacy(); | |
| } |