mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-15 05:24:01 +00:00
Teach machine cse to eliminate instructions with multiple physreg uses and defs. rdar://8610857.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117745 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -22,6 +22,7 @@
|
|||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/ScopedHashTable.h"
|
#include "llvm/ADT/ScopedHashTable.h"
|
||||||
|
#include "llvm/ADT/SmallSet.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
@ -30,7 +31,8 @@ using namespace llvm;
|
|||||||
|
|
||||||
STATISTIC(NumCoalesces, "Number of copies coalesced");
|
STATISTIC(NumCoalesces, "Number of copies coalesced");
|
||||||
STATISTIC(NumCSEs, "Number of common subexpression eliminated");
|
STATISTIC(NumCSEs, "Number of common subexpression eliminated");
|
||||||
STATISTIC(NumPhysCSEs, "Number of phyreg defining common subexpr eliminated");
|
STATISTIC(NumPhysCSEs,
|
||||||
|
"Number of physreg referencing common subexpr eliminated");
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class MachineCSE : public MachineFunctionPass {
|
class MachineCSE : public MachineFunctionPass {
|
||||||
@ -74,11 +76,11 @@ namespace {
|
|||||||
bool isPhysDefTriviallyDead(unsigned Reg,
|
bool isPhysDefTriviallyDead(unsigned Reg,
|
||||||
MachineBasicBlock::const_iterator I,
|
MachineBasicBlock::const_iterator I,
|
||||||
MachineBasicBlock::const_iterator E) const ;
|
MachineBasicBlock::const_iterator E) const ;
|
||||||
bool hasLivePhysRegDefUse(const MachineInstr *MI,
|
bool hasLivePhysRegDefUses(const MachineInstr *MI,
|
||||||
const MachineBasicBlock *MBB,
|
const MachineBasicBlock *MBB,
|
||||||
unsigned &PhysDef) const;
|
SmallSet<unsigned,8> &PhysRefs) const;
|
||||||
bool PhysRegDefReaches(MachineInstr *CSMI, MachineInstr *MI,
|
bool PhysRegDefsReach(MachineInstr *CSMI, MachineInstr *MI,
|
||||||
unsigned PhysDef) const;
|
SmallSet<unsigned,8> &PhysRefs) const;
|
||||||
bool isCSECandidate(MachineInstr *MI);
|
bool isCSECandidate(MachineInstr *MI);
|
||||||
bool isProfitableToCSE(unsigned CSReg, unsigned Reg,
|
bool isProfitableToCSE(unsigned CSReg, unsigned Reg,
|
||||||
MachineInstr *CSMI, MachineInstr *MI);
|
MachineInstr *CSMI, MachineInstr *MI);
|
||||||
@ -177,14 +179,14 @@ MachineCSE::isPhysDefTriviallyDead(unsigned Reg,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// hasLivePhysRegDefUse - Return true if the specified instruction read / write
|
/// hasLivePhysRegDefUses - Return true if the specified instruction read/write
|
||||||
/// physical registers (except for dead defs of physical registers). It also
|
/// physical registers (except for dead defs of physical registers). It also
|
||||||
/// returns the physical register def by reference if it's the only one and the
|
/// returns the physical register def by reference if it's the only one and the
|
||||||
/// instruction does not uses a physical register.
|
/// instruction does not uses a physical register.
|
||||||
bool MachineCSE::hasLivePhysRegDefUse(const MachineInstr *MI,
|
bool MachineCSE::hasLivePhysRegDefUses(const MachineInstr *MI,
|
||||||
const MachineBasicBlock *MBB,
|
const MachineBasicBlock *MBB,
|
||||||
unsigned &PhysDef) const {
|
SmallSet<unsigned,8> &PhysRefs) const {
|
||||||
PhysDef = 0;
|
MachineBasicBlock::const_iterator I = MI; I = llvm::next(I);
|
||||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||||
const MachineOperand &MO = MI->getOperand(i);
|
const MachineOperand &MO = MI->getOperand(i);
|
||||||
if (!MO.isReg())
|
if (!MO.isReg())
|
||||||
@ -194,35 +196,22 @@ bool MachineCSE::hasLivePhysRegDefUse(const MachineInstr *MI,
|
|||||||
continue;
|
continue;
|
||||||
if (TargetRegisterInfo::isVirtualRegister(Reg))
|
if (TargetRegisterInfo::isVirtualRegister(Reg))
|
||||||
continue;
|
continue;
|
||||||
if (MO.isUse()) {
|
// If the def is dead, it's ok. But the def may not marked "dead". That's
|
||||||
// Can't touch anything to read a physical register.
|
|
||||||
PhysDef = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (MO.isDead())
|
|
||||||
// If the def is dead, it's ok.
|
|
||||||
continue;
|
|
||||||
// Ok, this is a physical register def that's not marked "dead". That's
|
|
||||||
// common since this pass is run before livevariables. We can scan
|
// common since this pass is run before livevariables. We can scan
|
||||||
// forward a few instructions and check if it is obviously dead.
|
// forward a few instructions and check if it is obviously dead.
|
||||||
if (PhysDef) {
|
if (MO.isDef() &&
|
||||||
// Multiple physical register defs. These are rare, forget about it.
|
(MO.isDead() || isPhysDefTriviallyDead(Reg, I, MBB->end())))
|
||||||
PhysDef = 0;
|
continue;
|
||||||
return true;
|
PhysRefs.insert(Reg);
|
||||||
}
|
for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias)
|
||||||
PhysDef = Reg;
|
PhysRefs.insert(*Alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PhysDef) {
|
return !PhysRefs.empty();
|
||||||
MachineBasicBlock::const_iterator I = MI; I = llvm::next(I);
|
|
||||||
if (!isPhysDefTriviallyDead(PhysDef, I, MBB->end()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MachineCSE::PhysRegDefReaches(MachineInstr *CSMI, MachineInstr *MI,
|
bool MachineCSE::PhysRegDefsReach(MachineInstr *CSMI, MachineInstr *MI,
|
||||||
unsigned PhysDef) const {
|
SmallSet<unsigned,8> &PhysRefs) const {
|
||||||
// For now conservatively returns false if the common subexpression is
|
// For now conservatively returns false if the common subexpression is
|
||||||
// not in the same basic block as the given instruction.
|
// not in the same basic block as the given instruction.
|
||||||
MachineBasicBlock *MBB = MI->getParent();
|
MachineBasicBlock *MBB = MI->getParent();
|
||||||
@ -238,8 +227,17 @@ bool MachineCSE::PhysRegDefReaches(MachineInstr *CSMI, MachineInstr *MI,
|
|||||||
|
|
||||||
if (I == E)
|
if (I == E)
|
||||||
return true;
|
return true;
|
||||||
if (I->modifiesRegister(PhysDef, TRI))
|
|
||||||
return false;
|
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
|
||||||
|
const MachineOperand &MO = I->getOperand(i);
|
||||||
|
if (!MO.isReg() || !MO.isDef())
|
||||||
|
continue;
|
||||||
|
unsigned MOReg = MO.getReg();
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(MOReg))
|
||||||
|
continue;
|
||||||
|
if (PhysRefs.count(MOReg))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
--LookAheadLeft;
|
--LookAheadLeft;
|
||||||
++I;
|
++I;
|
||||||
@ -360,7 +358,6 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) {
|
|||||||
if (!isCSECandidate(MI))
|
if (!isCSECandidate(MI))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool DefPhys = false;
|
|
||||||
bool FoundCSE = VNT.count(MI);
|
bool FoundCSE = VNT.count(MI);
|
||||||
if (!FoundCSE) {
|
if (!FoundCSE) {
|
||||||
// Look for trivial copy coalescing opportunities.
|
// Look for trivial copy coalescing opportunities.
|
||||||
@ -373,22 +370,20 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) {
|
|||||||
}
|
}
|
||||||
// FIXME: commute commutable instructions?
|
// FIXME: commute commutable instructions?
|
||||||
|
|
||||||
// If the instruction defines a physical register and the value *may* be
|
// If the instruction defines physical registers and the values *may* be
|
||||||
// used, then it's not safe to replace it with a common subexpression.
|
// used, then it's not safe to replace it with a common subexpression.
|
||||||
unsigned PhysDef = 0;
|
// It's also not safe if the instruction uses physical registers.
|
||||||
if (FoundCSE && hasLivePhysRegDefUse(MI, MBB, PhysDef)) {
|
SmallSet<unsigned,8> PhysRefs;
|
||||||
|
if (FoundCSE && hasLivePhysRegDefUses(MI, MBB, PhysRefs)) {
|
||||||
FoundCSE = false;
|
FoundCSE = false;
|
||||||
|
|
||||||
// ... Unless the CS is local and it also defines the physical register
|
// ... Unless the CS is local and it also defines the physical register
|
||||||
// which is not clobbered in between.
|
// which is not clobbered in between and the physical register uses
|
||||||
if (PhysDef) {
|
// were not clobbered.
|
||||||
unsigned CSVN = VNT.lookup(MI);
|
unsigned CSVN = VNT.lookup(MI);
|
||||||
MachineInstr *CSMI = Exps[CSVN];
|
MachineInstr *CSMI = Exps[CSVN];
|
||||||
if (PhysRegDefReaches(CSMI, MI, PhysDef)) {
|
if (PhysRegDefsReach(CSMI, MI, PhysRefs))
|
||||||
FoundCSE = true;
|
FoundCSE = true;
|
||||||
DefPhys = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FoundCSE) {
|
if (!FoundCSE) {
|
||||||
@ -433,7 +428,7 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) {
|
|||||||
}
|
}
|
||||||
MI->eraseFromParent();
|
MI->eraseFromParent();
|
||||||
++NumCSEs;
|
++NumCSEs;
|
||||||
if (DefPhys)
|
if (!PhysRefs.empty())
|
||||||
++NumPhysCSEs;
|
++NumPhysCSEs;
|
||||||
} else {
|
} else {
|
||||||
DEBUG(dbgs() << "*** Not profitable, avoid CSE!\n");
|
DEBUG(dbgs() << "*** Not profitable, avoid CSE!\n");
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
; RUN: llc < %s -march=arm | grep moveq
|
; RUN: llc < %s -march=arm | grep moveq
|
||||||
; RUN: llc < %s -march=arm -mattr=+vfp2 | grep movvs
|
; RUN: llc < %s -mtriple=armv7-apple-darwin -mcpu=cortex-a8 | FileCheck %s
|
||||||
|
|
||||||
define i32 @f7(float %a, float %b) {
|
define i32 @f7(float %a, float %b) {
|
||||||
entry:
|
entry:
|
||||||
|
; CHECK: f7:
|
||||||
|
; CHECK: vcmpe.f32
|
||||||
|
; CHECK: vmrs apsr_nzcv, fpscr
|
||||||
|
; CHECK: movweq
|
||||||
|
; CHECK-NOT: vmrs
|
||||||
|
; CHECK: movwvs
|
||||||
%tmp = fcmp ueq float %a,%b
|
%tmp = fcmp ueq float %a,%b
|
||||||
%retval = select i1 %tmp, i32 666, i32 42
|
%retval = select i1 %tmp, i32 666, i32 42
|
||||||
ret i32 %retval
|
ret i32 %retval
|
||||||
|
Reference in New Issue
Block a user