10b57cec5SDimitry Andric //===------- X86ExpandPseudo.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 to allow proper scheduling, if-conversion, other late 110b57cec5SDimitry Andric // optimizations, or simply the encoding of the instructions. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "X86.h" 160b57cec5SDimitry Andric #include "X86FrameLowering.h" 170b57cec5SDimitry Andric #include "X86InstrBuilder.h" 180b57cec5SDimitry Andric #include "X86InstrInfo.h" 190b57cec5SDimitry Andric #include "X86MachineFunctionInfo.h" 200b57cec5SDimitry Andric #include "X86Subtarget.h" 210b57cec5SDimitry Andric #include "llvm/Analysis/EHPersonalities.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" // For IDs of passes that are preserved. 250b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h" 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #define DEBUG_TYPE "x86-pseudo" 290b57cec5SDimitry Andric #define X86_EXPAND_PSEUDO_NAME "X86 pseudo instruction expansion pass" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace { 320b57cec5SDimitry Andric class X86ExpandPseudo : public MachineFunctionPass { 330b57cec5SDimitry Andric public: 340b57cec5SDimitry Andric static char ID; 350b57cec5SDimitry Andric X86ExpandPseudo() : MachineFunctionPass(ID) {} 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 380b57cec5SDimitry Andric AU.setPreservesCFG(); 390b57cec5SDimitry Andric AU.addPreservedID(MachineLoopInfoID); 400b57cec5SDimitry Andric AU.addPreservedID(MachineDominatorsID); 410b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric 44*480093f4SDimitry Andric const X86Subtarget *STI = nullptr; 45*480093f4SDimitry Andric const X86InstrInfo *TII = nullptr; 46*480093f4SDimitry Andric const X86RegisterInfo *TRI = nullptr; 47*480093f4SDimitry Andric const X86MachineFunctionInfo *X86FI = nullptr; 48*480093f4SDimitry Andric const X86FrameLowering *X86FL = nullptr; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 530b57cec5SDimitry Andric return MachineFunctionProperties().set( 540b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric StringRef getPassName() const override { 580b57cec5SDimitry Andric return "X86 pseudo instruction expansion pass"; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric private: 620b57cec5SDimitry Andric void ExpandICallBranchFunnel(MachineBasicBlock *MBB, 630b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric bool ExpandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); 660b57cec5SDimitry Andric bool ExpandMBB(MachineBasicBlock &MBB); 670b57cec5SDimitry Andric }; 680b57cec5SDimitry Andric char X86ExpandPseudo::ID = 0; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric } // End anonymous namespace. 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric INITIALIZE_PASS(X86ExpandPseudo, DEBUG_TYPE, X86_EXPAND_PSEUDO_NAME, false, 730b57cec5SDimitry Andric false) 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric void X86ExpandPseudo::ExpandICallBranchFunnel( 760b57cec5SDimitry Andric MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI) { 770b57cec5SDimitry Andric MachineBasicBlock *JTMBB = MBB; 780b57cec5SDimitry Andric MachineInstr *JTInst = &*MBBI; 790b57cec5SDimitry Andric MachineFunction *MF = MBB->getParent(); 800b57cec5SDimitry Andric const BasicBlock *BB = MBB->getBasicBlock(); 810b57cec5SDimitry Andric auto InsPt = MachineFunction::iterator(MBB); 820b57cec5SDimitry Andric ++InsPt; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric std::vector<std::pair<MachineBasicBlock *, unsigned>> TargetMBBs; 850b57cec5SDimitry Andric DebugLoc DL = JTInst->getDebugLoc(); 860b57cec5SDimitry Andric MachineOperand Selector = JTInst->getOperand(0); 870b57cec5SDimitry Andric const GlobalValue *CombinedGlobal = JTInst->getOperand(1).getGlobal(); 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric auto CmpTarget = [&](unsigned Target) { 900b57cec5SDimitry Andric if (Selector.isReg()) 910b57cec5SDimitry Andric MBB->addLiveIn(Selector.getReg()); 920b57cec5SDimitry Andric BuildMI(*MBB, MBBI, DL, TII->get(X86::LEA64r), X86::R11) 930b57cec5SDimitry Andric .addReg(X86::RIP) 940b57cec5SDimitry Andric .addImm(1) 950b57cec5SDimitry Andric .addReg(0) 960b57cec5SDimitry Andric .addGlobalAddress(CombinedGlobal, 970b57cec5SDimitry Andric JTInst->getOperand(2 + 2 * Target).getImm()) 980b57cec5SDimitry Andric .addReg(0); 990b57cec5SDimitry Andric BuildMI(*MBB, MBBI, DL, TII->get(X86::CMP64rr)) 1000b57cec5SDimitry Andric .add(Selector) 1010b57cec5SDimitry Andric .addReg(X86::R11); 1020b57cec5SDimitry Andric }; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric auto CreateMBB = [&]() { 1050b57cec5SDimitry Andric auto *NewMBB = MF->CreateMachineBasicBlock(BB); 1060b57cec5SDimitry Andric MBB->addSuccessor(NewMBB); 1070b57cec5SDimitry Andric if (!MBB->isLiveIn(X86::EFLAGS)) 1080b57cec5SDimitry Andric MBB->addLiveIn(X86::EFLAGS); 1090b57cec5SDimitry Andric return NewMBB; 1100b57cec5SDimitry Andric }; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric auto EmitCondJump = [&](unsigned CC, MachineBasicBlock *ThenMBB) { 1130b57cec5SDimitry Andric BuildMI(*MBB, MBBI, DL, TII->get(X86::JCC_1)).addMBB(ThenMBB).addImm(CC); 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric auto *ElseMBB = CreateMBB(); 1160b57cec5SDimitry Andric MF->insert(InsPt, ElseMBB); 1170b57cec5SDimitry Andric MBB = ElseMBB; 1180b57cec5SDimitry Andric MBBI = MBB->end(); 1190b57cec5SDimitry Andric }; 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric auto EmitCondJumpTarget = [&](unsigned CC, unsigned Target) { 1220b57cec5SDimitry Andric auto *ThenMBB = CreateMBB(); 1230b57cec5SDimitry Andric TargetMBBs.push_back({ThenMBB, Target}); 1240b57cec5SDimitry Andric EmitCondJump(CC, ThenMBB); 1250b57cec5SDimitry Andric }; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric auto EmitTailCall = [&](unsigned Target) { 1280b57cec5SDimitry Andric BuildMI(*MBB, MBBI, DL, TII->get(X86::TAILJMPd64)) 1290b57cec5SDimitry Andric .add(JTInst->getOperand(3 + 2 * Target)); 1300b57cec5SDimitry Andric }; 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric std::function<void(unsigned, unsigned)> EmitBranchFunnel = 1330b57cec5SDimitry Andric [&](unsigned FirstTarget, unsigned NumTargets) { 1340b57cec5SDimitry Andric if (NumTargets == 1) { 1350b57cec5SDimitry Andric EmitTailCall(FirstTarget); 1360b57cec5SDimitry Andric return; 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric if (NumTargets == 2) { 1400b57cec5SDimitry Andric CmpTarget(FirstTarget + 1); 1410b57cec5SDimitry Andric EmitCondJumpTarget(X86::COND_B, FirstTarget); 1420b57cec5SDimitry Andric EmitTailCall(FirstTarget + 1); 1430b57cec5SDimitry Andric return; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric if (NumTargets < 6) { 1470b57cec5SDimitry Andric CmpTarget(FirstTarget + 1); 1480b57cec5SDimitry Andric EmitCondJumpTarget(X86::COND_B, FirstTarget); 1490b57cec5SDimitry Andric EmitCondJumpTarget(X86::COND_E, FirstTarget + 1); 1500b57cec5SDimitry Andric EmitBranchFunnel(FirstTarget + 2, NumTargets - 2); 1510b57cec5SDimitry Andric return; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric auto *ThenMBB = CreateMBB(); 1550b57cec5SDimitry Andric CmpTarget(FirstTarget + (NumTargets / 2)); 1560b57cec5SDimitry Andric EmitCondJump(X86::COND_B, ThenMBB); 1570b57cec5SDimitry Andric EmitCondJumpTarget(X86::COND_E, FirstTarget + (NumTargets / 2)); 1580b57cec5SDimitry Andric EmitBranchFunnel(FirstTarget + (NumTargets / 2) + 1, 1590b57cec5SDimitry Andric NumTargets - (NumTargets / 2) - 1); 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric MF->insert(InsPt, ThenMBB); 1620b57cec5SDimitry Andric MBB = ThenMBB; 1630b57cec5SDimitry Andric MBBI = MBB->end(); 1640b57cec5SDimitry Andric EmitBranchFunnel(FirstTarget, NumTargets / 2); 1650b57cec5SDimitry Andric }; 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric EmitBranchFunnel(0, (JTInst->getNumOperands() - 2) / 2); 1680b57cec5SDimitry Andric for (auto P : TargetMBBs) { 1690b57cec5SDimitry Andric MF->insert(InsPt, P.first); 1700b57cec5SDimitry Andric BuildMI(P.first, DL, TII->get(X86::TAILJMPd64)) 1710b57cec5SDimitry Andric .add(JTInst->getOperand(3 + 2 * P.second)); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric JTMBB->erase(JTInst); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric /// If \p MBBI is a pseudo instruction, this method expands 1770b57cec5SDimitry Andric /// it to the corresponding (sequence of) actual instruction(s). 1780b57cec5SDimitry Andric /// \returns true if \p MBBI has been expanded. 1790b57cec5SDimitry Andric bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB, 1800b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI) { 1810b57cec5SDimitry Andric MachineInstr &MI = *MBBI; 1820b57cec5SDimitry Andric unsigned Opcode = MI.getOpcode(); 1830b57cec5SDimitry Andric DebugLoc DL = MBBI->getDebugLoc(); 1840b57cec5SDimitry Andric switch (Opcode) { 1850b57cec5SDimitry Andric default: 1860b57cec5SDimitry Andric return false; 1870b57cec5SDimitry Andric case X86::TCRETURNdi: 1880b57cec5SDimitry Andric case X86::TCRETURNdicc: 1890b57cec5SDimitry Andric case X86::TCRETURNri: 1900b57cec5SDimitry Andric case X86::TCRETURNmi: 1910b57cec5SDimitry Andric case X86::TCRETURNdi64: 1920b57cec5SDimitry Andric case X86::TCRETURNdi64cc: 1930b57cec5SDimitry Andric case X86::TCRETURNri64: 1940b57cec5SDimitry Andric case X86::TCRETURNmi64: { 1950b57cec5SDimitry Andric bool isMem = Opcode == X86::TCRETURNmi || Opcode == X86::TCRETURNmi64; 1960b57cec5SDimitry Andric MachineOperand &JumpTarget = MBBI->getOperand(0); 1978bcb0991SDimitry Andric MachineOperand &StackAdjust = MBBI->getOperand(isMem ? X86::AddrNumOperands 1988bcb0991SDimitry Andric : 1); 1990b57cec5SDimitry Andric assert(StackAdjust.isImm() && "Expecting immediate value."); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric // Adjust stack pointer. 2020b57cec5SDimitry Andric int StackAdj = StackAdjust.getImm(); 2030b57cec5SDimitry Andric int MaxTCDelta = X86FI->getTCReturnAddrDelta(); 2040b57cec5SDimitry Andric int Offset = 0; 2050b57cec5SDimitry Andric assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive"); 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric // Incoporate the retaddr area. 2080b57cec5SDimitry Andric Offset = StackAdj - MaxTCDelta; 2090b57cec5SDimitry Andric assert(Offset >= 0 && "Offset should never be negative"); 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric if (Opcode == X86::TCRETURNdicc || Opcode == X86::TCRETURNdi64cc) { 2120b57cec5SDimitry Andric assert(Offset == 0 && "Conditional tail call cannot adjust the stack."); 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric if (Offset) { 2160b57cec5SDimitry Andric // Check for possible merge with preceding ADD instruction. 2170b57cec5SDimitry Andric Offset += X86FL->mergeSPUpdates(MBB, MBBI, true); 2180b57cec5SDimitry Andric X86FL->emitSPUpdate(MBB, MBBI, DL, Offset, /*InEpilogue=*/true); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric // Jump to label or value in register. 2220b57cec5SDimitry Andric bool IsWin64 = STI->isTargetWin64(); 2230b57cec5SDimitry Andric if (Opcode == X86::TCRETURNdi || Opcode == X86::TCRETURNdicc || 2240b57cec5SDimitry Andric Opcode == X86::TCRETURNdi64 || Opcode == X86::TCRETURNdi64cc) { 2250b57cec5SDimitry Andric unsigned Op; 2260b57cec5SDimitry Andric switch (Opcode) { 2270b57cec5SDimitry Andric case X86::TCRETURNdi: 2280b57cec5SDimitry Andric Op = X86::TAILJMPd; 2290b57cec5SDimitry Andric break; 2300b57cec5SDimitry Andric case X86::TCRETURNdicc: 2310b57cec5SDimitry Andric Op = X86::TAILJMPd_CC; 2320b57cec5SDimitry Andric break; 2330b57cec5SDimitry Andric case X86::TCRETURNdi64cc: 2340b57cec5SDimitry Andric assert(!MBB.getParent()->hasWinCFI() && 2350b57cec5SDimitry Andric "Conditional tail calls confuse " 2360b57cec5SDimitry Andric "the Win64 unwinder."); 2370b57cec5SDimitry Andric Op = X86::TAILJMPd64_CC; 2380b57cec5SDimitry Andric break; 2390b57cec5SDimitry Andric default: 2400b57cec5SDimitry Andric // Note: Win64 uses REX prefixes indirect jumps out of functions, but 2410b57cec5SDimitry Andric // not direct ones. 2420b57cec5SDimitry Andric Op = X86::TAILJMPd64; 2430b57cec5SDimitry Andric break; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(Op)); 2460b57cec5SDimitry Andric if (JumpTarget.isGlobal()) { 2470b57cec5SDimitry Andric MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), 2480b57cec5SDimitry Andric JumpTarget.getTargetFlags()); 2490b57cec5SDimitry Andric } else { 2500b57cec5SDimitry Andric assert(JumpTarget.isSymbol()); 2510b57cec5SDimitry Andric MIB.addExternalSymbol(JumpTarget.getSymbolName(), 2520b57cec5SDimitry Andric JumpTarget.getTargetFlags()); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric if (Op == X86::TAILJMPd_CC || Op == X86::TAILJMPd64_CC) { 2550b57cec5SDimitry Andric MIB.addImm(MBBI->getOperand(2).getImm()); 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric } else if (Opcode == X86::TCRETURNmi || Opcode == X86::TCRETURNmi64) { 2590b57cec5SDimitry Andric unsigned Op = (Opcode == X86::TCRETURNmi) 2600b57cec5SDimitry Andric ? X86::TAILJMPm 2610b57cec5SDimitry Andric : (IsWin64 ? X86::TAILJMPm64_REX : X86::TAILJMPm64); 2620b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(Op)); 2638bcb0991SDimitry Andric for (unsigned i = 0; i != X86::AddrNumOperands; ++i) 2640b57cec5SDimitry Andric MIB.add(MBBI->getOperand(i)); 2650b57cec5SDimitry Andric } else if (Opcode == X86::TCRETURNri64) { 2660b57cec5SDimitry Andric JumpTarget.setIsKill(); 2670b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, 2680b57cec5SDimitry Andric TII->get(IsWin64 ? X86::TAILJMPr64_REX : X86::TAILJMPr64)) 2690b57cec5SDimitry Andric .add(JumpTarget); 2700b57cec5SDimitry Andric } else { 2710b57cec5SDimitry Andric JumpTarget.setIsKill(); 2720b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(X86::TAILJMPr)) 2730b57cec5SDimitry Andric .add(JumpTarget); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric MachineInstr &NewMI = *std::prev(MBBI); 2770b57cec5SDimitry Andric NewMI.copyImplicitOps(*MBBI->getParent()->getParent(), *MBBI); 2788bcb0991SDimitry Andric MBB.getParent()->moveCallSiteInfo(&*MBBI, &NewMI); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Delete the pseudo instruction TCRETURN. 2810b57cec5SDimitry Andric MBB.erase(MBBI); 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric return true; 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric case X86::EH_RETURN: 2860b57cec5SDimitry Andric case X86::EH_RETURN64: { 2870b57cec5SDimitry Andric MachineOperand &DestAddr = MBBI->getOperand(0); 2880b57cec5SDimitry Andric assert(DestAddr.isReg() && "Offset should be in register!"); 2890b57cec5SDimitry Andric const bool Uses64BitFramePtr = 2900b57cec5SDimitry Andric STI->isTarget64BitLP64() || STI->isTargetNaCl64(); 2918bcb0991SDimitry Andric Register StackPtr = TRI->getStackRegister(); 2920b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, 2930b57cec5SDimitry Andric TII->get(Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr), StackPtr) 2940b57cec5SDimitry Andric .addReg(DestAddr.getReg()); 2950b57cec5SDimitry Andric // The EH_RETURN pseudo is really removed during the MC Lowering. 2960b57cec5SDimitry Andric return true; 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric case X86::IRET: { 2990b57cec5SDimitry Andric // Adjust stack to erase error code 3000b57cec5SDimitry Andric int64_t StackAdj = MBBI->getOperand(0).getImm(); 3010b57cec5SDimitry Andric X86FL->emitSPUpdate(MBB, MBBI, DL, StackAdj, true); 3020b57cec5SDimitry Andric // Replace pseudo with machine iret 3030b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, 3040b57cec5SDimitry Andric TII->get(STI->is64Bit() ? X86::IRET64 : X86::IRET32)); 3050b57cec5SDimitry Andric MBB.erase(MBBI); 3060b57cec5SDimitry Andric return true; 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric case X86::RET: { 3090b57cec5SDimitry Andric // Adjust stack to erase error code 3100b57cec5SDimitry Andric int64_t StackAdj = MBBI->getOperand(0).getImm(); 3110b57cec5SDimitry Andric MachineInstrBuilder MIB; 3120b57cec5SDimitry Andric if (StackAdj == 0) { 3130b57cec5SDimitry Andric MIB = BuildMI(MBB, MBBI, DL, 3140b57cec5SDimitry Andric TII->get(STI->is64Bit() ? X86::RETQ : X86::RETL)); 3150b57cec5SDimitry Andric } else if (isUInt<16>(StackAdj)) { 3160b57cec5SDimitry Andric MIB = BuildMI(MBB, MBBI, DL, 3170b57cec5SDimitry Andric TII->get(STI->is64Bit() ? X86::RETIQ : X86::RETIL)) 3180b57cec5SDimitry Andric .addImm(StackAdj); 3190b57cec5SDimitry Andric } else { 3200b57cec5SDimitry Andric assert(!STI->is64Bit() && 3210b57cec5SDimitry Andric "shouldn't need to do this for x86_64 targets!"); 3220b57cec5SDimitry Andric // A ret can only handle immediates as big as 2**16-1. If we need to pop 3230b57cec5SDimitry Andric // off bytes before the return address, we must do it manually. 3240b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(X86::POP32r)).addReg(X86::ECX, RegState::Define); 3250b57cec5SDimitry Andric X86FL->emitSPUpdate(MBB, MBBI, DL, StackAdj, /*InEpilogue=*/true); 3260b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(X86::PUSH32r)).addReg(X86::ECX); 3270b57cec5SDimitry Andric MIB = BuildMI(MBB, MBBI, DL, TII->get(X86::RETL)); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric for (unsigned I = 1, E = MBBI->getNumOperands(); I != E; ++I) 3300b57cec5SDimitry Andric MIB.add(MBBI->getOperand(I)); 3310b57cec5SDimitry Andric MBB.erase(MBBI); 3320b57cec5SDimitry Andric return true; 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric case X86::EH_RESTORE: { 3350b57cec5SDimitry Andric // Restore ESP and EBP, and optionally ESI if required. 3360b57cec5SDimitry Andric bool IsSEH = isAsynchronousEHPersonality(classifyEHPersonality( 3370b57cec5SDimitry Andric MBB.getParent()->getFunction().getPersonalityFn())); 3380b57cec5SDimitry Andric X86FL->restoreWin32EHStackPointers(MBB, MBBI, DL, /*RestoreSP=*/IsSEH); 3390b57cec5SDimitry Andric MBBI->eraseFromParent(); 3400b57cec5SDimitry Andric return true; 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric case X86::LCMPXCHG8B_SAVE_EBX: 3430b57cec5SDimitry Andric case X86::LCMPXCHG16B_SAVE_RBX: { 3440b57cec5SDimitry Andric // Perform the following transformation. 3450b57cec5SDimitry Andric // SaveRbx = pseudocmpxchg Addr, <4 opds for the address>, InArg, SaveRbx 3460b57cec5SDimitry Andric // => 3470b57cec5SDimitry Andric // [E|R]BX = InArg 3480b57cec5SDimitry Andric // actualcmpxchg Addr 3490b57cec5SDimitry Andric // [E|R]BX = SaveRbx 3500b57cec5SDimitry Andric const MachineOperand &InArg = MBBI->getOperand(6); 3518bcb0991SDimitry Andric Register SaveRbx = MBBI->getOperand(7).getReg(); 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric unsigned ActualInArg = 3540b57cec5SDimitry Andric Opcode == X86::LCMPXCHG8B_SAVE_EBX ? X86::EBX : X86::RBX; 3550b57cec5SDimitry Andric // Copy the input argument of the pseudo into the argument of the 3560b57cec5SDimitry Andric // actual instruction. 3570b57cec5SDimitry Andric TII->copyPhysReg(MBB, MBBI, DL, ActualInArg, InArg.getReg(), 3580b57cec5SDimitry Andric InArg.isKill()); 3590b57cec5SDimitry Andric // Create the actual instruction. 3600b57cec5SDimitry Andric unsigned ActualOpc = 3610b57cec5SDimitry Andric Opcode == X86::LCMPXCHG8B_SAVE_EBX ? X86::LCMPXCHG8B : X86::LCMPXCHG16B; 3620b57cec5SDimitry Andric MachineInstr *NewInstr = BuildMI(MBB, MBBI, DL, TII->get(ActualOpc)); 3630b57cec5SDimitry Andric // Copy the operands related to the address. 3640b57cec5SDimitry Andric for (unsigned Idx = 1; Idx < 6; ++Idx) 3650b57cec5SDimitry Andric NewInstr->addOperand(MBBI->getOperand(Idx)); 3660b57cec5SDimitry Andric // Finally, restore the value of RBX. 3670b57cec5SDimitry Andric TII->copyPhysReg(MBB, MBBI, DL, ActualInArg, SaveRbx, 3680b57cec5SDimitry Andric /*SrcIsKill*/ true); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric // Delete the pseudo. 3710b57cec5SDimitry Andric MBBI->eraseFromParent(); 3720b57cec5SDimitry Andric return true; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric case TargetOpcode::ICALL_BRANCH_FUNNEL: 3750b57cec5SDimitry Andric ExpandICallBranchFunnel(&MBB, MBBI); 3760b57cec5SDimitry Andric return true; 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric llvm_unreachable("Previous switch has a fallthrough?"); 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric /// Expand all pseudo instructions contained in \p MBB. 3820b57cec5SDimitry Andric /// \returns true if any expansion occurred for \p MBB. 3830b57cec5SDimitry Andric bool X86ExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { 3840b57cec5SDimitry Andric bool Modified = false; 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric // MBBI may be invalidated by the expansion. 3870b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 3880b57cec5SDimitry Andric while (MBBI != E) { 3890b57cec5SDimitry Andric MachineBasicBlock::iterator NMBBI = std::next(MBBI); 3900b57cec5SDimitry Andric Modified |= ExpandMI(MBB, MBBI); 3910b57cec5SDimitry Andric MBBI = NMBBI; 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric return Modified; 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric bool X86ExpandPseudo::runOnMachineFunction(MachineFunction &MF) { 3980b57cec5SDimitry Andric STI = &static_cast<const X86Subtarget &>(MF.getSubtarget()); 3990b57cec5SDimitry Andric TII = STI->getInstrInfo(); 4000b57cec5SDimitry Andric TRI = STI->getRegisterInfo(); 4010b57cec5SDimitry Andric X86FI = MF.getInfo<X86MachineFunctionInfo>(); 4020b57cec5SDimitry Andric X86FL = STI->getFrameLowering(); 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric bool Modified = false; 4050b57cec5SDimitry Andric for (MachineBasicBlock &MBB : MF) 4060b57cec5SDimitry Andric Modified |= ExpandMBB(MBB); 4070b57cec5SDimitry Andric return Modified; 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric /// Returns an instance of the pseudo instruction expansion pass. 4110b57cec5SDimitry Andric FunctionPass *llvm::createX86ExpandPseudoPass() { 4120b57cec5SDimitry Andric return new X86ExpandPseudo(); 4130b57cec5SDimitry Andric } 414