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