diff options
Diffstat (limited to 'llvm/lib/CodeGen/ExpandPostRAPseudos.cpp')
| -rw-r--r-- | llvm/lib/CodeGen/ExpandPostRAPseudos.cpp | 226 | 
1 files changed, 226 insertions, 0 deletions
| diff --git a/llvm/lib/CodeGen/ExpandPostRAPseudos.cpp b/llvm/lib/CodeGen/ExpandPostRAPseudos.cpp new file mode 100644 index 000000000000..1fc57fac1489 --- /dev/null +++ b/llvm/lib/CodeGen/ExpandPostRAPseudos.cpp @@ -0,0 +1,226 @@ +//===-- ExpandPostRAPseudos.cpp - Pseudo instruction expansion pass -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a pass that expands COPY and SUBREG_TO_REG pseudo +// instructions after register allocation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "postrapseudos" + +namespace { +struct ExpandPostRA : public MachineFunctionPass { +private: +  const TargetRegisterInfo *TRI; +  const TargetInstrInfo *TII; + +public: +  static char ID; // Pass identification, replacement for typeid +  ExpandPostRA() : MachineFunctionPass(ID) {} + +  void getAnalysisUsage(AnalysisUsage &AU) const override { +    AU.setPreservesCFG(); +    AU.addPreservedID(MachineLoopInfoID); +    AU.addPreservedID(MachineDominatorsID); +    MachineFunctionPass::getAnalysisUsage(AU); +  } + +  /// runOnMachineFunction - pass entry point +  bool runOnMachineFunction(MachineFunction&) override; + +private: +  bool LowerSubregToReg(MachineInstr *MI); +  bool LowerCopy(MachineInstr *MI); + +  void TransferImplicitOperands(MachineInstr *MI); +}; +} // end anonymous namespace + +char ExpandPostRA::ID = 0; +char &llvm::ExpandPostRAPseudosID = ExpandPostRA::ID; + +INITIALIZE_PASS(ExpandPostRA, DEBUG_TYPE, +                "Post-RA pseudo instruction expansion pass", false, false) + +/// TransferImplicitOperands - MI is a pseudo-instruction, and the lowered +/// replacement instructions immediately precede it.  Copy any implicit +/// operands from MI to the replacement instruction. +void ExpandPostRA::TransferImplicitOperands(MachineInstr *MI) { +  MachineBasicBlock::iterator CopyMI = MI; +  --CopyMI; + +  for (const MachineOperand &MO : MI->implicit_operands()) +    if (MO.isReg()) +      CopyMI->addOperand(MO); +} + +bool ExpandPostRA::LowerSubregToReg(MachineInstr *MI) { +  MachineBasicBlock *MBB = MI->getParent(); +  assert((MI->getOperand(0).isReg() && MI->getOperand(0).isDef()) && +         MI->getOperand(1).isImm() && +         (MI->getOperand(2).isReg() && MI->getOperand(2).isUse()) && +          MI->getOperand(3).isImm() && "Invalid subreg_to_reg"); + +  Register DstReg = MI->getOperand(0).getReg(); +  Register InsReg = MI->getOperand(2).getReg(); +  assert(!MI->getOperand(2).getSubReg() && "SubIdx on physreg?"); +  unsigned SubIdx  = MI->getOperand(3).getImm(); + +  assert(SubIdx != 0 && "Invalid index for insert_subreg"); +  Register DstSubReg = TRI->getSubReg(DstReg, SubIdx); + +  assert(Register::isPhysicalRegister(DstReg) && +         "Insert destination must be in a physical register"); +  assert(Register::isPhysicalRegister(InsReg) && +         "Inserted value must be in a physical register"); + +  LLVM_DEBUG(dbgs() << "subreg: CONVERTING: " << *MI); + +  if (MI->allDefsAreDead()) { +    MI->setDesc(TII->get(TargetOpcode::KILL)); +    MI->RemoveOperand(3); // SubIdx +    MI->RemoveOperand(1); // Imm +    LLVM_DEBUG(dbgs() << "subreg: replaced by: " << *MI); +    return true; +  } + +  if (DstSubReg == InsReg) { +    // No need to insert an identity copy instruction. +    // Watch out for case like this: +    // %rax = SUBREG_TO_REG 0, killed %eax, 3 +    // We must leave %rax live. +    if (DstReg != InsReg) { +      MI->setDesc(TII->get(TargetOpcode::KILL)); +      MI->RemoveOperand(3);     // SubIdx +      MI->RemoveOperand(1);     // Imm +      LLVM_DEBUG(dbgs() << "subreg: replace by: " << *MI); +      return true; +    } +    LLVM_DEBUG(dbgs() << "subreg: eliminated!"); +  } else { +    TII->copyPhysReg(*MBB, MI, MI->getDebugLoc(), DstSubReg, InsReg, +                     MI->getOperand(2).isKill()); + +    // Implicitly define DstReg for subsequent uses. +    MachineBasicBlock::iterator CopyMI = MI; +    --CopyMI; +    CopyMI->addRegisterDefined(DstReg); +    LLVM_DEBUG(dbgs() << "subreg: " << *CopyMI); +  } + +  LLVM_DEBUG(dbgs() << '\n'); +  MBB->erase(MI); +  return true; +} + +bool ExpandPostRA::LowerCopy(MachineInstr *MI) { + +  if (MI->allDefsAreDead()) { +    LLVM_DEBUG(dbgs() << "dead copy: " << *MI); +    MI->setDesc(TII->get(TargetOpcode::KILL)); +    LLVM_DEBUG(dbgs() << "replaced by: " << *MI); +    return true; +  } + +  MachineOperand &DstMO = MI->getOperand(0); +  MachineOperand &SrcMO = MI->getOperand(1); + +  bool IdentityCopy = (SrcMO.getReg() == DstMO.getReg()); +  if (IdentityCopy || SrcMO.isUndef()) { +    LLVM_DEBUG(dbgs() << (IdentityCopy ? "identity copy: " : "undef copy:    ") +                      << *MI); +    // No need to insert an identity copy instruction, but replace with a KILL +    // if liveness is changed. +    if (SrcMO.isUndef() || MI->getNumOperands() > 2) { +      // We must make sure the super-register gets killed. Replace the +      // instruction with KILL. +      MI->setDesc(TII->get(TargetOpcode::KILL)); +      LLVM_DEBUG(dbgs() << "replaced by:   " << *MI); +      return true; +    } +    // Vanilla identity copy. +    MI->eraseFromParent(); +    return true; +  } + +  LLVM_DEBUG(dbgs() << "real copy:   " << *MI); +  TII->copyPhysReg(*MI->getParent(), MI, MI->getDebugLoc(), +                   DstMO.getReg(), SrcMO.getReg(), SrcMO.isKill()); + +  if (MI->getNumOperands() > 2) +    TransferImplicitOperands(MI); +  LLVM_DEBUG({ +    MachineBasicBlock::iterator dMI = MI; +    dbgs() << "replaced by: " << *(--dMI); +  }); +  MI->eraseFromParent(); +  return true; +} + +/// runOnMachineFunction - Reduce subregister inserts and extracts to register +/// copies. +/// +bool ExpandPostRA::runOnMachineFunction(MachineFunction &MF) { +  LLVM_DEBUG(dbgs() << "Machine Function\n" +                    << "********** EXPANDING POST-RA PSEUDO INSTRS **********\n" +                    << "********** Function: " << MF.getName() << '\n'); +  TRI = MF.getSubtarget().getRegisterInfo(); +  TII = MF.getSubtarget().getInstrInfo(); + +  bool MadeChange = false; + +  for (MachineFunction::iterator mbbi = MF.begin(), mbbe = MF.end(); +       mbbi != mbbe; ++mbbi) { +    for (MachineBasicBlock::iterator mi = mbbi->begin(), me = mbbi->end(); +         mi != me;) { +      MachineInstr &MI = *mi; +      // Advance iterator here because MI may be erased. +      ++mi; + +      // Only expand pseudos. +      if (!MI.isPseudo()) +        continue; + +      // Give targets a chance to expand even standard pseudos. +      if (TII->expandPostRAPseudo(MI)) { +        MadeChange = true; +        continue; +      } + +      // Expand standard pseudos. +      switch (MI.getOpcode()) { +      case TargetOpcode::SUBREG_TO_REG: +        MadeChange |= LowerSubregToReg(&MI); +        break; +      case TargetOpcode::COPY: +        MadeChange |= LowerCopy(&MI); +        break; +      case TargetOpcode::DBG_VALUE: +        continue; +      case TargetOpcode::INSERT_SUBREG: +      case TargetOpcode::EXTRACT_SUBREG: +        llvm_unreachable("Sub-register pseudos should have been eliminated."); +      } +    } +  } + +  return MadeChange; +} | 
