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