Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / Target / RISCV / RISCVMoveMerger.cpp
blob934a2a0f8e1afc9380264127ecb6b7c528e049b6
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.
12 //===----------------------------------------------------------------------===//
14 #include "RISCVInstrInfo.h"
15 #include "RISCVMachineFunctionInfo.h"
17 using namespace llvm;
19 #define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass"
21 namespace {
22 struct RISCVMoveMerge : public MachineFunctionPass {
23 static char ID;
25 RISCVMoveMerge() : MachineFunctionPass(ID) {
26 initializeRISCVMoveMergePass(*PassRegistry::getPassRegistry());
29 const RISCVInstrInfo *TII;
30 const TargetRegisterInfo *TRI;
32 // Track which register units have been modified and used.
33 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
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);
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;
51 StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
54 char RISCVMoveMerge::ID = 0;
56 } // end of anonymous namespace
58 INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
59 false, false)
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;
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;
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();
96 if (NextI == Paired)
97 NextI = next_nodbg(NextI, E);
98 DebugLoc DL = I->getDebugLoc();
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
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;
117 BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
119 I->eraseFromParent();
120 Paired->eraseFromParent();
121 return NextI;
124 MachineBasicBlock::iterator
125 RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
126 unsigned InstOpcode,
127 const DestSourcePair &RegPair) {
128 MachineBasicBlock::iterator E = MBBI->getParent()->end();
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();
135 for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E;
136 I = next_nodbg(I, E)) {
138 MachineInstr &MI = *I;
140 if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
141 Register SourceReg = SecondPair->Source->getReg();
142 Register DestReg = SecondPair->Destination->getReg();
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;
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;
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;
165 if (!ModifiedRegUnits.available(DestReg) ||
166 !UsedRegUnits.available(DestReg) ||
167 !ModifiedRegUnits.available(SourceReg))
168 return E;
170 return I;
173 // Update modified / used register units.
174 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
176 return E;
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;
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;
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;
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;
210 ++MBBI;
212 return Modified;
215 bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
216 if (skipFunction(Fn.getFunction()))
217 return false;
219 const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
220 if (!Subtarget->hasStdExtZcmp())
221 return false;
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;
236 /// createRISCVMoveMergePass - returns an instance of the
237 /// move merge pass.
238 FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }