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