llvm-6502/lib/CodeGen/MachineCopyPropagation.cpp
Evan Cheng 977679d603 Added a late machine instruction copy propagation pass. This catches
opportunities that only present themselves after late optimizations
such as tail duplication .e.g.
## BB#1:
        movl    %eax, %ecx
        movl    %ecx, %eax
        ret

The register allocator also leaves some of them around (due to false
dep between copies from phi-elimination, etc.)

This required some changes in codegen passes. Post-ra scheduler and the
pseudo-instruction expansion passes have been moved after branch folding
and tail merging. They were before branch folding before because it did
not always update block livein's. That's fixed now. The pass change makes
independently since we want to properly schedule instructions after
branch folding / tail duplication.

rdar://10428165
rdar://10640363



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@147716 91177308-0d34-0410-b5e6-96231b3b80d8
2012-01-07 03:02:36 +00:00

241 lines
8.0 KiB
C++

//===- MachineCopyPropagation.cpp - Machine Copy Propagation Pass ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is an extremely simple MachineInstr-level copy propagation pass.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "codegen-cp"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;
STATISTIC(NumDeletes, "Number of dead copies deleted");
namespace {
class MachineCopyPropagation : public MachineFunctionPass {
const TargetRegisterInfo *TRI;
BitVector ReservedRegs;
public:
static char ID; // Pass identification, replacement for typeid
MachineCopyPropagation() : MachineFunctionPass(ID) {
initializeMachineCopyPropagationPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnMachineFunction(MachineFunction &MF);
private:
void SourceNoLongerAvailable(unsigned Reg,
DenseMap<unsigned, unsigned> &SrcMap,
DenseMap<unsigned, MachineInstr*> &AvailCopyMap);
bool CopyPropagateBlock(MachineBasicBlock &MBB);
};
}
char MachineCopyPropagation::ID = 0;
INITIALIZE_PASS(MachineCopyPropagation, "machine-cp",
"Machine Copy Propagation Pass", false, false)
FunctionPass *llvm::createMachineCopyPropagationPass() {
return new MachineCopyPropagation();
}
void
MachineCopyPropagation::SourceNoLongerAvailable(unsigned Reg,
DenseMap<unsigned, unsigned> &SrcMap,
DenseMap<unsigned, MachineInstr*> &AvailCopyMap) {
DenseMap<unsigned, unsigned>::iterator SI = SrcMap.find(Reg);
if (SI != SrcMap.end()) {
unsigned MappedDef = SI->second;
// Source of copy is no longer available for propagation.
if (AvailCopyMap.erase(MappedDef)) {
for (const unsigned *SR = TRI->getSubRegisters(MappedDef); *SR; ++SR)
AvailCopyMap.erase(*SR);
}
}
for (const unsigned *AS = TRI->getAliasSet(Reg); *AS; ++AS) {
SI = SrcMap.find(*AS);
if (SI != SrcMap.end()) {
unsigned MappedDef = SI->second;
if (AvailCopyMap.erase(MappedDef)) {
for (const unsigned *SR = TRI->getSubRegisters(MappedDef); *SR; ++SR)
AvailCopyMap.erase(*SR);
}
}
}
}
bool MachineCopyPropagation::CopyPropagateBlock(MachineBasicBlock &MBB) {
SmallSetVector<MachineInstr*, 8> MaybeDeadCopies; // Candidates for deletion
DenseMap<unsigned, MachineInstr*> AvailCopyMap; // Def -> available copies map
DenseMap<unsigned, MachineInstr*> CopyMap; // Def -> copies map
DenseMap<unsigned, unsigned> SrcMap; // Src -> Def map
bool Changed = false;
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ) {
MachineInstr *MI = &*I;
++I;
if (MI->isCopy()) {
unsigned Def = MI->getOperand(0).getReg();
unsigned Src = MI->getOperand(1).getReg();
if (TargetRegisterInfo::isVirtualRegister(Def) ||
TargetRegisterInfo::isVirtualRegister(Src))
report_fatal_error("MachineCopyPropagation should be run after"
" register allocation!");
DenseMap<unsigned, MachineInstr*>::iterator CI = AvailCopyMap.find(Src);
if (CI != AvailCopyMap.end()) {
MachineInstr *CopyMI = CI->second;
unsigned SrcSrc = CopyMI->getOperand(1).getReg();
if (!ReservedRegs.test(Def) &&
(SrcSrc == Def || TRI->isSubRegister(SrcSrc, Def))) {
// The two copies cancel out and the source of the first copy
// hasn't been overridden, eliminate the second one. e.g.
// %ECX<def> = COPY %EAX<kill>
// ... nothing clobbered EAX.
// %EAX<def> = COPY %ECX
// =>
// %ECX<def> = COPY %EAX
CopyMI->getOperand(1).setIsKill(false);
MI->eraseFromParent();
Changed = true;
++NumDeletes;
continue;
}
}
// If Src is defined by a previous copy, it cannot be eliminated.
CI = CopyMap.find(Src);
if (CI != CopyMap.end())
MaybeDeadCopies.remove(CI->second);
for (const unsigned *AS = TRI->getAliasSet(Src); *AS; ++AS) {
CI = CopyMap.find(*AS);
if (CI != CopyMap.end())
MaybeDeadCopies.remove(CI->second);
}
// Copy is now a candidate for deletion.
MaybeDeadCopies.insert(MI);
// If 'Src' is previously source of another copy, then this earlier copy's
// source is no longer available. e.g.
// %xmm9<def> = copy %xmm2
// ...
// %xmm2<def> = copy %xmm0
// ...
// %xmm2<def> = copy %xmm9
SourceNoLongerAvailable(Def, SrcMap, AvailCopyMap);
// Remember Def is defined by the copy.
CopyMap[Def] = MI;
AvailCopyMap[Def] = MI;
for (const unsigned *SR = TRI->getSubRegisters(Def); *SR; ++SR) {
CopyMap[*SR] = MI;
AvailCopyMap[*SR] = MI;
}
// Remember source that's copied to Def. Once it's clobbered, then
// it's no longer available for copy propagation.
SrcMap[Src] = Def;
continue;
}
// Not a copy.
SmallVector<unsigned, 2> Defs;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
unsigned Reg = MO.getReg();
if (!Reg)
continue;
if (TargetRegisterInfo::isVirtualRegister(Reg))
report_fatal_error("MachineCopyPropagation should be run after"
" register allocation!");
if (MO.isDef()) {
Defs.push_back(Reg);
continue;
}
// If 'Reg' is defined by a copy, the copy is no longer a candidate
// for elimination.
DenseMap<unsigned, MachineInstr*>::iterator CI = CopyMap.find(Reg);
if (CI != CopyMap.end())
MaybeDeadCopies.remove(CI->second);
for (const unsigned *AS = TRI->getAliasSet(Reg); *AS; ++AS) {
CI = CopyMap.find(*AS);
if (CI != CopyMap.end())
MaybeDeadCopies.remove(CI->second);
}
}
for (unsigned i = 0, e = Defs.size(); i != e; ++i) {
unsigned Reg = Defs[i];
// No longer defined by a copy.
CopyMap.erase(Reg);
AvailCopyMap.erase(Reg);
for (const unsigned *AS = TRI->getAliasSet(Reg); *AS; ++AS) {
CopyMap.erase(*AS);
AvailCopyMap.erase(*AS);
}
// If 'Reg' is previously source of a copy, it is no longer available for
// copy propagation.
SourceNoLongerAvailable(Reg, SrcMap, AvailCopyMap);
}
}
// If MBB doesn't have successors, delete the copies whose defs are not used.
// If MBB does have successors, then conservative assume the defs are live-out
// since we don't want to trust live-in lists.
if (MBB.succ_empty()) {
for (SmallSetVector<MachineInstr*, 8>::iterator
DI = MaybeDeadCopies.begin(), DE = MaybeDeadCopies.end();
DI != DE; ++DI) {
if (!ReservedRegs.test((*DI)->getOperand(0).getReg())) {
(*DI)->eraseFromParent();
Changed = true;
++NumDeletes;
}
}
}
return Changed;
}
bool MachineCopyPropagation::runOnMachineFunction(MachineFunction &MF) {
bool Changed = false;
TRI = MF.getTarget().getRegisterInfo();
ReservedRegs = TRI->getReservedRegs(MF);
for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
Changed |= CopyPropagateBlock(*I);
return Changed;
}