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