diff options
Diffstat (limited to 'llvm/lib/CodeGen/ProcessImplicitDefs.cpp')
| -rw-r--r-- | llvm/lib/CodeGen/ProcessImplicitDefs.cpp | 165 | 
1 files changed, 165 insertions, 0 deletions
| diff --git a/llvm/lib/CodeGen/ProcessImplicitDefs.cpp b/llvm/lib/CodeGen/ProcessImplicitDefs.cpp new file mode 100644 index 000000000000..11bff45f9ad5 --- /dev/null +++ b/llvm/lib/CodeGen/ProcessImplicitDefs.cpp @@ -0,0 +1,165 @@ +//===---------------------- ProcessImplicitDefs.cpp -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SetVector.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "processimpdefs" + +namespace { +/// Process IMPLICIT_DEF instructions and make sure there is one implicit_def +/// for each use. Add isUndef marker to implicit_def defs and their uses. +class ProcessImplicitDefs : public MachineFunctionPass { +  const TargetInstrInfo *TII; +  const TargetRegisterInfo *TRI; +  MachineRegisterInfo *MRI; + +  SmallSetVector<MachineInstr*, 16> WorkList; + +  void processImplicitDef(MachineInstr *MI); +  bool canTurnIntoImplicitDef(MachineInstr *MI); + +public: +  static char ID; + +  ProcessImplicitDefs() : MachineFunctionPass(ID) { +    initializeProcessImplicitDefsPass(*PassRegistry::getPassRegistry()); +  } + +  void getAnalysisUsage(AnalysisUsage &au) const override; + +  bool runOnMachineFunction(MachineFunction &MF) override; +}; +} // end anonymous namespace + +char ProcessImplicitDefs::ID = 0; +char &llvm::ProcessImplicitDefsID = ProcessImplicitDefs::ID; + +INITIALIZE_PASS(ProcessImplicitDefs, DEBUG_TYPE, +                "Process Implicit Definitions", false, false) + +void ProcessImplicitDefs::getAnalysisUsage(AnalysisUsage &AU) const { +  AU.setPreservesCFG(); +  AU.addPreserved<AAResultsWrapperPass>(); +  MachineFunctionPass::getAnalysisUsage(AU); +} + +bool ProcessImplicitDefs::canTurnIntoImplicitDef(MachineInstr *MI) { +  if (!MI->isCopyLike() && +      !MI->isInsertSubreg() && +      !MI->isRegSequence() && +      !MI->isPHI()) +    return false; +  for (const MachineOperand &MO : MI->operands()) +    if (MO.isReg() && MO.isUse() && MO.readsReg()) +      return false; +  return true; +} + +void ProcessImplicitDefs::processImplicitDef(MachineInstr *MI) { +  LLVM_DEBUG(dbgs() << "Processing " << *MI); +  Register Reg = MI->getOperand(0).getReg(); + +  if (Register::isVirtualRegister(Reg)) { +    // For virtual registers, mark all uses as <undef>, and convert users to +    // implicit-def when possible. +    for (MachineOperand &MO : MRI->use_nodbg_operands(Reg)) { +      MO.setIsUndef(); +      MachineInstr *UserMI = MO.getParent(); +      if (!canTurnIntoImplicitDef(UserMI)) +        continue; +      LLVM_DEBUG(dbgs() << "Converting to IMPLICIT_DEF: " << *UserMI); +      UserMI->setDesc(TII->get(TargetOpcode::IMPLICIT_DEF)); +      WorkList.insert(UserMI); +    } +    MI->eraseFromParent(); +    return; +  } + +  // This is a physreg implicit-def. +  // Look for the first instruction to use or define an alias. +  MachineBasicBlock::instr_iterator UserMI = MI->getIterator(); +  MachineBasicBlock::instr_iterator UserE = MI->getParent()->instr_end(); +  bool Found = false; +  for (++UserMI; UserMI != UserE; ++UserMI) { +    for (MachineOperand &MO : UserMI->operands()) { +      if (!MO.isReg()) +        continue; +      Register UserReg = MO.getReg(); +      if (!Register::isPhysicalRegister(UserReg) || +          !TRI->regsOverlap(Reg, UserReg)) +        continue; +      // UserMI uses or redefines Reg. Set <undef> flags on all uses. +      Found = true; +      if (MO.isUse()) +        MO.setIsUndef(); +    } +    if (Found) +      break; +  } + +  // If we found the using MI, we can erase the IMPLICIT_DEF. +  if (Found) { +    LLVM_DEBUG(dbgs() << "Physreg user: " << *UserMI); +    MI->eraseFromParent(); +    return; +  } + +  // Using instr wasn't found, it could be in another block. +  // Leave the physreg IMPLICIT_DEF, but trim any extra operands. +  for (unsigned i = MI->getNumOperands() - 1; i; --i) +    MI->RemoveOperand(i); +  LLVM_DEBUG(dbgs() << "Keeping physreg: " << *MI); +} + +/// processImplicitDefs - Process IMPLICIT_DEF instructions and turn them into +/// <undef> operands. +bool ProcessImplicitDefs::runOnMachineFunction(MachineFunction &MF) { + +  LLVM_DEBUG(dbgs() << "********** PROCESS IMPLICIT DEFS **********\n" +                    << "********** Function: " << MF.getName() << '\n'); + +  bool Changed = false; + +  TII = MF.getSubtarget().getInstrInfo(); +  TRI = MF.getSubtarget().getRegisterInfo(); +  MRI = &MF.getRegInfo(); +  assert(MRI->isSSA() && "ProcessImplicitDefs only works on SSA form."); +  assert(WorkList.empty() && "Inconsistent worklist state"); + +  for (MachineFunction::iterator MFI = MF.begin(), MFE = MF.end(); +       MFI != MFE; ++MFI) { +    // Scan the basic block for implicit defs. +    for (MachineBasicBlock::instr_iterator MBBI = MFI->instr_begin(), +         MBBE = MFI->instr_end(); MBBI != MBBE; ++MBBI) +      if (MBBI->isImplicitDef()) +        WorkList.insert(&*MBBI); + +    if (WorkList.empty()) +      continue; + +    LLVM_DEBUG(dbgs() << printMBBReference(*MFI) << " has " << WorkList.size() +                      << " implicit defs.\n"); +    Changed = true; + +    // Drain the WorkList to recursively process any new implicit defs. +    do processImplicitDef(WorkList.pop_back_val()); +    while (!WorkList.empty()); +  } +  return Changed; +} | 
