mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-09-27 16:17:17 +00:00
[mips] Define class MemDefsUses.
This class tracks dependence between memory instructions using underlying objects of memory operands. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176313 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -16,9 +16,13 @@
|
|||||||
#include "Mips.h"
|
#include "Mips.h"
|
||||||
#include "MipsTargetMachine.h"
|
#include "MipsTargetMachine.h"
|
||||||
#include "llvm/ADT/BitVector.h"
|
#include "llvm/ADT/BitVector.h"
|
||||||
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
|
#include "llvm/Analysis/ValueTracking.h"
|
||||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||||
|
#include "llvm/CodeGen/PseudoSourceValue.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
#include "llvm/Target/TargetMachine.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
@@ -61,6 +65,38 @@ namespace {
|
|||||||
BitVector Defs, Uses;
|
BitVector Defs, Uses;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This class maintains memory dependence information.
|
||||||
|
class MemDefsUses {
|
||||||
|
public:
|
||||||
|
MemDefsUses(const MachineFrameInfo *MFI);
|
||||||
|
|
||||||
|
/// Return true if MI cannot be moved to delay slot.
|
||||||
|
bool hasHazard(const MachineInstr &MI);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Update Defs and Uses. Return true if there exist dependences that
|
||||||
|
/// disqualify the delay slot candidate between V and values in Uses and Defs.
|
||||||
|
bool updateDefsUses(const Value *V, bool MayStore);
|
||||||
|
|
||||||
|
/// Get the list of underlying objects of MI's memory operand.
|
||||||
|
bool getUnderlyingObjects(const MachineInstr &MI,
|
||||||
|
SmallVectorImpl<const Value *> &Objects) const;
|
||||||
|
|
||||||
|
const MachineFrameInfo *MFI;
|
||||||
|
SmallPtrSet<const Value*, 4> Uses, Defs;
|
||||||
|
|
||||||
|
/// Flags indicating whether loads or stores have been seen.
|
||||||
|
bool SeenLoad, SeenStore;
|
||||||
|
|
||||||
|
/// Flags indicating whether loads or stores with no underlying objects have
|
||||||
|
/// been seen.
|
||||||
|
bool SeenNoObjLoad, SeenNoObjStore;
|
||||||
|
|
||||||
|
/// Memory instructions are not allowed to move to delay slot if this flag
|
||||||
|
/// is true.
|
||||||
|
bool ForbidMemInstr;
|
||||||
|
};
|
||||||
|
|
||||||
class Filler : public MachineFunctionPass {
|
class Filler : public MachineFunctionPass {
|
||||||
public:
|
public:
|
||||||
Filler(TargetMachine &tm)
|
Filler(TargetMachine &tm)
|
||||||
@@ -88,10 +124,10 @@ namespace {
|
|||||||
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
|
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
|
||||||
|
|
||||||
/// This function checks if it is valid to move Candidate to the delay slot
|
/// This function checks if it is valid to move Candidate to the delay slot
|
||||||
/// and returns true if it isn't. It also updates load and store flags and
|
/// and returns true if it isn't. It also updates memory and register
|
||||||
/// register defs and uses.
|
/// dependence information.
|
||||||
bool delayHasHazard(const MachineInstr &Candidate, bool &SawLoad,
|
bool delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU,
|
||||||
bool &SawStore, RegDefsUses &RegDU) const;
|
MemDefsUses &MemDU) const;
|
||||||
|
|
||||||
bool findDelayInstr(MachineBasicBlock &MBB, Iter slot, Iter &Filler) const;
|
bool findDelayInstr(MachineBasicBlock &MBB, Iter slot, Iter &Filler) const;
|
||||||
|
|
||||||
@@ -164,6 +200,84 @@ bool RegDefsUses::isRegInSet(const BitVector &RegSet, unsigned Reg) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemDefsUses::MemDefsUses(const MachineFrameInfo *MFI_)
|
||||||
|
: MFI(MFI_), SeenLoad(false), SeenStore(false), SeenNoObjLoad(false),
|
||||||
|
SeenNoObjStore(false), ForbidMemInstr(false) {}
|
||||||
|
|
||||||
|
bool MemDefsUses::hasHazard(const MachineInstr &MI) {
|
||||||
|
if (!MI.mayStore() && !MI.mayLoad())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ForbidMemInstr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool OrigSeenLoad = SeenLoad, OrigSeenStore = SeenStore;
|
||||||
|
|
||||||
|
SeenLoad |= MI.mayLoad();
|
||||||
|
SeenStore |= MI.mayStore();
|
||||||
|
|
||||||
|
// If MI is an ordered or volatile memory reference, disallow moving
|
||||||
|
// subsequent loads and stores to delay slot.
|
||||||
|
if (MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) {
|
||||||
|
ForbidMemInstr = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasHazard = false;
|
||||||
|
SmallVector<const Value *, 4> Objs;
|
||||||
|
|
||||||
|
// Check underlying object list.
|
||||||
|
if (getUnderlyingObjects(MI, Objs)) {
|
||||||
|
for (SmallVector<const Value *, 4>::const_iterator I = Objs.begin();
|
||||||
|
I != Objs.end(); ++I)
|
||||||
|
HasHazard |= updateDefsUses(*I, MI.mayStore());
|
||||||
|
|
||||||
|
return HasHazard;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No underlying objects found.
|
||||||
|
HasHazard = MI.mayStore() && (OrigSeenLoad || OrigSeenStore);
|
||||||
|
HasHazard |= MI.mayLoad() || OrigSeenStore;
|
||||||
|
|
||||||
|
SeenNoObjLoad |= MI.mayLoad();
|
||||||
|
SeenNoObjStore |= MI.mayStore();
|
||||||
|
|
||||||
|
return HasHazard;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemDefsUses::updateDefsUses(const Value *V, bool MayStore) {
|
||||||
|
if (MayStore)
|
||||||
|
return !Defs.insert(V) || Uses.count(V) || SeenNoObjStore || SeenNoObjLoad;
|
||||||
|
|
||||||
|
Uses.insert(V);
|
||||||
|
return Defs.count(V) || SeenNoObjStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemDefsUses::
|
||||||
|
getUnderlyingObjects(const MachineInstr &MI,
|
||||||
|
SmallVectorImpl<const Value *> &Objects) const {
|
||||||
|
if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getValue())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Value *V = (*MI.memoperands_begin())->getValue();
|
||||||
|
|
||||||
|
SmallVector<Value *, 4> Objs;
|
||||||
|
GetUnderlyingObjects(const_cast<Value *>(V), Objs);
|
||||||
|
|
||||||
|
for (SmallVector<Value*, 4>::iterator I = Objs.begin(), E = Objs.end();
|
||||||
|
I != E; ++I) {
|
||||||
|
if (const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(*I)) {
|
||||||
|
if (PSV->isAliased(MFI))
|
||||||
|
return false;
|
||||||
|
} else if (!isIdentifiedObject(V))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Objects.push_back(*I);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
|
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
|
||||||
/// We assume there is only one delay slot per delayed instruction.
|
/// We assume there is only one delay slot per delayed instruction.
|
||||||
bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
||||||
@@ -201,12 +315,10 @@ FunctionPass *llvm::createMipsDelaySlotFillerPass(MipsTargetMachine &tm) {
|
|||||||
bool Filler::findDelayInstr(MachineBasicBlock &MBB, Iter Slot,
|
bool Filler::findDelayInstr(MachineBasicBlock &MBB, Iter Slot,
|
||||||
Iter &Filler) const {
|
Iter &Filler) const {
|
||||||
RegDefsUses RegDU(TM);
|
RegDefsUses RegDU(TM);
|
||||||
|
MemDefsUses MemDU(MBB.getParent()->getFrameInfo());
|
||||||
|
|
||||||
RegDU.init(*Slot);
|
RegDU.init(*Slot);
|
||||||
|
|
||||||
bool SawLoad = false;
|
|
||||||
bool SawStore = false;
|
|
||||||
|
|
||||||
for (ReverseIter I(Slot); I != MBB.rend(); ++I) {
|
for (ReverseIter I(Slot); I != MBB.rend(); ++I) {
|
||||||
// skip debug value
|
// skip debug value
|
||||||
if (I->isDebugValue())
|
if (I->isDebugValue())
|
||||||
@@ -215,7 +327,10 @@ bool Filler::findDelayInstr(MachineBasicBlock &MBB, Iter Slot,
|
|||||||
if (terminateSearch(*I))
|
if (terminateSearch(*I))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (delayHasHazard(*I, SawLoad, SawStore, RegDU))
|
assert((!I->isCall() && !I->isReturn() && !I->isBranch()) &&
|
||||||
|
"Cannot put calls, returns or branches in delay slot.");
|
||||||
|
|
||||||
|
if (delayHasHazard(*I, RegDU, MemDU))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Filler = llvm::next(I).base();
|
Filler = llvm::next(I).base();
|
||||||
@@ -225,23 +340,11 @@ bool Filler::findDelayInstr(MachineBasicBlock &MBB, Iter Slot,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Filler::delayHasHazard(const MachineInstr &Candidate, bool &SawLoad,
|
bool Filler::delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU,
|
||||||
bool &SawStore, RegDefsUses &RegDU) const {
|
MemDefsUses &MemDU) const {
|
||||||
bool HasHazard = (Candidate.isImplicitDef() || Candidate.isKill());
|
bool HasHazard = (Candidate.isImplicitDef() || Candidate.isKill());
|
||||||
|
|
||||||
// Loads or stores cannot be moved past a store to the delay slot
|
HasHazard |= MemDU.hasHazard(Candidate);
|
||||||
// and stores cannot be moved past a load.
|
|
||||||
if (Candidate.mayStore() || Candidate.hasOrderedMemoryRef()) {
|
|
||||||
HasHazard |= SawStore | SawLoad;
|
|
||||||
SawStore = true;
|
|
||||||
} else if (Candidate.mayLoad()) {
|
|
||||||
HasHazard |= SawStore;
|
|
||||||
SawLoad = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert((!Candidate.isCall() && !Candidate.isReturn()) &&
|
|
||||||
"Cannot put calls or returns in delay slot.");
|
|
||||||
|
|
||||||
HasHazard |= RegDU.update(Candidate, 0, Candidate.getNumOperands());
|
HasHazard |= RegDU.update(Candidate, 0, Candidate.getNumOperands());
|
||||||
|
|
||||||
return HasHazard;
|
return HasHazard;
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
; RUN: llc -march=mipsel -O0 < %s | FileCheck %s -check-prefix=None
|
; RUN: llc -march=mipsel -O0 < %s | FileCheck %s -check-prefix=None
|
||||||
; RUN: llc -march=mipsel < %s | FileCheck %s -check-prefix=Default
|
; RUN: llc -march=mipsel < %s | FileCheck %s -check-prefix=Default
|
||||||
|
; RUN: llc -march=mipsel -O1 -relocation-model=static < %s | \
|
||||||
|
; RUN: FileCheck %s -check-prefix=STATICO1
|
||||||
|
|
||||||
define void @foo1() nounwind {
|
define void @foo1() nounwind {
|
||||||
entry:
|
entry:
|
||||||
@@ -80,3 +82,20 @@ entry:
|
|||||||
|
|
||||||
declare void @foo7(double, float)
|
declare void @foo7(double, float)
|
||||||
|
|
||||||
|
; Check that a store can move past other memory instructions.
|
||||||
|
;
|
||||||
|
; STATICO1: foo8:
|
||||||
|
; STATICO1: jalr ${{[0-9]+}}
|
||||||
|
; STATICO1-NEXT: sw ${{[0-9]+}}, %lo(g1)
|
||||||
|
|
||||||
|
@foo9 = common global void ()* null, align 4
|
||||||
|
|
||||||
|
define i32 @foo8(i32 %a) nounwind {
|
||||||
|
entry:
|
||||||
|
store i32 %a, i32* @g1, align 4
|
||||||
|
%0 = load void ()** @foo9, align 4
|
||||||
|
tail call void %0() nounwind
|
||||||
|
%1 = load i32* @g1, align 4
|
||||||
|
%add = add nsw i32 %1, %a
|
||||||
|
ret i32 %add
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user