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