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