mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-12 20:48:17 +00:00
[TRE] Improve code motion in TRE, use AA to tell whether a load can be moved before a call that writes to memory.
Summary: use AA to tell whether a load can be moved before a call that writes to memory. Reviewers: dberlin, davide, sanjoy, hfinkel Reviewed By: hfinkel Subscribers: hfinkel, llvm-commits Differential Revision: https://reviews.llvm.org/D34115 llvm-svn: 305698
This commit is contained in:
parent
7874185006
commit
a3f0081b68
@ -321,7 +321,7 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls) {
|
|||||||
/// instruction from after the call to before the call, assuming that all
|
/// instruction from after the call to before the call, assuming that all
|
||||||
/// instructions between the call and this instruction are movable.
|
/// instructions between the call and this instruction are movable.
|
||||||
///
|
///
|
||||||
static bool canMoveAboveCall(Instruction *I, CallInst *CI) {
|
static bool canMoveAboveCall(Instruction *I, CallInst *CI, AliasAnalysis *AA) {
|
||||||
// FIXME: We can move load/store/call/free instructions above the call if the
|
// FIXME: We can move load/store/call/free instructions above the call if the
|
||||||
// call does not mod/ref the memory location being processed.
|
// call does not mod/ref the memory location being processed.
|
||||||
if (I->mayHaveSideEffects()) // This also handles volatile loads.
|
if (I->mayHaveSideEffects()) // This also handles volatile loads.
|
||||||
@ -332,10 +332,10 @@ static bool canMoveAboveCall(Instruction *I, CallInst *CI) {
|
|||||||
if (CI->mayHaveSideEffects()) {
|
if (CI->mayHaveSideEffects()) {
|
||||||
// Non-volatile loads may be moved above a call with side effects if it
|
// Non-volatile loads may be moved above a call with side effects if it
|
||||||
// does not write to memory and the load provably won't trap.
|
// does not write to memory and the load provably won't trap.
|
||||||
// FIXME: Writes to memory only matter if they may alias the pointer
|
// Writes to memory only matter if they may alias the pointer
|
||||||
// being loaded from.
|
// being loaded from.
|
||||||
const DataLayout &DL = L->getModule()->getDataLayout();
|
const DataLayout &DL = L->getModule()->getDataLayout();
|
||||||
if (CI->mayWriteToMemory() ||
|
if ((AA->getModRefInfo(CI, MemoryLocation::get(L)) & MRI_Mod) ||
|
||||||
!isSafeToLoadUnconditionally(L->getPointerOperand(),
|
!isSafeToLoadUnconditionally(L->getPointerOperand(),
|
||||||
L->getAlignment(), DL, L))
|
L->getAlignment(), DL, L))
|
||||||
return false;
|
return false;
|
||||||
@ -492,10 +492,11 @@ static CallInst *findTRECandidate(Instruction *TI,
|
|||||||
return CI;
|
return CI;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool eliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret,
|
||||||
eliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret, BasicBlock *&OldEntry,
|
BasicBlock *&OldEntry,
|
||||||
bool &TailCallsAreMarkedTail,
|
bool &TailCallsAreMarkedTail,
|
||||||
SmallVectorImpl<PHINode *> &ArgumentPHIs) {
|
SmallVectorImpl<PHINode *> &ArgumentPHIs,
|
||||||
|
AliasAnalysis *AA) {
|
||||||
// If we are introducing accumulator recursion to eliminate operations after
|
// If we are introducing accumulator recursion to eliminate operations after
|
||||||
// the call instruction that are both associative and commutative, the initial
|
// the call instruction that are both associative and commutative, the initial
|
||||||
// value for the accumulator is placed in this variable. If this value is set
|
// value for the accumulator is placed in this variable. If this value is set
|
||||||
@ -515,7 +516,8 @@ eliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret, BasicBlock *&OldEntry,
|
|||||||
// Check that this is the case now.
|
// Check that this is the case now.
|
||||||
BasicBlock::iterator BBI(CI);
|
BasicBlock::iterator BBI(CI);
|
||||||
for (++BBI; &*BBI != Ret; ++BBI) {
|
for (++BBI; &*BBI != Ret; ++BBI) {
|
||||||
if (canMoveAboveCall(&*BBI, CI)) continue;
|
if (canMoveAboveCall(&*BBI, CI, AA))
|
||||||
|
continue;
|
||||||
|
|
||||||
// If we can't move the instruction above the call, it might be because it
|
// If we can't move the instruction above the call, it might be because it
|
||||||
// is an associative and commutative operation that could be transformed
|
// is an associative and commutative operation that could be transformed
|
||||||
@ -674,7 +676,8 @@ static bool foldReturnAndProcessPred(BasicBlock *BB, ReturnInst *Ret,
|
|||||||
bool &TailCallsAreMarkedTail,
|
bool &TailCallsAreMarkedTail,
|
||||||
SmallVectorImpl<PHINode *> &ArgumentPHIs,
|
SmallVectorImpl<PHINode *> &ArgumentPHIs,
|
||||||
bool CannotTailCallElimCallsMarkedTail,
|
bool CannotTailCallElimCallsMarkedTail,
|
||||||
const TargetTransformInfo *TTI) {
|
const TargetTransformInfo *TTI,
|
||||||
|
AliasAnalysis *AA) {
|
||||||
bool Change = false;
|
bool Change = false;
|
||||||
|
|
||||||
// Make sure this block is a trivial return block.
|
// Make sure this block is a trivial return block.
|
||||||
@ -710,7 +713,7 @@ static bool foldReturnAndProcessPred(BasicBlock *BB, ReturnInst *Ret,
|
|||||||
BB->eraseFromParent();
|
BB->eraseFromParent();
|
||||||
|
|
||||||
eliminateRecursiveTailCall(CI, RI, OldEntry, TailCallsAreMarkedTail,
|
eliminateRecursiveTailCall(CI, RI, OldEntry, TailCallsAreMarkedTail,
|
||||||
ArgumentPHIs);
|
ArgumentPHIs, AA);
|
||||||
++NumRetDuped;
|
++NumRetDuped;
|
||||||
Change = true;
|
Change = true;
|
||||||
}
|
}
|
||||||
@ -723,16 +726,18 @@ static bool processReturningBlock(ReturnInst *Ret, BasicBlock *&OldEntry,
|
|||||||
bool &TailCallsAreMarkedTail,
|
bool &TailCallsAreMarkedTail,
|
||||||
SmallVectorImpl<PHINode *> &ArgumentPHIs,
|
SmallVectorImpl<PHINode *> &ArgumentPHIs,
|
||||||
bool CannotTailCallElimCallsMarkedTail,
|
bool CannotTailCallElimCallsMarkedTail,
|
||||||
const TargetTransformInfo *TTI) {
|
const TargetTransformInfo *TTI,
|
||||||
|
AliasAnalysis *AA) {
|
||||||
CallInst *CI = findTRECandidate(Ret, CannotTailCallElimCallsMarkedTail, TTI);
|
CallInst *CI = findTRECandidate(Ret, CannotTailCallElimCallsMarkedTail, TTI);
|
||||||
if (!CI)
|
if (!CI)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return eliminateRecursiveTailCall(CI, Ret, OldEntry, TailCallsAreMarkedTail,
|
return eliminateRecursiveTailCall(CI, Ret, OldEntry, TailCallsAreMarkedTail,
|
||||||
ArgumentPHIs);
|
ArgumentPHIs, AA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool eliminateTailRecursion(Function &F, const TargetTransformInfo *TTI) {
|
static bool eliminateTailRecursion(Function &F, const TargetTransformInfo *TTI,
|
||||||
|
AliasAnalysis *AA) {
|
||||||
if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true")
|
if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true")
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -767,11 +772,11 @@ static bool eliminateTailRecursion(Function &F, const TargetTransformInfo *TTI)
|
|||||||
if (ReturnInst *Ret = dyn_cast<ReturnInst>(BB->getTerminator())) {
|
if (ReturnInst *Ret = dyn_cast<ReturnInst>(BB->getTerminator())) {
|
||||||
bool Change =
|
bool Change =
|
||||||
processReturningBlock(Ret, OldEntry, TailCallsAreMarkedTail,
|
processReturningBlock(Ret, OldEntry, TailCallsAreMarkedTail,
|
||||||
ArgumentPHIs, !CanTRETailMarkedCall, TTI);
|
ArgumentPHIs, !CanTRETailMarkedCall, TTI, AA);
|
||||||
if (!Change && BB->getFirstNonPHIOrDbg() == Ret)
|
if (!Change && BB->getFirstNonPHIOrDbg() == Ret)
|
||||||
Change =
|
Change = foldReturnAndProcessPred(BB, Ret, OldEntry,
|
||||||
foldReturnAndProcessPred(BB, Ret, OldEntry, TailCallsAreMarkedTail,
|
TailCallsAreMarkedTail, ArgumentPHIs,
|
||||||
ArgumentPHIs, !CanTRETailMarkedCall, TTI);
|
!CanTRETailMarkedCall, TTI, AA);
|
||||||
MadeChange |= Change;
|
MadeChange |= Change;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -801,6 +806,7 @@ struct TailCallElim : public FunctionPass {
|
|||||||
|
|
||||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||||
AU.addRequired<TargetTransformInfoWrapperPass>();
|
AU.addRequired<TargetTransformInfoWrapperPass>();
|
||||||
|
AU.addRequired<AAResultsWrapperPass>();
|
||||||
AU.addPreserved<GlobalsAAWrapperPass>();
|
AU.addPreserved<GlobalsAAWrapperPass>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,7 +815,8 @@ struct TailCallElim : public FunctionPass {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
return eliminateTailRecursion(
|
return eliminateTailRecursion(
|
||||||
F, &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F));
|
F, &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F),
|
||||||
|
&getAnalysis<AAResultsWrapperPass>().getAAResults());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -830,8 +837,9 @@ PreservedAnalyses TailCallElimPass::run(Function &F,
|
|||||||
FunctionAnalysisManager &AM) {
|
FunctionAnalysisManager &AM) {
|
||||||
|
|
||||||
TargetTransformInfo &TTI = AM.getResult<TargetIRAnalysis>(F);
|
TargetTransformInfo &TTI = AM.getResult<TargetIRAnalysis>(F);
|
||||||
|
AliasAnalysis &AA = AM.getResult<AAManager>(F);
|
||||||
|
|
||||||
bool Changed = eliminateTailRecursion(F, &TTI);
|
bool Changed = eliminateTailRecursion(F, &TTI, &AA);
|
||||||
|
|
||||||
if (!Changed)
|
if (!Changed)
|
||||||
return PreservedAnalyses::all();
|
return PreservedAnalyses::all();
|
||||||
|
@ -7,6 +7,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|||||||
; then eliminate the tail recursion.
|
; then eliminate the tail recursion.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@global = external global i32 ; <i32*> [#uses=1]
|
@global = external global i32 ; <i32*> [#uses=1]
|
||||||
@extern_weak_global = extern_weak global i32 ; <i32*> [#uses=1]
|
@extern_weak_global = extern_weak global i32 ; <i32*> [#uses=1]
|
||||||
|
|
||||||
@ -145,3 +146,29 @@ else: ; preds = %entry
|
|||||||
%tmp10 = add i32 %tmp9, %tmp8 ; <i32> [#uses=1]
|
%tmp10 = add i32 %tmp9, %tmp8 ; <i32> [#uses=1]
|
||||||
ret i32 %tmp10
|
ret i32 %tmp10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; This load can be moved above the call because the function call does not write to the memory the load
|
||||||
|
; is accessing and the load is safe to speculate.
|
||||||
|
define fastcc i32 @raise_load_6(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) nounwind {
|
||||||
|
; CHECK-LABEL: @raise_load_6(
|
||||||
|
; CHECK-NOT: call
|
||||||
|
; CHECK: load i32, i32*
|
||||||
|
; CHECK-NOT: call
|
||||||
|
; CHECK: }
|
||||||
|
entry:
|
||||||
|
%s = alloca i32
|
||||||
|
store i32 4, i32* %s
|
||||||
|
%tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1]
|
||||||
|
br i1 %tmp2, label %if, label %else
|
||||||
|
|
||||||
|
if: ; preds = %entry
|
||||||
|
store i32 1, i32* %a_arg
|
||||||
|
ret i32 0
|
||||||
|
|
||||||
|
else: ; preds = %entry
|
||||||
|
%tmp7 = add i32 %start_arg, 1 ; <i32> [#uses=1]
|
||||||
|
%tmp8 = call fastcc i32 @raise_load_6(i32* %a_arg, i32 %a_len_arg, i32 %tmp7) ; <i32> [#uses=1]
|
||||||
|
%tmp9 = load i32, i32* %s ; <i32> [#uses=1]
|
||||||
|
%tmp10 = add i32 %tmp9, %tmp8 ; <i32> [#uses=1]
|
||||||
|
ret i32 %tmp10
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user