mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-09 11:25:55 +00:00
Memory Dependence Analysis (not mem-dep test) take advantage of "invariant.load" metadata.
The "invariant.load" metadata indicates the memory unit being accessed is immutable. A load annotated with this metadata can be moved across any store. As I am not sure if it is legal to move such loads across barrier/fence, this change dose not allow such transformation. rdar://11311484 Thank Arnold for code review. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176562 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -391,14 +391,17 @@ namespace llvm {
|
|||||||
/// getPointerDependencyFrom - Return the instruction on which a memory
|
/// getPointerDependencyFrom - Return the instruction on which a memory
|
||||||
/// location depends. If isLoad is true, this routine ignores may-aliases
|
/// location depends. If isLoad is true, this routine ignores may-aliases
|
||||||
/// with read-only operations. If isLoad is false, this routine ignores
|
/// with read-only operations. If isLoad is false, this routine ignores
|
||||||
/// may-aliases with reads from read-only locations.
|
/// may-aliases with reads from read-only locations. If possible, pass
|
||||||
|
/// the query instruction as well; this function may take advantage of
|
||||||
|
/// the metadata annotated to the query instruction to refine the result.
|
||||||
///
|
///
|
||||||
/// Note that this is an uncached query, and thus may be inefficient.
|
/// Note that this is an uncached query, and thus may be inefficient.
|
||||||
///
|
///
|
||||||
MemDepResult getPointerDependencyFrom(const AliasAnalysis::Location &Loc,
|
MemDepResult getPointerDependencyFrom(const AliasAnalysis::Location &Loc,
|
||||||
bool isLoad,
|
bool isLoad,
|
||||||
BasicBlock::iterator ScanIt,
|
BasicBlock::iterator ScanIt,
|
||||||
BasicBlock *BB);
|
BasicBlock *BB,
|
||||||
|
Instruction *QueryInst = 0);
|
||||||
|
|
||||||
|
|
||||||
/// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that
|
/// getLoadLoadClobberFullWidthSize - This is a little bit of analysis that
|
||||||
|
@@ -46,7 +46,8 @@ public:
|
|||||||
MD_prof = 2, // "prof"
|
MD_prof = 2, // "prof"
|
||||||
MD_fpmath = 3, // "fpmath"
|
MD_fpmath = 3, // "fpmath"
|
||||||
MD_range = 4, // "range"
|
MD_range = 4, // "range"
|
||||||
MD_tbaa_struct = 5 // "tbaa.struct"
|
MD_tbaa_struct = 5, // "tbaa.struct"
|
||||||
|
MD_invariant_load = 6 // "invariant.load"
|
||||||
};
|
};
|
||||||
|
|
||||||
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
|
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
|
||||||
|
@@ -351,15 +351,23 @@ getLoadLoadClobberFullWidthSize(const Value *MemLocBase, int64_t MemLocOffs,
|
|||||||
/// getPointerDependencyFrom - Return the instruction on which a memory
|
/// getPointerDependencyFrom - Return the instruction on which a memory
|
||||||
/// location depends. If isLoad is true, this routine ignores may-aliases with
|
/// location depends. If isLoad is true, this routine ignores may-aliases with
|
||||||
/// read-only operations. If isLoad is false, this routine ignores may-aliases
|
/// read-only operations. If isLoad is false, this routine ignores may-aliases
|
||||||
/// with reads from read-only locations.
|
/// with reads from read-only locations. If possible, pass the query
|
||||||
|
/// instruction as well; this function may take advantage of the metadata
|
||||||
|
/// annotated to the query instruction to refine the result.
|
||||||
MemDepResult MemoryDependenceAnalysis::
|
MemDepResult MemoryDependenceAnalysis::
|
||||||
getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad,
|
getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad,
|
||||||
BasicBlock::iterator ScanIt, BasicBlock *BB) {
|
BasicBlock::iterator ScanIt, BasicBlock *BB,
|
||||||
|
Instruction *QueryInst) {
|
||||||
|
|
||||||
const Value *MemLocBase = 0;
|
const Value *MemLocBase = 0;
|
||||||
int64_t MemLocOffset = 0;
|
int64_t MemLocOffset = 0;
|
||||||
|
|
||||||
unsigned Limit = BlockScanLimit;
|
unsigned Limit = BlockScanLimit;
|
||||||
|
bool isInvariantLoad = false;
|
||||||
|
if (isLoad && QueryInst) {
|
||||||
|
LoadInst *LI = dyn_cast<LoadInst>(QueryInst);
|
||||||
|
if (LI && LI->getMetadata(LLVMContext::MD_invariant_load) != 0)
|
||||||
|
isInvariantLoad = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Walk backwards through the basic block, looking for dependencies.
|
// Walk backwards through the basic block, looking for dependencies.
|
||||||
while (ScanIt != BB->begin()) {
|
while (ScanIt != BB->begin()) {
|
||||||
@@ -474,6 +482,8 @@ getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad,
|
|||||||
continue;
|
continue;
|
||||||
if (R == AliasAnalysis::MustAlias)
|
if (R == AliasAnalysis::MustAlias)
|
||||||
return MemDepResult::getDef(Inst);
|
return MemDepResult::getDef(Inst);
|
||||||
|
if (isInvariantLoad)
|
||||||
|
continue;
|
||||||
return MemDepResult::getClobber(Inst);
|
return MemDepResult::getClobber(Inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,7 +581,7 @@ MemDepResult MemoryDependenceAnalysis::getDependency(Instruction *QueryInst) {
|
|||||||
isLoad |= II->getIntrinsicID() == Intrinsic::lifetime_start;
|
isLoad |= II->getIntrinsicID() == Intrinsic::lifetime_start;
|
||||||
|
|
||||||
LocalCache = getPointerDependencyFrom(MemLoc, isLoad, ScanPos,
|
LocalCache = getPointerDependencyFrom(MemLoc, isLoad, ScanPos,
|
||||||
QueryParent);
|
QueryParent, QueryInst);
|
||||||
} else if (isa<CallInst>(QueryInst) || isa<InvokeInst>(QueryInst)) {
|
} else if (isa<CallInst>(QueryInst) || isa<InvokeInst>(QueryInst)) {
|
||||||
CallSite QueryCS(QueryInst);
|
CallSite QueryCS(QueryInst);
|
||||||
bool isReadOnly = AA->onlyReadsMemory(QueryCS);
|
bool isReadOnly = AA->onlyReadsMemory(QueryCS);
|
||||||
|
@@ -58,6 +58,11 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
|
|||||||
unsigned TBAAStructID = getMDKindID("tbaa.struct");
|
unsigned TBAAStructID = getMDKindID("tbaa.struct");
|
||||||
assert(TBAAStructID == MD_tbaa_struct && "tbaa.struct kind id drifted");
|
assert(TBAAStructID == MD_tbaa_struct && "tbaa.struct kind id drifted");
|
||||||
(void)TBAAStructID;
|
(void)TBAAStructID;
|
||||||
|
|
||||||
|
// Create the 'invariant.load' metadata kind.
|
||||||
|
unsigned InvariantLdId = getMDKindID("invariant.load");
|
||||||
|
assert(InvariantLdId == MD_invariant_load && "invariant.load kind id drifted");
|
||||||
|
(void)InvariantLdId;
|
||||||
}
|
}
|
||||||
LLVMContext::~LLVMContext() { delete pImpl; }
|
LLVMContext::~LLVMContext() { delete pImpl; }
|
||||||
|
|
||||||
|
29
test/Analysis/BasicAA/invariant_load.ll
Normal file
29
test/Analysis/BasicAA/invariant_load.ll
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
; RUN: opt < %s -basicaa -gvn -S | FileCheck %s
|
||||||
|
|
||||||
|
; The input *.ll is obtained by manually annotating "invariant.load" to the
|
||||||
|
; two loads. With "invariant.load" metadata, the second load is redundant.
|
||||||
|
;
|
||||||
|
; int foo(int *p, char *q) {
|
||||||
|
; *q = (char)*p;
|
||||||
|
; return *p + 1;
|
||||||
|
; }
|
||||||
|
|
||||||
|
define i32 @foo(i32* nocapture %p, i8* nocapture %q) {
|
||||||
|
entry:
|
||||||
|
%0 = load i32* %p, align 4, !tbaa !0, !invariant.load !3
|
||||||
|
%conv = trunc i32 %0 to i8
|
||||||
|
store i8 %conv, i8* %q, align 1, !tbaa !1
|
||||||
|
%1 = load i32* %p, align 4, !tbaa !0, !invariant.load !3
|
||||||
|
%add = add nsw i32 %1, 1
|
||||||
|
ret i32 %add
|
||||||
|
|
||||||
|
; CHECK: foo
|
||||||
|
; CHECK: %0 = load i32* %p
|
||||||
|
; CHECK: store i8 %conv, i8* %q,
|
||||||
|
; CHECK: %add = add nsw i32 %0, 1
|
||||||
|
}
|
||||||
|
|
||||||
|
!0 = metadata !{metadata !"int", metadata !1}
|
||||||
|
!1 = metadata !{metadata !"omnipotent char", metadata !2}
|
||||||
|
!2 = metadata !{metadata !"Simple C/C++ TBAA"}
|
||||||
|
!3 = metadata !{}
|
Reference in New Issue
Block a user