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