xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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