xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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   // The order of S-reg depends on which instruction holds A0, instead of
141   // the order of register pair.
142   // e,g.
143   //   mv a1, s1
144   //   mv a0, s2    =>  cm.mva01s s2,s1
145   //
146   //   mv a0, s2
147   //   mv a1, s1    =>  cm.mva01s s2,s1
148   bool StartWithX10 = ARegInFirstPair == RISCV::X10;
149   if (isMoveFromAToS(Opcode)) {
150     Sreg1 = StartWithX10 ? FirstPair.Source : PairedRegs.Source;
151     Sreg2 = StartWithX10 ? PairedRegs.Source : FirstPair.Source;
152   } else {
153     Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination;
154     Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination;
155   }
156 
157   BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
158 
159   I->eraseFromParent();
160   Paired->eraseFromParent();
161   return NextI;
162 }
163 
164 MachineBasicBlock::iterator
165 RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
166                                  unsigned InstOpcode,
167                                  const DestSourcePair &RegPair) {
168   MachineBasicBlock::iterator E = MBBI->getParent()->end();
169 
170   // Track which register units have been modified and used between the first
171   // insn and the second insn.
172   ModifiedRegUnits.clear();
173   UsedRegUnits.clear();
174 
175   for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E;
176        I = next_nodbg(I, E)) {
177 
178     MachineInstr &MI = *I;
179 
180     if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
181       Register SourceReg = SecondPair->Source->getReg();
182       Register DestReg = SecondPair->Destination->getReg();
183 
184       if (isMoveFromAToS(InstOpcode) && isCandidateToMergeMVA01S(*SecondPair)) {
185         // If register pair is valid and destination registers are different.
186         if ((RegPair.Destination->getReg() == DestReg))
187           return E;
188 
189         //  If paired destination register was modified or used, the source reg
190         //  was modified, there is no possibility of finding matching
191         //  instruction so exit early.
192         if (!ModifiedRegUnits.available(DestReg) ||
193             !UsedRegUnits.available(DestReg) ||
194             !ModifiedRegUnits.available(SourceReg))
195           return E;
196 
197         return I;
198       } else if (isMoveFromSToA(InstOpcode) &&
199                  isCandidateToMergeMVSA01(*SecondPair)) {
200         if ((RegPair.Source->getReg() == SourceReg) ||
201             (RegPair.Destination->getReg() == DestReg))
202           return E;
203 
204         if (!ModifiedRegUnits.available(DestReg) ||
205             !UsedRegUnits.available(DestReg) ||
206             !ModifiedRegUnits.available(SourceReg))
207           return E;
208 
209         return I;
210       }
211     }
212     // Update modified / used register units.
213     LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
214   }
215   return E;
216 }
217 
218 // Finds instructions, which could be represented as C.MV instructions and
219 // merged into CM.MVA01S or CM.MVSA01.
220 bool RISCVMoveMerge::mergeMoveSARegPair(const RISCVSubtarget &STI,
221                                         MachineBasicBlock &MBB) {
222   bool Modified = false;
223 
224   for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
225        MBBI != E;) {
226     // Check if the instruction can be compressed to C.MV instruction. If it
227     // can, return Dest/Src register pair.
228     auto RegPair = TII->isCopyInstrImpl(*MBBI);
229     if (RegPair.has_value()) {
230       unsigned Opcode = 0;
231 
232       if (isCandidateToMergeMVA01S(*RegPair))
233         Opcode = getMoveFromAToSOpcode(STI);
234       else if (isCandidateToMergeMVSA01(*RegPair))
235         Opcode = getMoveFromSToAOpcode(STI);
236       else {
237         ++MBBI;
238         continue;
239       }
240 
241       MachineBasicBlock::iterator Paired =
242           findMatchingInst(MBBI, Opcode, RegPair.value());
243       // If matching instruction can be found merge them.
244       if (Paired != E) {
245         MBBI = mergePairedInsns(MBBI, Paired, Opcode);
246         Modified = true;
247         continue;
248       }
249     }
250     ++MBBI;
251   }
252   return Modified;
253 }
254 
255 bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
256   if (skipFunction(Fn.getFunction()))
257     return false;
258 
259   const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
260   if (!(Subtarget->hasStdExtZcmp() || Subtarget->hasVendorXqccmp()))
261     return false;
262 
263   TII = Subtarget->getInstrInfo();
264   TRI = Subtarget->getRegisterInfo();
265   // Resize the modified and used register unit trackers.  We do this once
266   // per function and then clear the register units each time we optimize a
267   // move.
268   ModifiedRegUnits.init(*TRI);
269   UsedRegUnits.init(*TRI);
270   bool Modified = false;
271   for (auto &MBB : Fn)
272     Modified |= mergeMoveSARegPair(*Subtarget, MBB);
273   return Modified;
274 }
275 
276 /// createRISCVMoveMergePass - returns an instance of the
277 /// move merge pass.
278 FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }
279