diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/ProcessImplicitDefs.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/ProcessImplicitDefs.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/ProcessImplicitDefs.cpp b/contrib/llvm-project/llvm/lib/CodeGen/ProcessImplicitDefs.cpp new file mode 100644 index 000000000000..7e46dd35ce47 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/CodeGen/ProcessImplicitDefs.cpp @@ -0,0 +1,168 @@ +//===---------------------- 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/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.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; + + MachineFunctionProperties getRequiredProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::IsSSA); + } +}; +} // 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 (Reg.isVirtual()) { + // 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 (!UserReg.isPhysical() || !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(WorkList.empty() && "Inconsistent worklist state"); + + for (MachineBasicBlock &MBB : MF) { + // Scan the basic block for implicit defs. + for (MachineInstr &MI : MBB) + if (MI.isImplicitDef()) + WorkList.insert(&MI); + + if (WorkList.empty()) + continue; + + LLVM_DEBUG(dbgs() << printMBBReference(MBB) << " 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; +} |