1*06c3fb27SDimitry Andric //===-- RISCVMoveMerger.cpp - RISCV move merge pass -----------------------===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric // 9*06c3fb27SDimitry Andric // This file contains a pass that performs move related peephole optimizations 10*06c3fb27SDimitry Andric // as Zcmp has specified. This pass should be run after register allocation. 11*06c3fb27SDimitry Andric // 12*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 13*06c3fb27SDimitry Andric 14*06c3fb27SDimitry Andric #include "RISCVInstrInfo.h" 15*06c3fb27SDimitry Andric #include "RISCVMachineFunctionInfo.h" 16*06c3fb27SDimitry Andric 17*06c3fb27SDimitry Andric using namespace llvm; 18*06c3fb27SDimitry Andric 19*06c3fb27SDimitry Andric #define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass" 20*06c3fb27SDimitry Andric 21*06c3fb27SDimitry Andric namespace { 22*06c3fb27SDimitry Andric struct RISCVMoveMerge : public MachineFunctionPass { 23*06c3fb27SDimitry Andric static char ID; 24*06c3fb27SDimitry Andric 25*06c3fb27SDimitry Andric RISCVMoveMerge() : MachineFunctionPass(ID) { 26*06c3fb27SDimitry Andric initializeRISCVMoveMergePass(*PassRegistry::getPassRegistry()); 27*06c3fb27SDimitry Andric } 28*06c3fb27SDimitry Andric 29*06c3fb27SDimitry Andric const RISCVInstrInfo *TII; 30*06c3fb27SDimitry Andric const TargetRegisterInfo *TRI; 31*06c3fb27SDimitry Andric 32*06c3fb27SDimitry Andric // Track which register units have been modified and used. 33*06c3fb27SDimitry Andric LiveRegUnits ModifiedRegUnits, UsedRegUnits; 34*06c3fb27SDimitry Andric 35*06c3fb27SDimitry Andric bool isCandidateToMergeMVA01S(const DestSourcePair &RegPair); 36*06c3fb27SDimitry Andric bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair); 37*06c3fb27SDimitry Andric // Merge the two instructions indicated into a single pair instruction. 38*06c3fb27SDimitry Andric MachineBasicBlock::iterator 39*06c3fb27SDimitry Andric mergePairedInsns(MachineBasicBlock::iterator I, 40*06c3fb27SDimitry Andric MachineBasicBlock::iterator Paired, unsigned Opcode); 41*06c3fb27SDimitry Andric 42*06c3fb27SDimitry Andric // Look for C.MV instruction that can be combined with 43*06c3fb27SDimitry Andric // the given instruction into CM.MVA01S or CM.MVSA01. Return the matching 44*06c3fb27SDimitry Andric // instruction if one exists. 45*06c3fb27SDimitry Andric MachineBasicBlock::iterator 46*06c3fb27SDimitry Andric findMatchingInst(MachineBasicBlock::iterator &MBBI, unsigned InstOpcode, 47*06c3fb27SDimitry Andric const DestSourcePair &RegPair); 48*06c3fb27SDimitry Andric bool mergeMoveSARegPair(MachineBasicBlock &MBB); 49*06c3fb27SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 50*06c3fb27SDimitry Andric 51*06c3fb27SDimitry Andric StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; } 52*06c3fb27SDimitry Andric }; 53*06c3fb27SDimitry Andric 54*06c3fb27SDimitry Andric char RISCVMoveMerge::ID = 0; 55*06c3fb27SDimitry Andric 56*06c3fb27SDimitry Andric } // end of anonymous namespace 57*06c3fb27SDimitry Andric 58*06c3fb27SDimitry Andric INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME, 59*06c3fb27SDimitry Andric false, false) 60*06c3fb27SDimitry Andric 61*06c3fb27SDimitry Andric // Check if registers meet CM.MVA01S constraints. 62*06c3fb27SDimitry Andric bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) { 63*06c3fb27SDimitry Andric Register Destination = RegPair.Destination->getReg(); 64*06c3fb27SDimitry Andric Register Source = RegPair.Source->getReg(); 65*06c3fb27SDimitry Andric // If destination is not a0 or a1. 66*06c3fb27SDimitry Andric if ((Destination == RISCV::X10 || Destination == RISCV::X11) && 67*06c3fb27SDimitry Andric RISCV::SR07RegClass.contains(Source)) 68*06c3fb27SDimitry Andric return true; 69*06c3fb27SDimitry Andric return false; 70*06c3fb27SDimitry Andric } 71*06c3fb27SDimitry Andric 72*06c3fb27SDimitry Andric // Check if registers meet CM.MVSA01 constraints. 73*06c3fb27SDimitry Andric bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) { 74*06c3fb27SDimitry Andric Register Destination = RegPair.Destination->getReg(); 75*06c3fb27SDimitry Andric Register Source = RegPair.Source->getReg(); 76*06c3fb27SDimitry Andric // If Source is s0 - s7. 77*06c3fb27SDimitry Andric if ((Source == RISCV::X10 || Source == RISCV::X11) && 78*06c3fb27SDimitry Andric RISCV::SR07RegClass.contains(Destination)) 79*06c3fb27SDimitry Andric return true; 80*06c3fb27SDimitry Andric return false; 81*06c3fb27SDimitry Andric } 82*06c3fb27SDimitry Andric 83*06c3fb27SDimitry Andric MachineBasicBlock::iterator 84*06c3fb27SDimitry Andric RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I, 85*06c3fb27SDimitry Andric MachineBasicBlock::iterator Paired, 86*06c3fb27SDimitry Andric unsigned Opcode) { 87*06c3fb27SDimitry Andric const MachineOperand *Sreg1, *Sreg2; 88*06c3fb27SDimitry Andric MachineBasicBlock::iterator E = I->getParent()->end(); 89*06c3fb27SDimitry Andric MachineBasicBlock::iterator NextI = next_nodbg(I, E); 90*06c3fb27SDimitry Andric DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value(); 91*06c3fb27SDimitry Andric DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value(); 92*06c3fb27SDimitry Andric Register ARegInFirstPair = Opcode == RISCV::CM_MVA01S 93*06c3fb27SDimitry Andric ? FirstPair.Destination->getReg() 94*06c3fb27SDimitry Andric : FirstPair.Source->getReg(); 95*06c3fb27SDimitry Andric 96*06c3fb27SDimitry Andric if (NextI == Paired) 97*06c3fb27SDimitry Andric NextI = next_nodbg(NextI, E); 98*06c3fb27SDimitry Andric DebugLoc DL = I->getDebugLoc(); 99*06c3fb27SDimitry Andric 100*06c3fb27SDimitry Andric // The order of S-reg depends on which instruction holds A0, instead of 101*06c3fb27SDimitry Andric // the order of register pair. 102*06c3fb27SDimitry Andric // e,g. 103*06c3fb27SDimitry Andric // mv a1, s1 104*06c3fb27SDimitry Andric // mv a0, s2 => cm.mva01s s2,s1 105*06c3fb27SDimitry Andric // 106*06c3fb27SDimitry Andric // mv a0, s2 107*06c3fb27SDimitry Andric // mv a1, s1 => cm.mva01s s2,s1 108*06c3fb27SDimitry Andric bool StartWithX10 = ARegInFirstPair == RISCV::X10; 109*06c3fb27SDimitry Andric if (Opcode == RISCV::CM_MVA01S) { 110*06c3fb27SDimitry Andric Sreg1 = StartWithX10 ? FirstPair.Source : PairedRegs.Source; 111*06c3fb27SDimitry Andric Sreg2 = StartWithX10 ? PairedRegs.Source : FirstPair.Source; 112*06c3fb27SDimitry Andric } else { 113*06c3fb27SDimitry Andric Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination; 114*06c3fb27SDimitry Andric Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination; 115*06c3fb27SDimitry Andric } 116*06c3fb27SDimitry Andric 117*06c3fb27SDimitry Andric BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2); 118*06c3fb27SDimitry Andric 119*06c3fb27SDimitry Andric I->eraseFromParent(); 120*06c3fb27SDimitry Andric Paired->eraseFromParent(); 121*06c3fb27SDimitry Andric return NextI; 122*06c3fb27SDimitry Andric } 123*06c3fb27SDimitry Andric 124*06c3fb27SDimitry Andric MachineBasicBlock::iterator 125*06c3fb27SDimitry Andric RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI, 126*06c3fb27SDimitry Andric unsigned InstOpcode, 127*06c3fb27SDimitry Andric const DestSourcePair &RegPair) { 128*06c3fb27SDimitry Andric MachineBasicBlock::iterator E = MBBI->getParent()->end(); 129*06c3fb27SDimitry Andric 130*06c3fb27SDimitry Andric // Track which register units have been modified and used between the first 131*06c3fb27SDimitry Andric // insn and the second insn. 132*06c3fb27SDimitry Andric ModifiedRegUnits.clear(); 133*06c3fb27SDimitry Andric UsedRegUnits.clear(); 134*06c3fb27SDimitry Andric 135*06c3fb27SDimitry Andric for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E; 136*06c3fb27SDimitry Andric I = next_nodbg(I, E)) { 137*06c3fb27SDimitry Andric 138*06c3fb27SDimitry Andric MachineInstr &MI = *I; 139*06c3fb27SDimitry Andric 140*06c3fb27SDimitry Andric if (auto SecondPair = TII->isCopyInstrImpl(MI)) { 141*06c3fb27SDimitry Andric Register SourceReg = SecondPair->Source->getReg(); 142*06c3fb27SDimitry Andric Register DestReg = SecondPair->Destination->getReg(); 143*06c3fb27SDimitry Andric 144*06c3fb27SDimitry Andric if (InstOpcode == RISCV::CM_MVA01S && 145*06c3fb27SDimitry Andric isCandidateToMergeMVA01S(*SecondPair)) { 146*06c3fb27SDimitry Andric // If register pair is valid and destination registers are different. 147*06c3fb27SDimitry Andric if ((RegPair.Destination->getReg() == DestReg)) 148*06c3fb27SDimitry Andric return E; 149*06c3fb27SDimitry Andric 150*06c3fb27SDimitry Andric // If paired destination register was modified or used, the source reg 151*06c3fb27SDimitry Andric // was modified, there is no possibility of finding matching 152*06c3fb27SDimitry Andric // instruction so exit early. 153*06c3fb27SDimitry Andric if (!ModifiedRegUnits.available(DestReg) || 154*06c3fb27SDimitry Andric !UsedRegUnits.available(DestReg) || 155*06c3fb27SDimitry Andric !ModifiedRegUnits.available(SourceReg)) 156*06c3fb27SDimitry Andric return E; 157*06c3fb27SDimitry Andric 158*06c3fb27SDimitry Andric return I; 159*06c3fb27SDimitry Andric } else if (InstOpcode == RISCV::CM_MVSA01 && 160*06c3fb27SDimitry Andric isCandidateToMergeMVSA01(*SecondPair)) { 161*06c3fb27SDimitry Andric if ((RegPair.Source->getReg() == SourceReg) || 162*06c3fb27SDimitry Andric (RegPair.Destination->getReg() == DestReg)) 163*06c3fb27SDimitry Andric return E; 164*06c3fb27SDimitry Andric 165*06c3fb27SDimitry Andric if (!ModifiedRegUnits.available(DestReg) || 166*06c3fb27SDimitry Andric !UsedRegUnits.available(DestReg) || 167*06c3fb27SDimitry Andric !ModifiedRegUnits.available(SourceReg)) 168*06c3fb27SDimitry Andric return E; 169*06c3fb27SDimitry Andric 170*06c3fb27SDimitry Andric return I; 171*06c3fb27SDimitry Andric } 172*06c3fb27SDimitry Andric } 173*06c3fb27SDimitry Andric // Update modified / used register units. 174*06c3fb27SDimitry Andric LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI); 175*06c3fb27SDimitry Andric } 176*06c3fb27SDimitry Andric return E; 177*06c3fb27SDimitry Andric } 178*06c3fb27SDimitry Andric 179*06c3fb27SDimitry Andric // Finds instructions, which could be represented as C.MV instructions and 180*06c3fb27SDimitry Andric // merged into CM.MVA01S or CM.MVSA01. 181*06c3fb27SDimitry Andric bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) { 182*06c3fb27SDimitry Andric bool Modified = false; 183*06c3fb27SDimitry Andric 184*06c3fb27SDimitry Andric for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 185*06c3fb27SDimitry Andric MBBI != E;) { 186*06c3fb27SDimitry Andric // Check if the instruction can be compressed to C.MV instruction. If it 187*06c3fb27SDimitry Andric // can, return Dest/Src register pair. 188*06c3fb27SDimitry Andric auto RegPair = TII->isCopyInstrImpl(*MBBI); 189*06c3fb27SDimitry Andric if (RegPair.has_value()) { 190*06c3fb27SDimitry Andric unsigned Opcode = 0; 191*06c3fb27SDimitry Andric 192*06c3fb27SDimitry Andric if (isCandidateToMergeMVA01S(*RegPair)) 193*06c3fb27SDimitry Andric Opcode = RISCV::CM_MVA01S; 194*06c3fb27SDimitry Andric else if (isCandidateToMergeMVSA01(*RegPair)) 195*06c3fb27SDimitry Andric Opcode = RISCV::CM_MVSA01; 196*06c3fb27SDimitry Andric else { 197*06c3fb27SDimitry Andric ++MBBI; 198*06c3fb27SDimitry Andric continue; 199*06c3fb27SDimitry Andric } 200*06c3fb27SDimitry Andric 201*06c3fb27SDimitry Andric MachineBasicBlock::iterator Paired = 202*06c3fb27SDimitry Andric findMatchingInst(MBBI, Opcode, RegPair.value()); 203*06c3fb27SDimitry Andric // If matching instruction can be found merge them. 204*06c3fb27SDimitry Andric if (Paired != E) { 205*06c3fb27SDimitry Andric MBBI = mergePairedInsns(MBBI, Paired, Opcode); 206*06c3fb27SDimitry Andric Modified = true; 207*06c3fb27SDimitry Andric continue; 208*06c3fb27SDimitry Andric } 209*06c3fb27SDimitry Andric } 210*06c3fb27SDimitry Andric ++MBBI; 211*06c3fb27SDimitry Andric } 212*06c3fb27SDimitry Andric return Modified; 213*06c3fb27SDimitry Andric } 214*06c3fb27SDimitry Andric 215*06c3fb27SDimitry Andric bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) { 216*06c3fb27SDimitry Andric if (skipFunction(Fn.getFunction())) 217*06c3fb27SDimitry Andric return false; 218*06c3fb27SDimitry Andric 219*06c3fb27SDimitry Andric const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>(); 220*06c3fb27SDimitry Andric if (!Subtarget->hasStdExtZcmp()) 221*06c3fb27SDimitry Andric return false; 222*06c3fb27SDimitry Andric 223*06c3fb27SDimitry Andric TII = Subtarget->getInstrInfo(); 224*06c3fb27SDimitry Andric TRI = Subtarget->getRegisterInfo(); 225*06c3fb27SDimitry Andric // Resize the modified and used register unit trackers. We do this once 226*06c3fb27SDimitry Andric // per function and then clear the register units each time we optimize a 227*06c3fb27SDimitry Andric // move. 228*06c3fb27SDimitry Andric ModifiedRegUnits.init(*TRI); 229*06c3fb27SDimitry Andric UsedRegUnits.init(*TRI); 230*06c3fb27SDimitry Andric bool Modified = false; 231*06c3fb27SDimitry Andric for (auto &MBB : Fn) 232*06c3fb27SDimitry Andric Modified |= mergeMoveSARegPair(MBB); 233*06c3fb27SDimitry Andric return Modified; 234*06c3fb27SDimitry Andric } 235*06c3fb27SDimitry Andric 236*06c3fb27SDimitry Andric /// createRISCVMoveMergePass - returns an instance of the 237*06c3fb27SDimitry Andric /// move merge pass. 238*06c3fb27SDimitry Andric FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); } 239