10b57cec5SDimitry Andric //===-- RISCVExpandPseudoInsts.cpp - Expand pseudo instructions -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a pass that expands pseudo instructions into target
100b57cec5SDimitry Andric // instructions. This pass should be run after register allocation but before
110b57cec5SDimitry Andric // the post-regalloc scheduling pass.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "RISCV.h"
160b57cec5SDimitry Andric #include "RISCVInstrInfo.h"
170b57cec5SDimitry Andric #include "RISCVTargetMachine.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
22bdd1243dSDimitry Andric #include "llvm/MC/MCContext.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric 
2606c3fb27SDimitry Andric #define RISCV_EXPAND_PSEUDO_NAME "RISC-V pseudo instruction expansion pass"
2706c3fb27SDimitry Andric #define RISCV_PRERA_EXPAND_PSEUDO_NAME "RISC-V Pre-RA pseudo instruction expansion pass"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace {
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric class RISCVExpandPseudo : public MachineFunctionPass {
320b57cec5SDimitry Andric public:
3306c3fb27SDimitry Andric   const RISCVSubtarget *STI;
340b57cec5SDimitry Andric   const RISCVInstrInfo *TII;
350b57cec5SDimitry Andric   static char ID;
360b57cec5SDimitry Andric 
RISCVExpandPseudo()375f757f3fSDimitry Andric   RISCVExpandPseudo() : MachineFunctionPass(ID) {}
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
400b57cec5SDimitry Andric 
getPassName() const410b57cec5SDimitry Andric   StringRef getPassName() const override { return RISCV_EXPAND_PSEUDO_NAME; }
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric private:
440b57cec5SDimitry Andric   bool expandMBB(MachineBasicBlock &MBB);
450b57cec5SDimitry Andric   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
460b57cec5SDimitry Andric                 MachineBasicBlock::iterator &NextMBBI);
47bdd1243dSDimitry Andric   bool expandCCOp(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
480b57cec5SDimitry Andric                   MachineBasicBlock::iterator &NextMBBI);
49e8d8bef9SDimitry Andric   bool expandVSetVL(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
50e8d8bef9SDimitry Andric   bool expandVMSET_VMCLR(MachineBasicBlock &MBB,
51e8d8bef9SDimitry Andric                          MachineBasicBlock::iterator MBBI, unsigned Opcode);
5206c3fb27SDimitry Andric   bool expandRV32ZdinxStore(MachineBasicBlock &MBB,
5306c3fb27SDimitry Andric                             MachineBasicBlock::iterator MBBI);
5406c3fb27SDimitry Andric   bool expandRV32ZdinxLoad(MachineBasicBlock &MBB,
5506c3fb27SDimitry Andric                            MachineBasicBlock::iterator MBBI);
5606c3fb27SDimitry Andric #ifndef NDEBUG
getInstSizeInBytes(const MachineFunction & MF) const5706c3fb27SDimitry Andric   unsigned getInstSizeInBytes(const MachineFunction &MF) const {
5806c3fb27SDimitry Andric     unsigned Size = 0;
5906c3fb27SDimitry Andric     for (auto &MBB : MF)
6006c3fb27SDimitry Andric       for (auto &MI : MBB)
6106c3fb27SDimitry Andric         Size += TII->getInstSizeInBytes(MI);
6206c3fb27SDimitry Andric     return Size;
6306c3fb27SDimitry Andric   }
6406c3fb27SDimitry Andric #endif
650b57cec5SDimitry Andric };
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric char RISCVExpandPseudo::ID = 0;
680b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)690b57cec5SDimitry Andric bool RISCVExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
7006c3fb27SDimitry Andric   STI = &MF.getSubtarget<RISCVSubtarget>();
7106c3fb27SDimitry Andric   TII = STI->getInstrInfo();
7206c3fb27SDimitry Andric 
7306c3fb27SDimitry Andric #ifndef NDEBUG
7406c3fb27SDimitry Andric   const unsigned OldSize = getInstSizeInBytes(MF);
7506c3fb27SDimitry Andric #endif
7606c3fb27SDimitry Andric 
770b57cec5SDimitry Andric   bool Modified = false;
780b57cec5SDimitry Andric   for (auto &MBB : MF)
790b57cec5SDimitry Andric     Modified |= expandMBB(MBB);
8006c3fb27SDimitry Andric 
8106c3fb27SDimitry Andric #ifndef NDEBUG
8206c3fb27SDimitry Andric   const unsigned NewSize = getInstSizeInBytes(MF);
8306c3fb27SDimitry Andric   assert(OldSize >= NewSize);
8406c3fb27SDimitry Andric #endif
850b57cec5SDimitry Andric   return Modified;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
expandMBB(MachineBasicBlock & MBB)880b57cec5SDimitry Andric bool RISCVExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
890b57cec5SDimitry Andric   bool Modified = false;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
920b57cec5SDimitry Andric   while (MBBI != E) {
930b57cec5SDimitry Andric     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
940b57cec5SDimitry Andric     Modified |= expandMI(MBB, MBBI, NMBBI);
950b57cec5SDimitry Andric     MBBI = NMBBI;
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   return Modified;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
expandMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)1010b57cec5SDimitry Andric bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
1020b57cec5SDimitry Andric                                  MachineBasicBlock::iterator MBBI,
1030b57cec5SDimitry Andric                                  MachineBasicBlock::iterator &NextMBBI) {
1041fd87a68SDimitry Andric   // RISCVInstrInfo::getInstSizeInBytes expects that the total size of the
1051fd87a68SDimitry Andric   // expanded instructions for each pseudo is correct in the Size field of the
1061fd87a68SDimitry Andric   // tablegen definition for the pseudo.
1070b57cec5SDimitry Andric   switch (MBBI->getOpcode()) {
10806c3fb27SDimitry Andric   case RISCV::PseudoRV32ZdinxSD:
10906c3fb27SDimitry Andric     return expandRV32ZdinxStore(MBB, MBBI);
11006c3fb27SDimitry Andric   case RISCV::PseudoRV32ZdinxLD:
11106c3fb27SDimitry Andric     return expandRV32ZdinxLoad(MBB, MBBI);
1121db9f3b2SDimitry Andric   case RISCV::PseudoCCMOVGPRNoX0:
113bdd1243dSDimitry Andric   case RISCV::PseudoCCMOVGPR:
114bdd1243dSDimitry Andric   case RISCV::PseudoCCADD:
115bdd1243dSDimitry Andric   case RISCV::PseudoCCSUB:
116bdd1243dSDimitry Andric   case RISCV::PseudoCCAND:
117bdd1243dSDimitry Andric   case RISCV::PseudoCCOR:
118bdd1243dSDimitry Andric   case RISCV::PseudoCCXOR:
119bdd1243dSDimitry Andric   case RISCV::PseudoCCADDW:
120bdd1243dSDimitry Andric   case RISCV::PseudoCCSUBW:
1215f757f3fSDimitry Andric   case RISCV::PseudoCCSLL:
1225f757f3fSDimitry Andric   case RISCV::PseudoCCSRL:
1235f757f3fSDimitry Andric   case RISCV::PseudoCCSRA:
1245f757f3fSDimitry Andric   case RISCV::PseudoCCADDI:
1255f757f3fSDimitry Andric   case RISCV::PseudoCCSLLI:
1265f757f3fSDimitry Andric   case RISCV::PseudoCCSRLI:
1275f757f3fSDimitry Andric   case RISCV::PseudoCCSRAI:
1285f757f3fSDimitry Andric   case RISCV::PseudoCCANDI:
1295f757f3fSDimitry Andric   case RISCV::PseudoCCORI:
1305f757f3fSDimitry Andric   case RISCV::PseudoCCXORI:
1315f757f3fSDimitry Andric   case RISCV::PseudoCCSLLW:
1325f757f3fSDimitry Andric   case RISCV::PseudoCCSRLW:
1335f757f3fSDimitry Andric   case RISCV::PseudoCCSRAW:
1345f757f3fSDimitry Andric   case RISCV::PseudoCCADDIW:
1355f757f3fSDimitry Andric   case RISCV::PseudoCCSLLIW:
1365f757f3fSDimitry Andric   case RISCV::PseudoCCSRLIW:
1375f757f3fSDimitry Andric   case RISCV::PseudoCCSRAIW:
1381db9f3b2SDimitry Andric   case RISCV::PseudoCCANDN:
1391db9f3b2SDimitry Andric   case RISCV::PseudoCCORN:
1401db9f3b2SDimitry Andric   case RISCV::PseudoCCXNOR:
141bdd1243dSDimitry Andric     return expandCCOp(MBB, MBBI, NextMBBI);
142e8d8bef9SDimitry Andric   case RISCV::PseudoVSETVLI:
143349cc55cSDimitry Andric   case RISCV::PseudoVSETVLIX0:
144d409305fSDimitry Andric   case RISCV::PseudoVSETIVLI:
145e8d8bef9SDimitry Andric     return expandVSetVL(MBB, MBBI);
146e8d8bef9SDimitry Andric   case RISCV::PseudoVMCLR_M_B1:
147e8d8bef9SDimitry Andric   case RISCV::PseudoVMCLR_M_B2:
148e8d8bef9SDimitry Andric   case RISCV::PseudoVMCLR_M_B4:
149e8d8bef9SDimitry Andric   case RISCV::PseudoVMCLR_M_B8:
150e8d8bef9SDimitry Andric   case RISCV::PseudoVMCLR_M_B16:
151e8d8bef9SDimitry Andric   case RISCV::PseudoVMCLR_M_B32:
152e8d8bef9SDimitry Andric   case RISCV::PseudoVMCLR_M_B64:
153e8d8bef9SDimitry Andric     // vmclr.m vd => vmxor.mm vd, vd, vd
154e8d8bef9SDimitry Andric     return expandVMSET_VMCLR(MBB, MBBI, RISCV::VMXOR_MM);
155e8d8bef9SDimitry Andric   case RISCV::PseudoVMSET_M_B1:
156e8d8bef9SDimitry Andric   case RISCV::PseudoVMSET_M_B2:
157e8d8bef9SDimitry Andric   case RISCV::PseudoVMSET_M_B4:
158e8d8bef9SDimitry Andric   case RISCV::PseudoVMSET_M_B8:
159e8d8bef9SDimitry Andric   case RISCV::PseudoVMSET_M_B16:
160e8d8bef9SDimitry Andric   case RISCV::PseudoVMSET_M_B32:
161e8d8bef9SDimitry Andric   case RISCV::PseudoVMSET_M_B64:
162e8d8bef9SDimitry Andric     // vmset.m vd => vmxnor.mm vd, vd, vd
163e8d8bef9SDimitry Andric     return expandVMSET_VMCLR(MBB, MBBI, RISCV::VMXNOR_MM);
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   return false;
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
expandCCOp(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)169bdd1243dSDimitry Andric bool RISCVExpandPseudo::expandCCOp(MachineBasicBlock &MBB,
170bdd1243dSDimitry Andric                                    MachineBasicBlock::iterator MBBI,
171bdd1243dSDimitry Andric                                    MachineBasicBlock::iterator &NextMBBI) {
172bdd1243dSDimitry Andric 
1730b57cec5SDimitry Andric   MachineFunction *MF = MBB.getParent();
1740b57cec5SDimitry Andric   MachineInstr &MI = *MBBI;
1750b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
1760b57cec5SDimitry Andric 
177bdd1243dSDimitry Andric   MachineBasicBlock *TrueBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
178bdd1243dSDimitry Andric   MachineBasicBlock *MergeBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
179bdd1243dSDimitry Andric 
180bdd1243dSDimitry Andric   MF->insert(++MBB.getIterator(), TrueBB);
181bdd1243dSDimitry Andric   MF->insert(++TrueBB->getIterator(), MergeBB);
182bdd1243dSDimitry Andric 
183bdd1243dSDimitry Andric   // We want to copy the "true" value when the condition is true which means
184bdd1243dSDimitry Andric   // we need to invert the branch condition to jump over TrueBB when the
185bdd1243dSDimitry Andric   // condition is false.
186bdd1243dSDimitry Andric   auto CC = static_cast<RISCVCC::CondCode>(MI.getOperand(3).getImm());
187bdd1243dSDimitry Andric   CC = RISCVCC::getOppositeBranchCondition(CC);
188bdd1243dSDimitry Andric 
189bdd1243dSDimitry Andric   // Insert branch instruction.
190bdd1243dSDimitry Andric   BuildMI(MBB, MBBI, DL, TII->getBrCond(CC))
191bdd1243dSDimitry Andric       .addReg(MI.getOperand(1).getReg())
192bdd1243dSDimitry Andric       .addReg(MI.getOperand(2).getReg())
193bdd1243dSDimitry Andric       .addMBB(MergeBB);
194bdd1243dSDimitry Andric 
1958bcb0991SDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
196bdd1243dSDimitry Andric   assert(MI.getOperand(4).getReg() == DestReg);
1970b57cec5SDimitry Andric 
1981db9f3b2SDimitry Andric   if (MI.getOpcode() == RISCV::PseudoCCMOVGPR ||
1991db9f3b2SDimitry Andric       MI.getOpcode() == RISCV::PseudoCCMOVGPRNoX0) {
200bdd1243dSDimitry Andric     // Add MV.
201bdd1243dSDimitry Andric     BuildMI(TrueBB, DL, TII->get(RISCV::ADDI), DestReg)
202bdd1243dSDimitry Andric         .add(MI.getOperand(5))
203bdd1243dSDimitry Andric         .addImm(0);
204bdd1243dSDimitry Andric   } else {
205bdd1243dSDimitry Andric     unsigned NewOpc;
206bdd1243dSDimitry Andric     switch (MI.getOpcode()) {
207bdd1243dSDimitry Andric     default:
208bdd1243dSDimitry Andric       llvm_unreachable("Unexpected opcode!");
209bdd1243dSDimitry Andric     case RISCV::PseudoCCADD:   NewOpc = RISCV::ADD;   break;
210bdd1243dSDimitry Andric     case RISCV::PseudoCCSUB:   NewOpc = RISCV::SUB;   break;
2115f757f3fSDimitry Andric     case RISCV::PseudoCCSLL:   NewOpc = RISCV::SLL;   break;
2125f757f3fSDimitry Andric     case RISCV::PseudoCCSRL:   NewOpc = RISCV::SRL;   break;
2135f757f3fSDimitry Andric     case RISCV::PseudoCCSRA:   NewOpc = RISCV::SRA;   break;
214bdd1243dSDimitry Andric     case RISCV::PseudoCCAND:   NewOpc = RISCV::AND;   break;
215bdd1243dSDimitry Andric     case RISCV::PseudoCCOR:    NewOpc = RISCV::OR;    break;
216bdd1243dSDimitry Andric     case RISCV::PseudoCCXOR:   NewOpc = RISCV::XOR;   break;
2175f757f3fSDimitry Andric     case RISCV::PseudoCCADDI:  NewOpc = RISCV::ADDI;  break;
2185f757f3fSDimitry Andric     case RISCV::PseudoCCSLLI:  NewOpc = RISCV::SLLI;  break;
2195f757f3fSDimitry Andric     case RISCV::PseudoCCSRLI:  NewOpc = RISCV::SRLI;  break;
2205f757f3fSDimitry Andric     case RISCV::PseudoCCSRAI:  NewOpc = RISCV::SRAI;  break;
2215f757f3fSDimitry Andric     case RISCV::PseudoCCANDI:  NewOpc = RISCV::ANDI;  break;
2225f757f3fSDimitry Andric     case RISCV::PseudoCCORI:   NewOpc = RISCV::ORI;   break;
2235f757f3fSDimitry Andric     case RISCV::PseudoCCXORI:  NewOpc = RISCV::XORI;  break;
224bdd1243dSDimitry Andric     case RISCV::PseudoCCADDW:  NewOpc = RISCV::ADDW;  break;
225bdd1243dSDimitry Andric     case RISCV::PseudoCCSUBW:  NewOpc = RISCV::SUBW;  break;
2265f757f3fSDimitry Andric     case RISCV::PseudoCCSLLW:  NewOpc = RISCV::SLLW;  break;
2275f757f3fSDimitry Andric     case RISCV::PseudoCCSRLW:  NewOpc = RISCV::SRLW;  break;
2285f757f3fSDimitry Andric     case RISCV::PseudoCCSRAW:  NewOpc = RISCV::SRAW;  break;
2295f757f3fSDimitry Andric     case RISCV::PseudoCCADDIW: NewOpc = RISCV::ADDIW; break;
2305f757f3fSDimitry Andric     case RISCV::PseudoCCSLLIW: NewOpc = RISCV::SLLIW; break;
2315f757f3fSDimitry Andric     case RISCV::PseudoCCSRLIW: NewOpc = RISCV::SRLIW; break;
2325f757f3fSDimitry Andric     case RISCV::PseudoCCSRAIW: NewOpc = RISCV::SRAIW; break;
2331db9f3b2SDimitry Andric     case RISCV::PseudoCCANDN:  NewOpc = RISCV::ANDN;  break;
2341db9f3b2SDimitry Andric     case RISCV::PseudoCCORN:   NewOpc = RISCV::ORN;   break;
2351db9f3b2SDimitry Andric     case RISCV::PseudoCCXNOR:  NewOpc = RISCV::XNOR;  break;
236bdd1243dSDimitry Andric     }
237bdd1243dSDimitry Andric     BuildMI(TrueBB, DL, TII->get(NewOpc), DestReg)
238bdd1243dSDimitry Andric         .add(MI.getOperand(5))
239bdd1243dSDimitry Andric         .add(MI.getOperand(6));
240bdd1243dSDimitry Andric   }
2410b57cec5SDimitry Andric 
242bdd1243dSDimitry Andric   TrueBB->addSuccessor(MergeBB);
2430b57cec5SDimitry Andric 
244bdd1243dSDimitry Andric   MergeBB->splice(MergeBB->end(), &MBB, MI, MBB.end());
245bdd1243dSDimitry Andric   MergeBB->transferSuccessors(&MBB);
2460b57cec5SDimitry Andric 
247bdd1243dSDimitry Andric   MBB.addSuccessor(TrueBB);
248bdd1243dSDimitry Andric   MBB.addSuccessor(MergeBB);
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   NextMBBI = MBB.end();
2510b57cec5SDimitry Andric   MI.eraseFromParent();
252bdd1243dSDimitry Andric 
253bdd1243dSDimitry Andric   // Make sure live-ins are correctly attached to this new basic block.
254bdd1243dSDimitry Andric   LivePhysRegs LiveRegs;
255bdd1243dSDimitry Andric   computeAndAddLiveIns(LiveRegs, *TrueBB);
256bdd1243dSDimitry Andric   computeAndAddLiveIns(LiveRegs, *MergeBB);
257bdd1243dSDimitry Andric 
2580b57cec5SDimitry Andric   return true;
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric 
expandVSetVL(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI)261e8d8bef9SDimitry Andric bool RISCVExpandPseudo::expandVSetVL(MachineBasicBlock &MBB,
262e8d8bef9SDimitry Andric                                      MachineBasicBlock::iterator MBBI) {
263fe6060f1SDimitry Andric   assert(MBBI->getNumExplicitOperands() == 3 && MBBI->getNumOperands() >= 5 &&
264fe6060f1SDimitry Andric          "Unexpected instruction format");
265e8d8bef9SDimitry Andric 
266e8d8bef9SDimitry Andric   DebugLoc DL = MBBI->getDebugLoc();
267e8d8bef9SDimitry Andric 
268d409305fSDimitry Andric   assert((MBBI->getOpcode() == RISCV::PseudoVSETVLI ||
269349cc55cSDimitry Andric           MBBI->getOpcode() == RISCV::PseudoVSETVLIX0 ||
270d409305fSDimitry Andric           MBBI->getOpcode() == RISCV::PseudoVSETIVLI) &&
271e8d8bef9SDimitry Andric          "Unexpected pseudo instruction");
272d409305fSDimitry Andric   unsigned Opcode;
273349cc55cSDimitry Andric   if (MBBI->getOpcode() == RISCV::PseudoVSETIVLI)
274d409305fSDimitry Andric     Opcode = RISCV::VSETIVLI;
275349cc55cSDimitry Andric   else
276349cc55cSDimitry Andric     Opcode = RISCV::VSETVLI;
277d409305fSDimitry Andric   const MCInstrDesc &Desc = TII->get(Opcode);
278e8d8bef9SDimitry Andric   assert(Desc.getNumOperands() == 3 && "Unexpected instruction format");
279e8d8bef9SDimitry Andric 
280e8d8bef9SDimitry Andric   Register DstReg = MBBI->getOperand(0).getReg();
281e8d8bef9SDimitry Andric   bool DstIsDead = MBBI->getOperand(0).isDead();
282e8d8bef9SDimitry Andric   BuildMI(MBB, MBBI, DL, Desc)
283e8d8bef9SDimitry Andric       .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
284e8d8bef9SDimitry Andric       .add(MBBI->getOperand(1))  // VL
285e8d8bef9SDimitry Andric       .add(MBBI->getOperand(2)); // VType
286e8d8bef9SDimitry Andric 
287e8d8bef9SDimitry Andric   MBBI->eraseFromParent(); // The pseudo instruction is gone now.
288e8d8bef9SDimitry Andric   return true;
289e8d8bef9SDimitry Andric }
290e8d8bef9SDimitry Andric 
expandVMSET_VMCLR(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,unsigned Opcode)291e8d8bef9SDimitry Andric bool RISCVExpandPseudo::expandVMSET_VMCLR(MachineBasicBlock &MBB,
292e8d8bef9SDimitry Andric                                           MachineBasicBlock::iterator MBBI,
293e8d8bef9SDimitry Andric                                           unsigned Opcode) {
294e8d8bef9SDimitry Andric   DebugLoc DL = MBBI->getDebugLoc();
295e8d8bef9SDimitry Andric   Register DstReg = MBBI->getOperand(0).getReg();
296e8d8bef9SDimitry Andric   const MCInstrDesc &Desc = TII->get(Opcode);
297e8d8bef9SDimitry Andric   BuildMI(MBB, MBBI, DL, Desc, DstReg)
298e8d8bef9SDimitry Andric       .addReg(DstReg, RegState::Undef)
299e8d8bef9SDimitry Andric       .addReg(DstReg, RegState::Undef);
300e8d8bef9SDimitry Andric   MBBI->eraseFromParent(); // The pseudo instruction is gone now.
301e8d8bef9SDimitry Andric   return true;
302e8d8bef9SDimitry Andric }
303e8d8bef9SDimitry Andric 
30406c3fb27SDimitry Andric // This function expands the PseudoRV32ZdinxSD for storing a double-precision
30506c3fb27SDimitry Andric // floating-point value into memory by generating an equivalent instruction
30606c3fb27SDimitry Andric // sequence for RV32.
expandRV32ZdinxStore(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI)30706c3fb27SDimitry Andric bool RISCVExpandPseudo::expandRV32ZdinxStore(MachineBasicBlock &MBB,
30806c3fb27SDimitry Andric                                              MachineBasicBlock::iterator MBBI) {
30906c3fb27SDimitry Andric   DebugLoc DL = MBBI->getDebugLoc();
31006c3fb27SDimitry Andric   const TargetRegisterInfo *TRI = STI->getRegisterInfo();
311297eecfbSDimitry Andric   Register Lo =
312297eecfbSDimitry Andric       TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_even);
313297eecfbSDimitry Andric   Register Hi =
314297eecfbSDimitry Andric       TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_odd);
31506c3fb27SDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(RISCV::SW))
31606c3fb27SDimitry Andric       .addReg(Lo, getKillRegState(MBBI->getOperand(0).isKill()))
31706c3fb27SDimitry Andric       .addReg(MBBI->getOperand(1).getReg())
31806c3fb27SDimitry Andric       .add(MBBI->getOperand(2));
31906c3fb27SDimitry Andric   if (MBBI->getOperand(2).isGlobal() || MBBI->getOperand(2).isCPI()) {
320*3a079333SDimitry Andric     // FIXME: Zdinx RV32 can not work on unaligned scalar memory.
321*3a079333SDimitry Andric     assert(!STI->hasFastUnalignedAccess() &&
322*3a079333SDimitry Andric            !STI->enableUnalignedScalarMem());
32306c3fb27SDimitry Andric 
32406c3fb27SDimitry Andric     assert(MBBI->getOperand(2).getOffset() % 8 == 0);
32506c3fb27SDimitry Andric     MBBI->getOperand(2).setOffset(MBBI->getOperand(2).getOffset() + 4);
32606c3fb27SDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(RISCV::SW))
32706c3fb27SDimitry Andric         .addReg(Hi, getKillRegState(MBBI->getOperand(0).isKill()))
32806c3fb27SDimitry Andric         .add(MBBI->getOperand(1))
32906c3fb27SDimitry Andric         .add(MBBI->getOperand(2));
33006c3fb27SDimitry Andric   } else {
33106c3fb27SDimitry Andric     assert(isInt<12>(MBBI->getOperand(2).getImm() + 4));
33206c3fb27SDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(RISCV::SW))
33306c3fb27SDimitry Andric         .addReg(Hi, getKillRegState(MBBI->getOperand(0).isKill()))
33406c3fb27SDimitry Andric         .add(MBBI->getOperand(1))
33506c3fb27SDimitry Andric         .addImm(MBBI->getOperand(2).getImm() + 4);
33606c3fb27SDimitry Andric   }
33706c3fb27SDimitry Andric   MBBI->eraseFromParent();
33806c3fb27SDimitry Andric   return true;
33906c3fb27SDimitry Andric }
34006c3fb27SDimitry Andric 
34106c3fb27SDimitry Andric // This function expands PseudoRV32ZdinxLoad for loading a double-precision
34206c3fb27SDimitry Andric // floating-point value from memory into an equivalent instruction sequence for
34306c3fb27SDimitry Andric // RV32.
expandRV32ZdinxLoad(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI)34406c3fb27SDimitry Andric bool RISCVExpandPseudo::expandRV32ZdinxLoad(MachineBasicBlock &MBB,
34506c3fb27SDimitry Andric                                             MachineBasicBlock::iterator MBBI) {
34606c3fb27SDimitry Andric   DebugLoc DL = MBBI->getDebugLoc();
34706c3fb27SDimitry Andric   const TargetRegisterInfo *TRI = STI->getRegisterInfo();
348297eecfbSDimitry Andric   Register Lo =
349297eecfbSDimitry Andric       TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_even);
350297eecfbSDimitry Andric   Register Hi =
351297eecfbSDimitry Andric       TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_odd);
35206c3fb27SDimitry Andric 
35306c3fb27SDimitry Andric   // If the register of operand 1 is equal to the Lo register, then swap the
35406c3fb27SDimitry Andric   // order of loading the Lo and Hi statements.
35506c3fb27SDimitry Andric   bool IsOp1EqualToLo = Lo == MBBI->getOperand(1).getReg();
35606c3fb27SDimitry Andric   // Order: Lo, Hi
35706c3fb27SDimitry Andric   if (!IsOp1EqualToLo) {
35806c3fb27SDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Lo)
35906c3fb27SDimitry Andric         .addReg(MBBI->getOperand(1).getReg())
36006c3fb27SDimitry Andric         .add(MBBI->getOperand(2));
36106c3fb27SDimitry Andric   }
36206c3fb27SDimitry Andric 
36306c3fb27SDimitry Andric   if (MBBI->getOperand(2).isGlobal() || MBBI->getOperand(2).isCPI()) {
36406c3fb27SDimitry Andric     auto Offset = MBBI->getOperand(2).getOffset();
36506c3fb27SDimitry Andric     assert(MBBI->getOperand(2).getOffset() % 8 == 0);
36606c3fb27SDimitry Andric     MBBI->getOperand(2).setOffset(Offset + 4);
36706c3fb27SDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Hi)
36806c3fb27SDimitry Andric         .addReg(MBBI->getOperand(1).getReg())
36906c3fb27SDimitry Andric         .add(MBBI->getOperand(2));
37006c3fb27SDimitry Andric     MBBI->getOperand(2).setOffset(Offset);
37106c3fb27SDimitry Andric   } else {
37206c3fb27SDimitry Andric     assert(isInt<12>(MBBI->getOperand(2).getImm() + 4));
37306c3fb27SDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Hi)
37406c3fb27SDimitry Andric         .addReg(MBBI->getOperand(1).getReg())
37506c3fb27SDimitry Andric         .addImm(MBBI->getOperand(2).getImm() + 4);
37606c3fb27SDimitry Andric   }
37706c3fb27SDimitry Andric 
37806c3fb27SDimitry Andric   // Order: Hi, Lo
37906c3fb27SDimitry Andric   if (IsOp1EqualToLo) {
38006c3fb27SDimitry Andric     BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Lo)
38106c3fb27SDimitry Andric         .addReg(MBBI->getOperand(1).getReg())
38206c3fb27SDimitry Andric         .add(MBBI->getOperand(2));
38306c3fb27SDimitry Andric   }
38406c3fb27SDimitry Andric 
38506c3fb27SDimitry Andric   MBBI->eraseFromParent();
38606c3fb27SDimitry Andric   return true;
38706c3fb27SDimitry Andric }
38806c3fb27SDimitry Andric 
389bdd1243dSDimitry Andric class RISCVPreRAExpandPseudo : public MachineFunctionPass {
390bdd1243dSDimitry Andric public:
39106c3fb27SDimitry Andric   const RISCVSubtarget *STI;
392bdd1243dSDimitry Andric   const RISCVInstrInfo *TII;
393bdd1243dSDimitry Andric   static char ID;
394fe6060f1SDimitry Andric 
RISCVPreRAExpandPseudo()3955f757f3fSDimitry Andric   RISCVPreRAExpandPseudo() : MachineFunctionPass(ID) {}
396bdd1243dSDimitry Andric 
397bdd1243dSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
398bdd1243dSDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const399bdd1243dSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
400bdd1243dSDimitry Andric     AU.setPreservesCFG();
401bdd1243dSDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
402bdd1243dSDimitry Andric   }
getPassName() const403bdd1243dSDimitry Andric   StringRef getPassName() const override {
404bdd1243dSDimitry Andric     return RISCV_PRERA_EXPAND_PSEUDO_NAME;
405bdd1243dSDimitry Andric   }
406bdd1243dSDimitry Andric 
407bdd1243dSDimitry Andric private:
408bdd1243dSDimitry Andric   bool expandMBB(MachineBasicBlock &MBB);
409bdd1243dSDimitry Andric   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
410bdd1243dSDimitry Andric                 MachineBasicBlock::iterator &NextMBBI);
411bdd1243dSDimitry Andric   bool expandAuipcInstPair(MachineBasicBlock &MBB,
412bdd1243dSDimitry Andric                            MachineBasicBlock::iterator MBBI,
413bdd1243dSDimitry Andric                            MachineBasicBlock::iterator &NextMBBI,
414bdd1243dSDimitry Andric                            unsigned FlagsHi, unsigned SecondOpcode);
415bdd1243dSDimitry Andric   bool expandLoadLocalAddress(MachineBasicBlock &MBB,
416bdd1243dSDimitry Andric                               MachineBasicBlock::iterator MBBI,
417bdd1243dSDimitry Andric                               MachineBasicBlock::iterator &NextMBBI);
41806c3fb27SDimitry Andric   bool expandLoadGlobalAddress(MachineBasicBlock &MBB,
419bdd1243dSDimitry Andric                                MachineBasicBlock::iterator MBBI,
420bdd1243dSDimitry Andric                                MachineBasicBlock::iterator &NextMBBI);
421bdd1243dSDimitry Andric   bool expandLoadTLSIEAddress(MachineBasicBlock &MBB,
422bdd1243dSDimitry Andric                               MachineBasicBlock::iterator MBBI,
423bdd1243dSDimitry Andric                               MachineBasicBlock::iterator &NextMBBI);
424bdd1243dSDimitry Andric   bool expandLoadTLSGDAddress(MachineBasicBlock &MBB,
425bdd1243dSDimitry Andric                               MachineBasicBlock::iterator MBBI,
426bdd1243dSDimitry Andric                               MachineBasicBlock::iterator &NextMBBI);
4277a6dacacSDimitry Andric   bool expandLoadTLSDescAddress(MachineBasicBlock &MBB,
4287a6dacacSDimitry Andric                                 MachineBasicBlock::iterator MBBI,
4297a6dacacSDimitry Andric                                 MachineBasicBlock::iterator &NextMBBI);
4307a6dacacSDimitry Andric 
43106c3fb27SDimitry Andric #ifndef NDEBUG
getInstSizeInBytes(const MachineFunction & MF) const43206c3fb27SDimitry Andric   unsigned getInstSizeInBytes(const MachineFunction &MF) const {
43306c3fb27SDimitry Andric     unsigned Size = 0;
43406c3fb27SDimitry Andric     for (auto &MBB : MF)
43506c3fb27SDimitry Andric       for (auto &MI : MBB)
43606c3fb27SDimitry Andric         Size += TII->getInstSizeInBytes(MI);
43706c3fb27SDimitry Andric     return Size;
43806c3fb27SDimitry Andric   }
43906c3fb27SDimitry Andric #endif
440bdd1243dSDimitry Andric };
441bdd1243dSDimitry Andric 
442bdd1243dSDimitry Andric char RISCVPreRAExpandPseudo::ID = 0;
443bdd1243dSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)444bdd1243dSDimitry Andric bool RISCVPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
44506c3fb27SDimitry Andric   STI = &MF.getSubtarget<RISCVSubtarget>();
44606c3fb27SDimitry Andric   TII = STI->getInstrInfo();
44706c3fb27SDimitry Andric 
44806c3fb27SDimitry Andric #ifndef NDEBUG
44906c3fb27SDimitry Andric   const unsigned OldSize = getInstSizeInBytes(MF);
45006c3fb27SDimitry Andric #endif
45106c3fb27SDimitry Andric 
452bdd1243dSDimitry Andric   bool Modified = false;
453bdd1243dSDimitry Andric   for (auto &MBB : MF)
454bdd1243dSDimitry Andric     Modified |= expandMBB(MBB);
45506c3fb27SDimitry Andric 
45606c3fb27SDimitry Andric #ifndef NDEBUG
45706c3fb27SDimitry Andric   const unsigned NewSize = getInstSizeInBytes(MF);
45806c3fb27SDimitry Andric   assert(OldSize >= NewSize);
45906c3fb27SDimitry Andric #endif
460bdd1243dSDimitry Andric   return Modified;
461bdd1243dSDimitry Andric }
462bdd1243dSDimitry Andric 
expandMBB(MachineBasicBlock & MBB)463bdd1243dSDimitry Andric bool RISCVPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
464bdd1243dSDimitry Andric   bool Modified = false;
465bdd1243dSDimitry Andric 
466bdd1243dSDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
467bdd1243dSDimitry Andric   while (MBBI != E) {
468bdd1243dSDimitry Andric     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
469bdd1243dSDimitry Andric     Modified |= expandMI(MBB, MBBI, NMBBI);
470bdd1243dSDimitry Andric     MBBI = NMBBI;
471bdd1243dSDimitry Andric   }
472bdd1243dSDimitry Andric 
473bdd1243dSDimitry Andric   return Modified;
474bdd1243dSDimitry Andric }
475bdd1243dSDimitry Andric 
expandMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)476bdd1243dSDimitry Andric bool RISCVPreRAExpandPseudo::expandMI(MachineBasicBlock &MBB,
477bdd1243dSDimitry Andric                                       MachineBasicBlock::iterator MBBI,
478bdd1243dSDimitry Andric                                       MachineBasicBlock::iterator &NextMBBI) {
479bdd1243dSDimitry Andric 
480bdd1243dSDimitry Andric   switch (MBBI->getOpcode()) {
481bdd1243dSDimitry Andric   case RISCV::PseudoLLA:
482bdd1243dSDimitry Andric     return expandLoadLocalAddress(MBB, MBBI, NextMBBI);
48306c3fb27SDimitry Andric   case RISCV::PseudoLGA:
48406c3fb27SDimitry Andric     return expandLoadGlobalAddress(MBB, MBBI, NextMBBI);
485bdd1243dSDimitry Andric   case RISCV::PseudoLA_TLS_IE:
486bdd1243dSDimitry Andric     return expandLoadTLSIEAddress(MBB, MBBI, NextMBBI);
487bdd1243dSDimitry Andric   case RISCV::PseudoLA_TLS_GD:
488bdd1243dSDimitry Andric     return expandLoadTLSGDAddress(MBB, MBBI, NextMBBI);
4897a6dacacSDimitry Andric   case RISCV::PseudoLA_TLSDESC:
4907a6dacacSDimitry Andric     return expandLoadTLSDescAddress(MBB, MBBI, NextMBBI);
491bdd1243dSDimitry Andric   }
492bdd1243dSDimitry Andric   return false;
493bdd1243dSDimitry Andric }
494bdd1243dSDimitry Andric 
expandAuipcInstPair(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned FlagsHi,unsigned SecondOpcode)495bdd1243dSDimitry Andric bool RISCVPreRAExpandPseudo::expandAuipcInstPair(
496bdd1243dSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
497bdd1243dSDimitry Andric     MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi,
498bdd1243dSDimitry Andric     unsigned SecondOpcode) {
499bdd1243dSDimitry Andric   MachineFunction *MF = MBB.getParent();
500bdd1243dSDimitry Andric   MachineInstr &MI = *MBBI;
501bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
502bdd1243dSDimitry Andric 
503bdd1243dSDimitry Andric   Register DestReg = MI.getOperand(0).getReg();
504bdd1243dSDimitry Andric   Register ScratchReg =
505bdd1243dSDimitry Andric       MF->getRegInfo().createVirtualRegister(&RISCV::GPRRegClass);
506bdd1243dSDimitry Andric 
507bdd1243dSDimitry Andric   MachineOperand &Symbol = MI.getOperand(1);
508bdd1243dSDimitry Andric   Symbol.setTargetFlags(FlagsHi);
509bdd1243dSDimitry Andric   MCSymbol *AUIPCSymbol = MF->getContext().createNamedTempSymbol("pcrel_hi");
510bdd1243dSDimitry Andric 
511bdd1243dSDimitry Andric   MachineInstr *MIAUIPC =
512bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL, TII->get(RISCV::AUIPC), ScratchReg).add(Symbol);
513bdd1243dSDimitry Andric   MIAUIPC->setPreInstrSymbol(*MF, AUIPCSymbol);
514bdd1243dSDimitry Andric 
515bdd1243dSDimitry Andric   MachineInstr *SecondMI =
516bdd1243dSDimitry Andric       BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
517bdd1243dSDimitry Andric           .addReg(ScratchReg)
518bdd1243dSDimitry Andric           .addSym(AUIPCSymbol, RISCVII::MO_PCREL_LO);
519bdd1243dSDimitry Andric 
520bdd1243dSDimitry Andric   if (MI.hasOneMemOperand())
521bdd1243dSDimitry Andric     SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
522bdd1243dSDimitry Andric 
523bdd1243dSDimitry Andric   MI.eraseFromParent();
524fe6060f1SDimitry Andric   return true;
525fe6060f1SDimitry Andric }
526fe6060f1SDimitry Andric 
expandLoadLocalAddress(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)527bdd1243dSDimitry Andric bool RISCVPreRAExpandPseudo::expandLoadLocalAddress(
528bdd1243dSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
529bdd1243dSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
530bdd1243dSDimitry Andric   return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_PCREL_HI,
531bdd1243dSDimitry Andric                              RISCV::ADDI);
532fe6060f1SDimitry Andric }
533bdd1243dSDimitry Andric 
expandLoadGlobalAddress(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)53406c3fb27SDimitry Andric bool RISCVPreRAExpandPseudo::expandLoadGlobalAddress(
535bdd1243dSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
536bdd1243dSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
53706c3fb27SDimitry Andric   unsigned SecondOpcode = STI->is64Bit() ? RISCV::LD : RISCV::LW;
538bdd1243dSDimitry Andric   return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_GOT_HI,
539bdd1243dSDimitry Andric                              SecondOpcode);
540bdd1243dSDimitry Andric }
541bdd1243dSDimitry Andric 
expandLoadTLSIEAddress(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)542bdd1243dSDimitry Andric bool RISCVPreRAExpandPseudo::expandLoadTLSIEAddress(
543bdd1243dSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
544bdd1243dSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
54506c3fb27SDimitry Andric   unsigned SecondOpcode = STI->is64Bit() ? RISCV::LD : RISCV::LW;
546bdd1243dSDimitry Andric   return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_TLS_GOT_HI,
547bdd1243dSDimitry Andric                              SecondOpcode);
548bdd1243dSDimitry Andric }
549bdd1243dSDimitry Andric 
expandLoadTLSGDAddress(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)550bdd1243dSDimitry Andric bool RISCVPreRAExpandPseudo::expandLoadTLSGDAddress(
551bdd1243dSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
552bdd1243dSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
553bdd1243dSDimitry Andric   return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_TLS_GD_HI,
554bdd1243dSDimitry Andric                              RISCV::ADDI);
555fe6060f1SDimitry Andric }
556fe6060f1SDimitry Andric 
expandLoadTLSDescAddress(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)5577a6dacacSDimitry Andric bool RISCVPreRAExpandPseudo::expandLoadTLSDescAddress(
5587a6dacacSDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
5597a6dacacSDimitry Andric     MachineBasicBlock::iterator &NextMBBI) {
5607a6dacacSDimitry Andric   MachineFunction *MF = MBB.getParent();
5617a6dacacSDimitry Andric   MachineInstr &MI = *MBBI;
5627a6dacacSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
5637a6dacacSDimitry Andric 
5647a6dacacSDimitry Andric   const auto &STI = MF->getSubtarget<RISCVSubtarget>();
5657a6dacacSDimitry Andric   unsigned SecondOpcode = STI.is64Bit() ? RISCV::LD : RISCV::LW;
5667a6dacacSDimitry Andric 
5677a6dacacSDimitry Andric   Register FinalReg = MI.getOperand(0).getReg();
5687a6dacacSDimitry Andric   Register DestReg =
5697a6dacacSDimitry Andric       MF->getRegInfo().createVirtualRegister(&RISCV::GPRRegClass);
5707a6dacacSDimitry Andric   Register ScratchReg =
5717a6dacacSDimitry Andric       MF->getRegInfo().createVirtualRegister(&RISCV::GPRRegClass);
5727a6dacacSDimitry Andric 
5737a6dacacSDimitry Andric   MachineOperand &Symbol = MI.getOperand(1);
5747a6dacacSDimitry Andric   Symbol.setTargetFlags(RISCVII::MO_TLSDESC_HI);
5757a6dacacSDimitry Andric   MCSymbol *AUIPCSymbol = MF->getContext().createNamedTempSymbol("tlsdesc_hi");
5767a6dacacSDimitry Andric 
5777a6dacacSDimitry Andric   MachineInstr *MIAUIPC =
5787a6dacacSDimitry Andric       BuildMI(MBB, MBBI, DL, TII->get(RISCV::AUIPC), ScratchReg).add(Symbol);
5797a6dacacSDimitry Andric   MIAUIPC->setPreInstrSymbol(*MF, AUIPCSymbol);
5807a6dacacSDimitry Andric 
5817a6dacacSDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
5827a6dacacSDimitry Andric       .addReg(ScratchReg)
5837a6dacacSDimitry Andric       .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_LOAD_LO);
5847a6dacacSDimitry Andric 
5857a6dacacSDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), RISCV::X10)
5867a6dacacSDimitry Andric       .addReg(ScratchReg)
5877a6dacacSDimitry Andric       .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_ADD_LO);
5887a6dacacSDimitry Andric 
5897a6dacacSDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(RISCV::PseudoTLSDESCCall), RISCV::X5)
5907a6dacacSDimitry Andric       .addReg(DestReg)
5917a6dacacSDimitry Andric       .addImm(0)
5927a6dacacSDimitry Andric       .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_CALL);
5937a6dacacSDimitry Andric 
5947a6dacacSDimitry Andric   BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADD), FinalReg)
5957a6dacacSDimitry Andric       .addReg(RISCV::X10)
5967a6dacacSDimitry Andric       .addReg(RISCV::X4);
5977a6dacacSDimitry Andric 
5987a6dacacSDimitry Andric   MI.eraseFromParent();
5997a6dacacSDimitry Andric   return true;
6007a6dacacSDimitry Andric }
6017a6dacacSDimitry Andric 
6020b57cec5SDimitry Andric } // end of anonymous namespace
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",
6050b57cec5SDimitry Andric                 RISCV_EXPAND_PSEUDO_NAME, false, false)
606bdd1243dSDimitry Andric 
607bdd1243dSDimitry Andric INITIALIZE_PASS(RISCVPreRAExpandPseudo, "riscv-prera-expand-pseudo",
608bdd1243dSDimitry Andric                 RISCV_PRERA_EXPAND_PSEUDO_NAME, false, false)
609bdd1243dSDimitry Andric 
6100b57cec5SDimitry Andric namespace llvm {
6110b57cec5SDimitry Andric 
createRISCVExpandPseudoPass()6120b57cec5SDimitry Andric FunctionPass *createRISCVExpandPseudoPass() { return new RISCVExpandPseudo(); }
createRISCVPreRAExpandPseudoPass()613bdd1243dSDimitry Andric FunctionPass *createRISCVPreRAExpandPseudoPass() { return new RISCVPreRAExpandPseudo(); }
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric } // end of namespace llvm
616