1 //===-- RISCVMoveMerger.cpp - RISC-V 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 // This pass also supports Xqccmp, which has identical instructions. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "RISCVInstrInfo.h" 17 #include "RISCVSubtarget.h" 18 19 using namespace llvm; 20 21 #define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass" 22 23 namespace { 24 struct RISCVMoveMerge : public MachineFunctionPass { 25 static char ID; 26 27 RISCVMoveMerge() : MachineFunctionPass(ID) {} 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(const RISCVSubtarget &STI, 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 static bool isMoveFromAToS(unsigned Opcode) { 62 switch (Opcode) { 63 case RISCV::CM_MVA01S: 64 case RISCV::QC_CM_MVA01S: 65 return true; 66 default: 67 return false; 68 } 69 } 70 71 static unsigned getMoveFromAToSOpcode(const RISCVSubtarget &STI) { 72 if (STI.hasStdExtZcmp()) 73 return RISCV::CM_MVA01S; 74 75 if (STI.hasVendorXqccmp()) 76 return RISCV::QC_CM_MVA01S; 77 78 llvm_unreachable("Unhandled subtarget with paired A to S move."); 79 } 80 81 static bool isMoveFromSToA(unsigned Opcode) { 82 switch (Opcode) { 83 case RISCV::CM_MVSA01: 84 case RISCV::QC_CM_MVSA01: 85 return true; 86 default: 87 return false; 88 } 89 } 90 91 static unsigned getMoveFromSToAOpcode(const RISCVSubtarget &STI) { 92 if (STI.hasStdExtZcmp()) 93 return RISCV::CM_MVSA01; 94 95 if (STI.hasVendorXqccmp()) 96 return RISCV::QC_CM_MVSA01; 97 98 llvm_unreachable("Unhandled subtarget with paired S to A move"); 99 } 100 101 // Check if registers meet CM.MVA01S constraints. 102 bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) { 103 Register Destination = RegPair.Destination->getReg(); 104 Register Source = RegPair.Source->getReg(); 105 // If destination is not a0 or a1. 106 if ((Destination == RISCV::X10 || Destination == RISCV::X11) && 107 RISCV::SR07RegClass.contains(Source)) 108 return true; 109 return false; 110 } 111 112 // Check if registers meet CM.MVSA01 constraints. 113 bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) { 114 Register Destination = RegPair.Destination->getReg(); 115 Register Source = RegPair.Source->getReg(); 116 // If Source is s0 - s7. 117 if ((Source == RISCV::X10 || Source == RISCV::X11) && 118 RISCV::SR07RegClass.contains(Destination)) 119 return true; 120 return false; 121 } 122 123 MachineBasicBlock::iterator 124 RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I, 125 MachineBasicBlock::iterator Paired, 126 unsigned Opcode) { 127 const MachineOperand *Sreg1, *Sreg2; 128 MachineBasicBlock::iterator E = I->getParent()->end(); 129 MachineBasicBlock::iterator NextI = next_nodbg(I, E); 130 DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value(); 131 DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value(); 132 Register ARegInFirstPair = isMoveFromAToS(Opcode) 133 ? FirstPair.Destination->getReg() 134 : FirstPair.Source->getReg(); 135 136 if (NextI == Paired) 137 NextI = next_nodbg(NextI, E); 138 DebugLoc DL = I->getDebugLoc(); 139 140 // Make a copy so we can update the kill flag in the MoveFromAToS case. The 141 // copied operand needs to be scoped outside the if since we make a pointer 142 // to it. 143 MachineOperand PairedSource = *PairedRegs.Source; 144 145 // The order of S-reg depends on which instruction holds A0, instead of 146 // the order of register pair. 147 // e,g. 148 // mv a1, s1 149 // mv a0, s2 => cm.mva01s s2,s1 150 // 151 // mv a0, s2 152 // mv a1, s1 => cm.mva01s s2,s1 153 bool StartWithX10 = ARegInFirstPair == RISCV::X10; 154 if (isMoveFromAToS(Opcode)) { 155 // We are moving one of the copies earlier so its kill flag may become 156 // invalid. Clear the copied kill flag if there are any reads of the 157 // register between the new location and the old location. 158 for (auto It = std::next(I); It != Paired && PairedSource.isKill(); ++It) 159 if (It->readsRegister(PairedSource.getReg(), TRI)) 160 PairedSource.setIsKill(false); 161 162 Sreg1 = StartWithX10 ? FirstPair.Source : &PairedSource; 163 Sreg2 = StartWithX10 ? &PairedSource : FirstPair.Source; 164 } else { 165 Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination; 166 Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination; 167 } 168 169 BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2); 170 171 I->eraseFromParent(); 172 Paired->eraseFromParent(); 173 return NextI; 174 } 175 176 MachineBasicBlock::iterator 177 RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI, 178 unsigned InstOpcode, 179 const DestSourcePair &RegPair) { 180 MachineBasicBlock::iterator E = MBBI->getParent()->end(); 181 182 // Track which register units have been modified and used between the first 183 // insn and the second insn. 184 ModifiedRegUnits.clear(); 185 UsedRegUnits.clear(); 186 187 for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E; 188 I = next_nodbg(I, E)) { 189 190 MachineInstr &MI = *I; 191 192 if (auto SecondPair = TII->isCopyInstrImpl(MI)) { 193 Register SourceReg = SecondPair->Source->getReg(); 194 Register DestReg = SecondPair->Destination->getReg(); 195 196 if (isMoveFromAToS(InstOpcode) && isCandidateToMergeMVA01S(*SecondPair)) { 197 // If register pair is valid and destination registers are different. 198 if ((RegPair.Destination->getReg() == DestReg)) 199 return E; 200 201 // If paired destination register was modified or used, the source reg 202 // was modified, there is no possibility of finding matching 203 // instruction so exit early. 204 if (!ModifiedRegUnits.available(DestReg) || 205 !UsedRegUnits.available(DestReg) || 206 !ModifiedRegUnits.available(SourceReg)) 207 return E; 208 209 return I; 210 } else if (isMoveFromSToA(InstOpcode) && 211 isCandidateToMergeMVSA01(*SecondPair)) { 212 if ((RegPair.Source->getReg() == SourceReg) || 213 (RegPair.Destination->getReg() == DestReg)) 214 return E; 215 216 if (!ModifiedRegUnits.available(DestReg) || 217 !UsedRegUnits.available(DestReg) || 218 !ModifiedRegUnits.available(SourceReg)) 219 return E; 220 221 return I; 222 } 223 } 224 // Update modified / used register units. 225 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI); 226 } 227 return E; 228 } 229 230 // Finds instructions, which could be represented as C.MV instructions and 231 // merged into CM.MVA01S or CM.MVSA01. 232 bool RISCVMoveMerge::mergeMoveSARegPair(const RISCVSubtarget &STI, 233 MachineBasicBlock &MBB) { 234 bool Modified = false; 235 236 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 237 MBBI != E;) { 238 // Check if the instruction can be compressed to C.MV instruction. If it 239 // can, return Dest/Src register pair. 240 auto RegPair = TII->isCopyInstrImpl(*MBBI); 241 if (RegPair.has_value()) { 242 unsigned Opcode = 0; 243 244 if (isCandidateToMergeMVA01S(*RegPair)) 245 Opcode = getMoveFromAToSOpcode(STI); 246 else if (isCandidateToMergeMVSA01(*RegPair)) 247 Opcode = getMoveFromSToAOpcode(STI); 248 else { 249 ++MBBI; 250 continue; 251 } 252 253 MachineBasicBlock::iterator Paired = 254 findMatchingInst(MBBI, Opcode, RegPair.value()); 255 // If matching instruction can be found merge them. 256 if (Paired != E) { 257 MBBI = mergePairedInsns(MBBI, Paired, Opcode); 258 Modified = true; 259 continue; 260 } 261 } 262 ++MBBI; 263 } 264 return Modified; 265 } 266 267 bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) { 268 if (skipFunction(Fn.getFunction())) 269 return false; 270 271 const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>(); 272 if (!(Subtarget->hasStdExtZcmp() || Subtarget->hasVendorXqccmp())) 273 return false; 274 275 TII = Subtarget->getInstrInfo(); 276 TRI = Subtarget->getRegisterInfo(); 277 // Resize the modified and used register unit trackers. We do this once 278 // per function and then clear the register units each time we optimize a 279 // move. 280 ModifiedRegUnits.init(*TRI); 281 UsedRegUnits.init(*TRI); 282 bool Modified = false; 283 for (auto &MBB : Fn) 284 Modified |= mergeMoveSARegPair(*Subtarget, MBB); 285 return Modified; 286 } 287 288 /// createRISCVMoveMergePass - returns an instance of the 289 /// move merge pass. 290 FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); } 291