mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-27 05:32:22 +00:00
Imporove load to store => memcpy
Summary: This now try to reorder instructions in order to help create the optimizable pattern. Reviewers: craig.topper, spatel, dexonsmith, Prazek, chandlerc, joker.eph, majnemer Differential Revision: http://reviews.llvm.org/D16523 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263503 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c02ad86a05
commit
b4891447ce
@ -13,6 +13,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/Transforms/Scalar.h"
|
#include "llvm/Transforms/Scalar.h"
|
||||||
|
#include "llvm/ADT/DenseSet.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/Analysis/AliasAnalysis.h"
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
@ -493,6 +494,92 @@ static unsigned findCommonAlignment(const DataLayout &DL, const StoreInst *SI,
|
|||||||
return std::min(StoreAlign, LoadAlign);
|
return std::min(StoreAlign, LoadAlign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method try to lift a store instruction before position P.
|
||||||
|
// It will lift the store and its argument + that anything that
|
||||||
|
// lay alias with these.
|
||||||
|
// The method returns true if it was successful.
|
||||||
|
static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P) {
|
||||||
|
// If the store alias this position, early bail out.
|
||||||
|
MemoryLocation StoreLoc = MemoryLocation::get(SI);
|
||||||
|
if (AA.getModRefInfo(P, StoreLoc) != MRI_NoModRef)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Keep track of the arguments of all instruction we plan to lift
|
||||||
|
// so we can make sure to lift them as well if apropriate.
|
||||||
|
DenseSet<Instruction*> Args;
|
||||||
|
if (auto *Ptr = dyn_cast<Instruction>(SI->getPointerOperand()))
|
||||||
|
if (Ptr->getParent() == SI->getParent())
|
||||||
|
Args.insert(Ptr);
|
||||||
|
|
||||||
|
// Instruction to lift before P.
|
||||||
|
SmallVector<Instruction*, 8> ToLift;
|
||||||
|
|
||||||
|
// Memory locations of lifted instructions.
|
||||||
|
SmallVector<MemoryLocation, 8> MemLocs;
|
||||||
|
MemLocs.push_back(StoreLoc);
|
||||||
|
|
||||||
|
// Lifted callsites.
|
||||||
|
SmallVector<ImmutableCallSite, 8> CallSites;
|
||||||
|
|
||||||
|
for (auto I = --SI->getIterator(), E = P->getIterator(); I != E; --I) {
|
||||||
|
auto *C = &*I;
|
||||||
|
|
||||||
|
bool MayAlias = AA.getModRefInfo(C) != MRI_NoModRef;
|
||||||
|
|
||||||
|
bool NeedLift = false;
|
||||||
|
if (Args.erase(C))
|
||||||
|
NeedLift = true;
|
||||||
|
else if (MayAlias) {
|
||||||
|
NeedLift = std::any_of(MemLocs.begin(), MemLocs.end(),
|
||||||
|
[C, &AA](const MemoryLocation &ML) {
|
||||||
|
return AA.getModRefInfo(C, ML);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!NeedLift)
|
||||||
|
NeedLift = std::any_of(CallSites.begin(), CallSites.end(),
|
||||||
|
[C, &AA](const ImmutableCallSite &CS) {
|
||||||
|
return AA.getModRefInfo(C, CS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NeedLift)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (MayAlias) {
|
||||||
|
if (auto CS = ImmutableCallSite(C)) {
|
||||||
|
// If we can't lift this before P, it's game over.
|
||||||
|
if (AA.getModRefInfo(P, CS) != MRI_NoModRef)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CallSites.push_back(CS);
|
||||||
|
} else if (isa<LoadInst>(C) || isa<StoreInst>(C) || isa<VAArgInst>(C)) {
|
||||||
|
// If we can't lift this before P, it's game over.
|
||||||
|
auto ML = MemoryLocation::get(C);
|
||||||
|
if (AA.getModRefInfo(P, ML) != MRI_NoModRef)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MemLocs.push_back(ML);
|
||||||
|
} else
|
||||||
|
// We don't know how to lift this instruction.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToLift.push_back(C);
|
||||||
|
for (unsigned k = 0, e = C->getNumOperands(); k != e; ++k)
|
||||||
|
if (auto *A = dyn_cast<Instruction>(C->getOperand(k)))
|
||||||
|
if (A->getParent() == SI->getParent())
|
||||||
|
Args.insert(A);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We made it, we need to lift
|
||||||
|
for (auto *I : reverse(ToLift)) {
|
||||||
|
DEBUG(dbgs() << "Lifting " << *I << " before " << *P << "\n");
|
||||||
|
I->moveBefore(P);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) {
|
bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) {
|
||||||
if (!SI->isSimple()) return false;
|
if (!SI->isSimple()) return false;
|
||||||
|
|
||||||
@ -522,26 +609,20 @@ bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) {
|
|||||||
// such an instruction is found, we try to promote there instead
|
// such an instruction is found, we try to promote there instead
|
||||||
// of at the store position.
|
// of at the store position.
|
||||||
Instruction *P = SI;
|
Instruction *P = SI;
|
||||||
for (BasicBlock::iterator I = ++LI->getIterator(), E = SI->getIterator();
|
for (auto &I : make_range(++LI->getIterator(), SI->getIterator())) {
|
||||||
I != E; ++I) {
|
if (AA.getModRefInfo(&I, LoadLoc) & MRI_Mod) {
|
||||||
if (!(AA.getModRefInfo(&*I, LoadLoc) & MRI_Mod))
|
P = &I;
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
// We found an instruction that may write to the loaded memory.
|
|
||||||
// We can try to promote at this position instead of the store
|
|
||||||
// position if nothing alias the store memory after this and the store
|
|
||||||
// destination is not in the range.
|
|
||||||
P = &*I;
|
|
||||||
for (; I != E; ++I) {
|
|
||||||
MemoryLocation StoreLoc = MemoryLocation::get(SI);
|
|
||||||
if (&*I == SI->getOperand(1) ||
|
|
||||||
AA.getModRefInfo(&*I, StoreLoc) != MRI_NoModRef) {
|
|
||||||
P = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
// We found an instruction that may write to the loaded memory.
|
||||||
|
// We can try to promote at this position instead of the store
|
||||||
|
// position if nothing alias the store memory after this and the store
|
||||||
|
// destination is not in the range.
|
||||||
|
if (P && P != SI) {
|
||||||
|
if (!moveUp(AA, SI, P))
|
||||||
|
P = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a valid insertion position is found, then we can promote
|
// If a valid insertion position is found, then we can promote
|
||||||
|
@ -73,16 +73,38 @@ define void @copyalias(%S* %src, %S* %dst) {
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; If the store address is computed ina complex manner, make
|
||||||
; The GEP is present after the aliasing store, preventing to move the memcpy before
|
; sure we lift the computation as well if needed and possible.
|
||||||
; (without further analysis/transformation)
|
define void @addrproducer(%S* %src, %S* %dst) {
|
||||||
define void @copyaliaswithproducerinbetween(%S* %src, %S* %dst) {
|
; CHECK-LABEL: addrproducer
|
||||||
; CHECK-LABEL: copyalias
|
; CHECK: %dst2 = getelementptr %S, %S* %dst, i64 1
|
||||||
; CHECK-NEXT: [[LOAD:%[a-z0-9\.]+]] = load %S, %S* %src
|
; CHECK: call void @llvm.memmove.p0i8.p0i8.i64
|
||||||
; CHECK-NOT: call
|
; CHECK-NEXT: store %S undef, %S* %dst
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
%1 = load %S, %S* %src
|
%1 = load %S, %S* %src
|
||||||
store %S undef, %S* %dst
|
store %S undef, %S* %dst
|
||||||
%dst2 = getelementptr %S , %S* %dst, i64 1
|
%dst2 = getelementptr %S , %S* %dst, i64 1
|
||||||
store %S %1, %S* %dst2
|
store %S %1, %S* %dst2
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @aliasaddrproducer(%S* %src, %S* %dst, i32* %dstidptr) {
|
||||||
|
; CHECK-LABEL: aliasaddrproducer
|
||||||
|
%1 = load %S, %S* %src
|
||||||
|
store %S undef, %S* %dst
|
||||||
|
%dstindex = load i32, i32* %dstidptr
|
||||||
|
%dst2 = getelementptr %S , %S* %dst, i32 %dstindex
|
||||||
|
store %S %1, %S* %dst2
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @noaliasaddrproducer(%S* %src, %S* noalias %dst, i32* noalias %dstidptr) {
|
||||||
|
; CHECK-LABEL: noaliasaddrproducer
|
||||||
|
%1 = load %S, %S* %src
|
||||||
|
store %S undef, %S* %src
|
||||||
|
%2 = load i32, i32* %dstidptr
|
||||||
|
%dstindex = or i32 %2, 1
|
||||||
|
%dst2 = getelementptr %S , %S* %dst, i32 %dstindex
|
||||||
|
store %S %1, %S* %dst2
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user