1 | //===-- RISCVExpandPseudoInsts.cpp - Expand pseudo instructions -----------===// |
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 expands pseudo instructions into target |
10 | // instructions. This pass should be run after register allocation but before |
11 | // the post-regalloc scheduling pass. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "RISCV.h" |
16 | #include "RISCVInstrInfo.h" |
17 | #include "RISCVTargetMachine.h" |
18 | |
19 | #include "llvm/CodeGen/LivePhysRegs.h" |
20 | #include "llvm/CodeGen/MachineFunctionPass.h" |
21 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
22 | #include "llvm/MC/MCContext.h" |
23 | |
24 | using namespace llvm; |
25 | |
26 | #define RISCV_EXPAND_PSEUDO_NAME "RISC-V pseudo instruction expansion pass" |
27 | #define RISCV_PRERA_EXPAND_PSEUDO_NAME "RISC-V Pre-RA pseudo instruction expansion pass" |
28 | |
29 | namespace { |
30 | |
31 | class RISCVExpandPseudo : public MachineFunctionPass { |
32 | public: |
33 | const RISCVSubtarget *STI; |
34 | const RISCVInstrInfo *TII; |
35 | static char ID; |
36 | |
37 | RISCVExpandPseudo() : MachineFunctionPass(ID) {} |
38 | |
39 | bool runOnMachineFunction(MachineFunction &MF) override; |
40 | |
41 | StringRef getPassName() const override { return RISCV_EXPAND_PSEUDO_NAME; } |
42 | |
43 | private: |
44 | bool expandMBB(MachineBasicBlock &MBB); |
45 | bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
46 | MachineBasicBlock::iterator &NextMBBI); |
47 | bool expandCCOp(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
48 | MachineBasicBlock::iterator &NextMBBI); |
49 | bool expandVMSET_VMCLR(MachineBasicBlock &MBB, |
50 | MachineBasicBlock::iterator MBBI, unsigned Opcode); |
51 | bool expandMV_FPR16INX(MachineBasicBlock &MBB, |
52 | MachineBasicBlock::iterator MBBI); |
53 | bool expandMV_FPR32INX(MachineBasicBlock &MBB, |
54 | MachineBasicBlock::iterator MBBI); |
55 | bool expandRV32ZdinxStore(MachineBasicBlock &MBB, |
56 | MachineBasicBlock::iterator MBBI); |
57 | bool expandRV32ZdinxLoad(MachineBasicBlock &MBB, |
58 | MachineBasicBlock::iterator MBBI); |
59 | bool expandPseudoReadVLENBViaVSETVLIX0(MachineBasicBlock &MBB, |
60 | MachineBasicBlock::iterator MBBI); |
61 | #ifndef NDEBUG |
62 | unsigned getInstSizeInBytes(const MachineFunction &MF) const { |
63 | unsigned Size = 0; |
64 | for (auto &MBB : MF) |
65 | for (auto &MI : MBB) |
66 | Size += TII->getInstSizeInBytes(MI); |
67 | return Size; |
68 | } |
69 | #endif |
70 | }; |
71 | |
72 | char RISCVExpandPseudo::ID = 0; |
73 | |
74 | bool RISCVExpandPseudo::runOnMachineFunction(MachineFunction &MF) { |
75 | STI = &MF.getSubtarget<RISCVSubtarget>(); |
76 | TII = STI->getInstrInfo(); |
77 | |
78 | #ifndef NDEBUG |
79 | const unsigned OldSize = getInstSizeInBytes(MF); |
80 | #endif |
81 | |
82 | bool Modified = false; |
83 | for (auto &MBB : MF) |
84 | Modified |= expandMBB(MBB); |
85 | |
86 | #ifndef NDEBUG |
87 | const unsigned NewSize = getInstSizeInBytes(MF); |
88 | assert(OldSize >= NewSize); |
89 | #endif |
90 | return Modified; |
91 | } |
92 | |
93 | bool RISCVExpandPseudo::expandMBB(MachineBasicBlock &MBB) { |
94 | bool Modified = false; |
95 | |
96 | MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); |
97 | while (MBBI != E) { |
98 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
99 | Modified |= expandMI(MBB, MBBI, NextMBBI&: NMBBI); |
100 | MBBI = NMBBI; |
101 | } |
102 | |
103 | return Modified; |
104 | } |
105 | |
106 | bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB, |
107 | MachineBasicBlock::iterator MBBI, |
108 | MachineBasicBlock::iterator &NextMBBI) { |
109 | // RISCVInstrInfo::getInstSizeInBytes expects that the total size of the |
110 | // expanded instructions for each pseudo is correct in the Size field of the |
111 | // tablegen definition for the pseudo. |
112 | switch (MBBI->getOpcode()) { |
113 | case RISCV::PseudoMV_FPR16INX: |
114 | return expandMV_FPR16INX(MBB, MBBI); |
115 | case RISCV::PseudoMV_FPR32INX: |
116 | return expandMV_FPR32INX(MBB, MBBI); |
117 | case RISCV::PseudoRV32ZdinxSD: |
118 | return expandRV32ZdinxStore(MBB, MBBI); |
119 | case RISCV::PseudoRV32ZdinxLD: |
120 | return expandRV32ZdinxLoad(MBB, MBBI); |
121 | case RISCV::PseudoCCMOVGPRNoX0: |
122 | case RISCV::PseudoCCMOVGPR: |
123 | case RISCV::PseudoCCADD: |
124 | case RISCV::PseudoCCSUB: |
125 | case RISCV::PseudoCCAND: |
126 | case RISCV::PseudoCCOR: |
127 | case RISCV::PseudoCCXOR: |
128 | case RISCV::PseudoCCADDW: |
129 | case RISCV::PseudoCCSUBW: |
130 | case RISCV::PseudoCCSLL: |
131 | case RISCV::PseudoCCSRL: |
132 | case RISCV::PseudoCCSRA: |
133 | case RISCV::PseudoCCADDI: |
134 | case RISCV::PseudoCCSLLI: |
135 | case RISCV::PseudoCCSRLI: |
136 | case RISCV::PseudoCCSRAI: |
137 | case RISCV::PseudoCCANDI: |
138 | case RISCV::PseudoCCORI: |
139 | case RISCV::PseudoCCXORI: |
140 | case RISCV::PseudoCCSLLW: |
141 | case RISCV::PseudoCCSRLW: |
142 | case RISCV::PseudoCCSRAW: |
143 | case RISCV::PseudoCCADDIW: |
144 | case RISCV::PseudoCCSLLIW: |
145 | case RISCV::PseudoCCSRLIW: |
146 | case RISCV::PseudoCCSRAIW: |
147 | case RISCV::PseudoCCANDN: |
148 | case RISCV::PseudoCCORN: |
149 | case RISCV::PseudoCCXNOR: |
150 | case RISCV::PseudoCCNDS_BFOS: |
151 | case RISCV::PseudoCCNDS_BFOZ: |
152 | return expandCCOp(MBB, MBBI, NextMBBI); |
153 | case RISCV::PseudoVMCLR_M_B1: |
154 | case RISCV::PseudoVMCLR_M_B2: |
155 | case RISCV::PseudoVMCLR_M_B4: |
156 | case RISCV::PseudoVMCLR_M_B8: |
157 | case RISCV::PseudoVMCLR_M_B16: |
158 | case RISCV::PseudoVMCLR_M_B32: |
159 | case RISCV::PseudoVMCLR_M_B64: |
160 | // vmclr.m vd => vmxor.mm vd, vd, vd |
161 | return expandVMSET_VMCLR(MBB, MBBI, Opcode: RISCV::VMXOR_MM); |
162 | case RISCV::PseudoVMSET_M_B1: |
163 | case RISCV::PseudoVMSET_M_B2: |
164 | case RISCV::PseudoVMSET_M_B4: |
165 | case RISCV::PseudoVMSET_M_B8: |
166 | case RISCV::PseudoVMSET_M_B16: |
167 | case RISCV::PseudoVMSET_M_B32: |
168 | case RISCV::PseudoVMSET_M_B64: |
169 | // vmset.m vd => vmxnor.mm vd, vd, vd |
170 | return expandVMSET_VMCLR(MBB, MBBI, Opcode: RISCV::VMXNOR_MM); |
171 | case RISCV::PseudoReadVLENBViaVSETVLIX0: |
172 | return expandPseudoReadVLENBViaVSETVLIX0(MBB, MBBI); |
173 | } |
174 | |
175 | return false; |
176 | } |
177 | |
178 | bool RISCVExpandPseudo::expandCCOp(MachineBasicBlock &MBB, |
179 | MachineBasicBlock::iterator MBBI, |
180 | MachineBasicBlock::iterator &NextMBBI) { |
181 | |
182 | MachineFunction *MF = MBB.getParent(); |
183 | MachineInstr &MI = *MBBI; |
184 | DebugLoc DL = MI.getDebugLoc(); |
185 | |
186 | MachineBasicBlock *TrueBB = MF->CreateMachineBasicBlock(BB: MBB.getBasicBlock()); |
187 | MachineBasicBlock *MergeBB = MF->CreateMachineBasicBlock(BB: MBB.getBasicBlock()); |
188 | |
189 | MF->insert(MBBI: ++MBB.getIterator(), MBB: TrueBB); |
190 | MF->insert(MBBI: ++TrueBB->getIterator(), MBB: MergeBB); |
191 | |
192 | // We want to copy the "true" value when the condition is true which means |
193 | // we need to invert the branch condition to jump over TrueBB when the |
194 | // condition is false. |
195 | auto CC = static_cast<RISCVCC::CondCode>(MI.getOperand(i: 3).getImm()); |
196 | CC = RISCVCC::getOppositeBranchCondition(CC); |
197 | |
198 | // Insert branch instruction. |
199 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCVCC::getBrCond(CC))) |
200 | .addReg(RegNo: MI.getOperand(i: 1).getReg()) |
201 | .addReg(RegNo: MI.getOperand(i: 2).getReg()) |
202 | .addMBB(MBB: MergeBB); |
203 | |
204 | Register DestReg = MI.getOperand(i: 0).getReg(); |
205 | assert(MI.getOperand(4).getReg() == DestReg); |
206 | |
207 | if (MI.getOpcode() == RISCV::PseudoCCMOVGPR || |
208 | MI.getOpcode() == RISCV::PseudoCCMOVGPRNoX0) { |
209 | // Add MV. |
210 | BuildMI(BB: TrueBB, MIMD: DL, MCID: TII->get(Opcode: RISCV::ADDI), DestReg) |
211 | .add(MO: MI.getOperand(i: 5)) |
212 | .addImm(Val: 0); |
213 | } else { |
214 | unsigned NewOpc; |
215 | switch (MI.getOpcode()) { |
216 | default: |
217 | llvm_unreachable("Unexpected opcode!" ); |
218 | case RISCV::PseudoCCADD: NewOpc = RISCV::ADD; break; |
219 | case RISCV::PseudoCCSUB: NewOpc = RISCV::SUB; break; |
220 | case RISCV::PseudoCCSLL: NewOpc = RISCV::SLL; break; |
221 | case RISCV::PseudoCCSRL: NewOpc = RISCV::SRL; break; |
222 | case RISCV::PseudoCCSRA: NewOpc = RISCV::SRA; break; |
223 | case RISCV::PseudoCCAND: NewOpc = RISCV::AND; break; |
224 | case RISCV::PseudoCCOR: NewOpc = RISCV::OR; break; |
225 | case RISCV::PseudoCCXOR: NewOpc = RISCV::XOR; break; |
226 | case RISCV::PseudoCCADDI: NewOpc = RISCV::ADDI; break; |
227 | case RISCV::PseudoCCSLLI: NewOpc = RISCV::SLLI; break; |
228 | case RISCV::PseudoCCSRLI: NewOpc = RISCV::SRLI; break; |
229 | case RISCV::PseudoCCSRAI: NewOpc = RISCV::SRAI; break; |
230 | case RISCV::PseudoCCANDI: NewOpc = RISCV::ANDI; break; |
231 | case RISCV::PseudoCCORI: NewOpc = RISCV::ORI; break; |
232 | case RISCV::PseudoCCXORI: NewOpc = RISCV::XORI; break; |
233 | case RISCV::PseudoCCADDW: NewOpc = RISCV::ADDW; break; |
234 | case RISCV::PseudoCCSUBW: NewOpc = RISCV::SUBW; break; |
235 | case RISCV::PseudoCCSLLW: NewOpc = RISCV::SLLW; break; |
236 | case RISCV::PseudoCCSRLW: NewOpc = RISCV::SRLW; break; |
237 | case RISCV::PseudoCCSRAW: NewOpc = RISCV::SRAW; break; |
238 | case RISCV::PseudoCCADDIW: NewOpc = RISCV::ADDIW; break; |
239 | case RISCV::PseudoCCSLLIW: NewOpc = RISCV::SLLIW; break; |
240 | case RISCV::PseudoCCSRLIW: NewOpc = RISCV::SRLIW; break; |
241 | case RISCV::PseudoCCSRAIW: NewOpc = RISCV::SRAIW; break; |
242 | case RISCV::PseudoCCANDN: NewOpc = RISCV::ANDN; break; |
243 | case RISCV::PseudoCCORN: NewOpc = RISCV::ORN; break; |
244 | case RISCV::PseudoCCXNOR: NewOpc = RISCV::XNOR; break; |
245 | case RISCV::PseudoCCNDS_BFOS: NewOpc = RISCV::NDS_BFOS; break; |
246 | case RISCV::PseudoCCNDS_BFOZ: NewOpc = RISCV::NDS_BFOZ; break; |
247 | } |
248 | |
249 | if (NewOpc == RISCV::NDS_BFOZ || NewOpc == RISCV::NDS_BFOS) { |
250 | BuildMI(BB: TrueBB, MIMD: DL, MCID: TII->get(Opcode: NewOpc), DestReg) |
251 | .add(MO: MI.getOperand(i: 5)) |
252 | .add(MO: MI.getOperand(i: 6)) |
253 | .add(MO: MI.getOperand(i: 7)); |
254 | } else { |
255 | BuildMI(BB: TrueBB, MIMD: DL, MCID: TII->get(Opcode: NewOpc), DestReg) |
256 | .add(MO: MI.getOperand(i: 5)) |
257 | .add(MO: MI.getOperand(i: 6)); |
258 | } |
259 | } |
260 | |
261 | TrueBB->addSuccessor(Succ: MergeBB); |
262 | |
263 | MergeBB->splice(Where: MergeBB->end(), Other: &MBB, From: MI, To: MBB.end()); |
264 | MergeBB->transferSuccessors(FromMBB: &MBB); |
265 | |
266 | MBB.addSuccessor(Succ: TrueBB); |
267 | MBB.addSuccessor(Succ: MergeBB); |
268 | |
269 | NextMBBI = MBB.end(); |
270 | MI.eraseFromParent(); |
271 | |
272 | // Make sure live-ins are correctly attached to this new basic block. |
273 | LivePhysRegs LiveRegs; |
274 | computeAndAddLiveIns(LiveRegs, MBB&: *TrueBB); |
275 | computeAndAddLiveIns(LiveRegs, MBB&: *MergeBB); |
276 | |
277 | return true; |
278 | } |
279 | |
280 | bool RISCVExpandPseudo::expandVMSET_VMCLR(MachineBasicBlock &MBB, |
281 | MachineBasicBlock::iterator MBBI, |
282 | unsigned Opcode) { |
283 | DebugLoc DL = MBBI->getDebugLoc(); |
284 | Register DstReg = MBBI->getOperand(i: 0).getReg(); |
285 | const MCInstrDesc &Desc = TII->get(Opcode); |
286 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: Desc, DestReg: DstReg) |
287 | .addReg(RegNo: DstReg, flags: RegState::Undef) |
288 | .addReg(RegNo: DstReg, flags: RegState::Undef); |
289 | MBBI->eraseFromParent(); // The pseudo instruction is gone now. |
290 | return true; |
291 | } |
292 | |
293 | bool RISCVExpandPseudo::expandMV_FPR16INX(MachineBasicBlock &MBB, |
294 | MachineBasicBlock::iterator MBBI) { |
295 | DebugLoc DL = MBBI->getDebugLoc(); |
296 | const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
297 | Register DstReg = TRI->getMatchingSuperReg( |
298 | Reg: MBBI->getOperand(i: 0).getReg(), SubIdx: RISCV::sub_16, RC: &RISCV::GPRRegClass); |
299 | Register SrcReg = TRI->getMatchingSuperReg( |
300 | Reg: MBBI->getOperand(i: 1).getReg(), SubIdx: RISCV::sub_16, RC: &RISCV::GPRRegClass); |
301 | |
302 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::ADDI), DestReg: DstReg) |
303 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: MBBI->getOperand(i: 1).isKill())) |
304 | .addImm(Val: 0); |
305 | |
306 | MBBI->eraseFromParent(); // The pseudo instruction is gone now. |
307 | return true; |
308 | } |
309 | |
310 | bool RISCVExpandPseudo::expandMV_FPR32INX(MachineBasicBlock &MBB, |
311 | MachineBasicBlock::iterator MBBI) { |
312 | DebugLoc DL = MBBI->getDebugLoc(); |
313 | const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
314 | Register DstReg = TRI->getMatchingSuperReg( |
315 | Reg: MBBI->getOperand(i: 0).getReg(), SubIdx: RISCV::sub_32, RC: &RISCV::GPRRegClass); |
316 | Register SrcReg = TRI->getMatchingSuperReg( |
317 | Reg: MBBI->getOperand(i: 1).getReg(), SubIdx: RISCV::sub_32, RC: &RISCV::GPRRegClass); |
318 | |
319 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::ADDI), DestReg: DstReg) |
320 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: MBBI->getOperand(i: 1).isKill())) |
321 | .addImm(Val: 0); |
322 | |
323 | MBBI->eraseFromParent(); // The pseudo instruction is gone now. |
324 | return true; |
325 | } |
326 | |
327 | // This function expands the PseudoRV32ZdinxSD for storing a double-precision |
328 | // floating-point value into memory by generating an equivalent instruction |
329 | // sequence for RV32. |
330 | bool RISCVExpandPseudo::expandRV32ZdinxStore(MachineBasicBlock &MBB, |
331 | MachineBasicBlock::iterator MBBI) { |
332 | DebugLoc DL = MBBI->getDebugLoc(); |
333 | const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
334 | Register Lo = |
335 | TRI->getSubReg(Reg: MBBI->getOperand(i: 0).getReg(), Idx: RISCV::sub_gpr_even); |
336 | Register Hi = |
337 | TRI->getSubReg(Reg: MBBI->getOperand(i: 0).getReg(), Idx: RISCV::sub_gpr_odd); |
338 | if (Hi == RISCV::DUMMY_REG_PAIR_WITH_X0) |
339 | Hi = RISCV::X0; |
340 | |
341 | auto MIBLo = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::SW)) |
342 | .addReg(RegNo: Lo, flags: getKillRegState(B: MBBI->getOperand(i: 0).isKill())) |
343 | .addReg(RegNo: MBBI->getOperand(i: 1).getReg()) |
344 | .add(MO: MBBI->getOperand(i: 2)); |
345 | |
346 | MachineInstrBuilder MIBHi; |
347 | if (MBBI->getOperand(i: 2).isGlobal() || MBBI->getOperand(i: 2).isCPI()) { |
348 | assert(MBBI->getOperand(2).getOffset() % 8 == 0); |
349 | MBBI->getOperand(i: 2).setOffset(MBBI->getOperand(i: 2).getOffset() + 4); |
350 | MIBHi = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::SW)) |
351 | .addReg(RegNo: Hi, flags: getKillRegState(B: MBBI->getOperand(i: 0).isKill())) |
352 | .add(MO: MBBI->getOperand(i: 1)) |
353 | .add(MO: MBBI->getOperand(i: 2)); |
354 | } else { |
355 | assert(isInt<12>(MBBI->getOperand(2).getImm() + 4)); |
356 | MIBHi = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::SW)) |
357 | .addReg(RegNo: Hi, flags: getKillRegState(B: MBBI->getOperand(i: 0).isKill())) |
358 | .add(MO: MBBI->getOperand(i: 1)) |
359 | .addImm(Val: MBBI->getOperand(i: 2).getImm() + 4); |
360 | } |
361 | |
362 | MachineFunction *MF = MBB.getParent(); |
363 | SmallVector<MachineMemOperand *> NewLoMMOs; |
364 | SmallVector<MachineMemOperand *> NewHiMMOs; |
365 | for (const MachineMemOperand *MMO : MBBI->memoperands()) { |
366 | NewLoMMOs.push_back(Elt: MF->getMachineMemOperand(MMO, Offset: 0, Size: 4)); |
367 | NewHiMMOs.push_back(Elt: MF->getMachineMemOperand(MMO, Offset: 4, Size: 4)); |
368 | } |
369 | MIBLo.setMemRefs(NewLoMMOs); |
370 | MIBHi.setMemRefs(NewHiMMOs); |
371 | |
372 | MBBI->eraseFromParent(); |
373 | return true; |
374 | } |
375 | |
376 | // This function expands PseudoRV32ZdinxLoad for loading a double-precision |
377 | // floating-point value from memory into an equivalent instruction sequence for |
378 | // RV32. |
379 | bool RISCVExpandPseudo::expandRV32ZdinxLoad(MachineBasicBlock &MBB, |
380 | MachineBasicBlock::iterator MBBI) { |
381 | DebugLoc DL = MBBI->getDebugLoc(); |
382 | const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
383 | Register Lo = |
384 | TRI->getSubReg(Reg: MBBI->getOperand(i: 0).getReg(), Idx: RISCV::sub_gpr_even); |
385 | Register Hi = |
386 | TRI->getSubReg(Reg: MBBI->getOperand(i: 0).getReg(), Idx: RISCV::sub_gpr_odd); |
387 | assert(Hi != RISCV::DUMMY_REG_PAIR_WITH_X0 && "Cannot write to X0_Pair" ); |
388 | |
389 | MachineInstrBuilder MIBLo, MIBHi; |
390 | |
391 | // If the register of operand 1 is equal to the Lo register, then swap the |
392 | // order of loading the Lo and Hi statements. |
393 | bool IsOp1EqualToLo = Lo == MBBI->getOperand(i: 1).getReg(); |
394 | // Order: Lo, Hi |
395 | if (!IsOp1EqualToLo) { |
396 | MIBLo = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::LW), DestReg: Lo) |
397 | .addReg(RegNo: MBBI->getOperand(i: 1).getReg()) |
398 | .add(MO: MBBI->getOperand(i: 2)); |
399 | } |
400 | |
401 | if (MBBI->getOperand(i: 2).isGlobal() || MBBI->getOperand(i: 2).isCPI()) { |
402 | auto Offset = MBBI->getOperand(i: 2).getOffset(); |
403 | assert(Offset % 8 == 0); |
404 | MBBI->getOperand(i: 2).setOffset(Offset + 4); |
405 | MIBHi = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::LW), DestReg: Hi) |
406 | .addReg(RegNo: MBBI->getOperand(i: 1).getReg()) |
407 | .add(MO: MBBI->getOperand(i: 2)); |
408 | MBBI->getOperand(i: 2).setOffset(Offset); |
409 | } else { |
410 | assert(isInt<12>(MBBI->getOperand(2).getImm() + 4)); |
411 | MIBHi = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::LW), DestReg: Hi) |
412 | .addReg(RegNo: MBBI->getOperand(i: 1).getReg()) |
413 | .addImm(Val: MBBI->getOperand(i: 2).getImm() + 4); |
414 | } |
415 | |
416 | // Order: Hi, Lo |
417 | if (IsOp1EqualToLo) { |
418 | MIBLo = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::LW), DestReg: Lo) |
419 | .addReg(RegNo: MBBI->getOperand(i: 1).getReg()) |
420 | .add(MO: MBBI->getOperand(i: 2)); |
421 | } |
422 | |
423 | MachineFunction *MF = MBB.getParent(); |
424 | SmallVector<MachineMemOperand *> NewLoMMOs; |
425 | SmallVector<MachineMemOperand *> NewHiMMOs; |
426 | for (const MachineMemOperand *MMO : MBBI->memoperands()) { |
427 | NewLoMMOs.push_back(Elt: MF->getMachineMemOperand(MMO, Offset: 0, Size: 4)); |
428 | NewHiMMOs.push_back(Elt: MF->getMachineMemOperand(MMO, Offset: 4, Size: 4)); |
429 | } |
430 | MIBLo.setMemRefs(NewLoMMOs); |
431 | MIBHi.setMemRefs(NewHiMMOs); |
432 | |
433 | MBBI->eraseFromParent(); |
434 | return true; |
435 | } |
436 | |
437 | bool RISCVExpandPseudo::expandPseudoReadVLENBViaVSETVLIX0( |
438 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) { |
439 | DebugLoc DL = MBBI->getDebugLoc(); |
440 | Register Dst = MBBI->getOperand(i: 0).getReg(); |
441 | unsigned Mul = MBBI->getOperand(i: 1).getImm(); |
442 | RISCVVType::VLMUL VLMUL = RISCVVType::encodeLMUL(LMUL: Mul, /*Fractional=*/false); |
443 | unsigned VTypeImm = RISCVVType::encodeVTYPE( |
444 | VLMUL, /*SEW=*/8, /*TailAgnostic=*/true, /*MaskAgnostic=*/true); |
445 | |
446 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::PseudoVSETVLIX0)) |
447 | .addReg(RegNo: Dst, flags: RegState::Define) |
448 | .addReg(RegNo: RISCV::X0, flags: RegState::Kill) |
449 | .addImm(Val: VTypeImm); |
450 | |
451 | MBBI->eraseFromParent(); |
452 | return true; |
453 | } |
454 | |
455 | class RISCVPreRAExpandPseudo : public MachineFunctionPass { |
456 | public: |
457 | const RISCVSubtarget *STI; |
458 | const RISCVInstrInfo *TII; |
459 | static char ID; |
460 | |
461 | RISCVPreRAExpandPseudo() : MachineFunctionPass(ID) {} |
462 | |
463 | bool runOnMachineFunction(MachineFunction &MF) override; |
464 | |
465 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
466 | AU.setPreservesCFG(); |
467 | MachineFunctionPass::getAnalysisUsage(AU); |
468 | } |
469 | StringRef getPassName() const override { |
470 | return RISCV_PRERA_EXPAND_PSEUDO_NAME; |
471 | } |
472 | |
473 | private: |
474 | bool expandMBB(MachineBasicBlock &MBB); |
475 | bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
476 | MachineBasicBlock::iterator &NextMBBI); |
477 | bool expandAuipcInstPair(MachineBasicBlock &MBB, |
478 | MachineBasicBlock::iterator MBBI, |
479 | MachineBasicBlock::iterator &NextMBBI, |
480 | unsigned FlagsHi, unsigned SecondOpcode); |
481 | bool expandLoadLocalAddress(MachineBasicBlock &MBB, |
482 | MachineBasicBlock::iterator MBBI, |
483 | MachineBasicBlock::iterator &NextMBBI); |
484 | bool expandLoadGlobalAddress(MachineBasicBlock &MBB, |
485 | MachineBasicBlock::iterator MBBI, |
486 | MachineBasicBlock::iterator &NextMBBI); |
487 | bool expandLoadTLSIEAddress(MachineBasicBlock &MBB, |
488 | MachineBasicBlock::iterator MBBI, |
489 | MachineBasicBlock::iterator &NextMBBI); |
490 | bool expandLoadTLSGDAddress(MachineBasicBlock &MBB, |
491 | MachineBasicBlock::iterator MBBI, |
492 | MachineBasicBlock::iterator &NextMBBI); |
493 | bool expandLoadTLSDescAddress(MachineBasicBlock &MBB, |
494 | MachineBasicBlock::iterator MBBI, |
495 | MachineBasicBlock::iterator &NextMBBI); |
496 | |
497 | #ifndef NDEBUG |
498 | unsigned getInstSizeInBytes(const MachineFunction &MF) const { |
499 | unsigned Size = 0; |
500 | for (auto &MBB : MF) |
501 | for (auto &MI : MBB) |
502 | Size += TII->getInstSizeInBytes(MI); |
503 | return Size; |
504 | } |
505 | #endif |
506 | }; |
507 | |
508 | char RISCVPreRAExpandPseudo::ID = 0; |
509 | |
510 | bool RISCVPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) { |
511 | STI = &MF.getSubtarget<RISCVSubtarget>(); |
512 | TII = STI->getInstrInfo(); |
513 | |
514 | #ifndef NDEBUG |
515 | const unsigned OldSize = getInstSizeInBytes(MF); |
516 | #endif |
517 | |
518 | bool Modified = false; |
519 | for (auto &MBB : MF) |
520 | Modified |= expandMBB(MBB); |
521 | |
522 | #ifndef NDEBUG |
523 | const unsigned NewSize = getInstSizeInBytes(MF); |
524 | assert(OldSize >= NewSize); |
525 | #endif |
526 | return Modified; |
527 | } |
528 | |
529 | bool RISCVPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) { |
530 | bool Modified = false; |
531 | |
532 | MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); |
533 | while (MBBI != E) { |
534 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
535 | Modified |= expandMI(MBB, MBBI, NextMBBI&: NMBBI); |
536 | MBBI = NMBBI; |
537 | } |
538 | |
539 | return Modified; |
540 | } |
541 | |
542 | bool RISCVPreRAExpandPseudo::expandMI(MachineBasicBlock &MBB, |
543 | MachineBasicBlock::iterator MBBI, |
544 | MachineBasicBlock::iterator &NextMBBI) { |
545 | |
546 | switch (MBBI->getOpcode()) { |
547 | case RISCV::PseudoLLA: |
548 | return expandLoadLocalAddress(MBB, MBBI, NextMBBI); |
549 | case RISCV::PseudoLGA: |
550 | return expandLoadGlobalAddress(MBB, MBBI, NextMBBI); |
551 | case RISCV::PseudoLA_TLS_IE: |
552 | return expandLoadTLSIEAddress(MBB, MBBI, NextMBBI); |
553 | case RISCV::PseudoLA_TLS_GD: |
554 | return expandLoadTLSGDAddress(MBB, MBBI, NextMBBI); |
555 | case RISCV::PseudoLA_TLSDESC: |
556 | return expandLoadTLSDescAddress(MBB, MBBI, NextMBBI); |
557 | } |
558 | return false; |
559 | } |
560 | |
561 | bool RISCVPreRAExpandPseudo::expandAuipcInstPair( |
562 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
563 | MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi, |
564 | unsigned SecondOpcode) { |
565 | MachineFunction *MF = MBB.getParent(); |
566 | MachineInstr &MI = *MBBI; |
567 | DebugLoc DL = MI.getDebugLoc(); |
568 | |
569 | Register DestReg = MI.getOperand(i: 0).getReg(); |
570 | Register ScratchReg = |
571 | MF->getRegInfo().createVirtualRegister(RegClass: &RISCV::GPRRegClass); |
572 | |
573 | MachineOperand &Symbol = MI.getOperand(i: 1); |
574 | Symbol.setTargetFlags(FlagsHi); |
575 | MCSymbol *AUIPCSymbol = MF->getContext().createNamedTempSymbol(Name: "pcrel_hi" ); |
576 | |
577 | MachineInstr *MIAUIPC = |
578 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::AUIPC), DestReg: ScratchReg).add(MO: Symbol); |
579 | MIAUIPC->setPreInstrSymbol(MF&: *MF, Symbol: AUIPCSymbol); |
580 | |
581 | MachineInstr *SecondMI = |
582 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: SecondOpcode), DestReg) |
583 | .addReg(RegNo: ScratchReg) |
584 | .addSym(Sym: AUIPCSymbol, TargetFlags: RISCVII::MO_PCREL_LO); |
585 | |
586 | if (MI.hasOneMemOperand()) |
587 | SecondMI->addMemOperand(MF&: *MF, MO: *MI.memoperands_begin()); |
588 | |
589 | MI.eraseFromParent(); |
590 | return true; |
591 | } |
592 | |
593 | bool RISCVPreRAExpandPseudo::expandLoadLocalAddress( |
594 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
595 | MachineBasicBlock::iterator &NextMBBI) { |
596 | return expandAuipcInstPair(MBB, MBBI, NextMBBI, FlagsHi: RISCVII::MO_PCREL_HI, |
597 | SecondOpcode: RISCV::ADDI); |
598 | } |
599 | |
600 | bool RISCVPreRAExpandPseudo::expandLoadGlobalAddress( |
601 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
602 | MachineBasicBlock::iterator &NextMBBI) { |
603 | unsigned SecondOpcode = STI->is64Bit() ? RISCV::LD : RISCV::LW; |
604 | return expandAuipcInstPair(MBB, MBBI, NextMBBI, FlagsHi: RISCVII::MO_GOT_HI, |
605 | SecondOpcode); |
606 | } |
607 | |
608 | bool RISCVPreRAExpandPseudo::expandLoadTLSIEAddress( |
609 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
610 | MachineBasicBlock::iterator &NextMBBI) { |
611 | unsigned SecondOpcode = STI->is64Bit() ? RISCV::LD : RISCV::LW; |
612 | return expandAuipcInstPair(MBB, MBBI, NextMBBI, FlagsHi: RISCVII::MO_TLS_GOT_HI, |
613 | SecondOpcode); |
614 | } |
615 | |
616 | bool RISCVPreRAExpandPseudo::expandLoadTLSGDAddress( |
617 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
618 | MachineBasicBlock::iterator &NextMBBI) { |
619 | return expandAuipcInstPair(MBB, MBBI, NextMBBI, FlagsHi: RISCVII::MO_TLS_GD_HI, |
620 | SecondOpcode: RISCV::ADDI); |
621 | } |
622 | |
623 | bool RISCVPreRAExpandPseudo::expandLoadTLSDescAddress( |
624 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
625 | MachineBasicBlock::iterator &NextMBBI) { |
626 | MachineFunction *MF = MBB.getParent(); |
627 | MachineInstr &MI = *MBBI; |
628 | DebugLoc DL = MI.getDebugLoc(); |
629 | |
630 | const auto &STI = MF->getSubtarget<RISCVSubtarget>(); |
631 | unsigned SecondOpcode = STI.is64Bit() ? RISCV::LD : RISCV::LW; |
632 | |
633 | Register FinalReg = MI.getOperand(i: 0).getReg(); |
634 | Register DestReg = |
635 | MF->getRegInfo().createVirtualRegister(RegClass: &RISCV::GPRRegClass); |
636 | Register ScratchReg = |
637 | MF->getRegInfo().createVirtualRegister(RegClass: &RISCV::GPRRegClass); |
638 | |
639 | MachineOperand &Symbol = MI.getOperand(i: 1); |
640 | Symbol.setTargetFlags(RISCVII::MO_TLSDESC_HI); |
641 | MCSymbol *AUIPCSymbol = MF->getContext().createNamedTempSymbol(Name: "tlsdesc_hi" ); |
642 | |
643 | MachineInstr *MIAUIPC = |
644 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::AUIPC), DestReg: ScratchReg).add(MO: Symbol); |
645 | MIAUIPC->setPreInstrSymbol(MF&: *MF, Symbol: AUIPCSymbol); |
646 | |
647 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: SecondOpcode), DestReg) |
648 | .addReg(RegNo: ScratchReg) |
649 | .addSym(Sym: AUIPCSymbol, TargetFlags: RISCVII::MO_TLSDESC_LOAD_LO); |
650 | |
651 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::ADDI), DestReg: RISCV::X10) |
652 | .addReg(RegNo: ScratchReg) |
653 | .addSym(Sym: AUIPCSymbol, TargetFlags: RISCVII::MO_TLSDESC_ADD_LO); |
654 | |
655 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::PseudoTLSDESCCall), DestReg: RISCV::X5) |
656 | .addReg(RegNo: DestReg) |
657 | .addImm(Val: 0) |
658 | .addSym(Sym: AUIPCSymbol, TargetFlags: RISCVII::MO_TLSDESC_CALL); |
659 | |
660 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: RISCV::ADD), DestReg: FinalReg) |
661 | .addReg(RegNo: RISCV::X10) |
662 | .addReg(RegNo: RISCV::X4); |
663 | |
664 | MI.eraseFromParent(); |
665 | return true; |
666 | } |
667 | |
668 | } // end of anonymous namespace |
669 | |
670 | INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo" , |
671 | RISCV_EXPAND_PSEUDO_NAME, false, false) |
672 | |
673 | INITIALIZE_PASS(RISCVPreRAExpandPseudo, "riscv-prera-expand-pseudo" , |
674 | RISCV_PRERA_EXPAND_PSEUDO_NAME, false, false) |
675 | |
676 | namespace llvm { |
677 | |
678 | FunctionPass *createRISCVExpandPseudoPass() { return new RISCVExpandPseudo(); } |
679 | FunctionPass *createRISCVPreRAExpandPseudoPass() { return new RISCVPreRAExpandPseudo(); } |
680 | |
681 | } // end of namespace llvm |
682 | |