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(Reg: 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(Reg: 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(It: I, End: E); |
88 | DestSourcePair FirstPair = TII->isCopyInstrImpl(MI: *I).value(); |
89 | DestSourcePair PairedRegs = TII->isCopyInstrImpl(MI: *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(It: NextI, End: 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(BB&: *I->getParent(), I, MIMD: DL, MCID: TII->get(Opcode)).add(MO: *Sreg1).add(MO: *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(It: MBBI, End: E); I != E; |
134 | I = next_nodbg(It: I, End: 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(RegPair: *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(Reg: DestReg) || |
152 | !UsedRegUnits.available(Reg: DestReg) || |
153 | !ModifiedRegUnits.available(Reg: SourceReg)) |
154 | return E; |
155 | |
156 | return I; |
157 | } else if (InstOpcode == RISCV::CM_MVSA01 && |
158 | isCandidateToMergeMVSA01(RegPair: *SecondPair)) { |
159 | if ((RegPair.Source->getReg() == SourceReg) || |
160 | (RegPair.Destination->getReg() == DestReg)) |
161 | return E; |
162 | |
163 | if (!ModifiedRegUnits.available(Reg: DestReg) || |
164 | !UsedRegUnits.available(Reg: DestReg) || |
165 | !ModifiedRegUnits.available(Reg: 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(MI: *MBBI); |
187 | if (RegPair.has_value()) { |
188 | unsigned Opcode = 0; |
189 | |
190 | if (isCandidateToMergeMVA01S(RegPair: *RegPair)) |
191 | Opcode = RISCV::CM_MVA01S; |
192 | else if (isCandidateToMergeMVSA01(RegPair: *RegPair)) |
193 | Opcode = RISCV::CM_MVSA01; |
194 | else { |
195 | ++MBBI; |
196 | continue; |
197 | } |
198 | |
199 | MachineBasicBlock::iterator Paired = |
200 | findMatchingInst(MBBI, InstOpcode: Opcode, RegPair: RegPair.value()); |
201 | // If matching instruction can be found merge them. |
202 | if (Paired != E) { |
203 | MBBI = mergePairedInsns(I: 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(F: 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: *TRI); |
227 | UsedRegUnits.init(TRI: *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 | |