forked from OSchip/llvm-project
[LICM] Report failing to hoist conditionally-executed loads
These are interesting again because the user may not be aware that this is a common reason preventing LICM. A const is removed from an instruction pointer declaration in order to pass it to ORE. Differential Revision: https://reviews.llvm.org/D27940 llvm-svn: 291649
This commit is contained in:
parent
81941b3195
commit
e2aaf3a35e
|
@ -91,10 +91,11 @@ static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
|
||||||
const Loop *CurLoop, AliasSetTracker *CurAST,
|
const Loop *CurLoop, AliasSetTracker *CurAST,
|
||||||
const LoopSafetyInfo *SafetyInfo,
|
const LoopSafetyInfo *SafetyInfo,
|
||||||
OptimizationRemarkEmitter *ORE);
|
OptimizationRemarkEmitter *ORE);
|
||||||
static bool isSafeToExecuteUnconditionally(const Instruction &Inst,
|
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
|
||||||
const DominatorTree *DT,
|
const DominatorTree *DT,
|
||||||
const Loop *CurLoop,
|
const Loop *CurLoop,
|
||||||
const LoopSafetyInfo *SafetyInfo,
|
const LoopSafetyInfo *SafetyInfo,
|
||||||
|
OptimizationRemarkEmitter *ORE,
|
||||||
const Instruction *CtxI = nullptr);
|
const Instruction *CtxI = nullptr);
|
||||||
static bool pointerInvalidatedByLoop(Value *V, uint64_t Size,
|
static bool pointerInvalidatedByLoop(Value *V, uint64_t Size,
|
||||||
const AAMDNodes &AAInfo,
|
const AAMDNodes &AAInfo,
|
||||||
|
@ -434,7 +435,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
|
||||||
if (CurLoop->hasLoopInvariantOperands(&I) &&
|
if (CurLoop->hasLoopInvariantOperands(&I) &&
|
||||||
canSinkOrHoistInst(I, AA, DT, CurLoop, CurAST, SafetyInfo, ORE) &&
|
canSinkOrHoistInst(I, AA, DT, CurLoop, CurAST, SafetyInfo, ORE) &&
|
||||||
isSafeToExecuteUnconditionally(
|
isSafeToExecuteUnconditionally(
|
||||||
I, DT, CurLoop, SafetyInfo,
|
I, DT, CurLoop, SafetyInfo, ORE,
|
||||||
CurLoop->getLoopPreheader()->getTerminator()))
|
CurLoop->getLoopPreheader()->getTerminator()))
|
||||||
Changed |= hoist(I, DT, CurLoop, SafetyInfo, ORE);
|
Changed |= hoist(I, DT, CurLoop, SafetyInfo, ORE);
|
||||||
}
|
}
|
||||||
|
@ -819,15 +820,28 @@ static bool hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
|
||||||
/// Only sink or hoist an instruction if it is not a trapping instruction,
|
/// Only sink or hoist an instruction if it is not a trapping instruction,
|
||||||
/// or if the instruction is known not to trap when moved to the preheader.
|
/// or if the instruction is known not to trap when moved to the preheader.
|
||||||
/// or if it is a trapping instruction and is guaranteed to execute.
|
/// or if it is a trapping instruction and is guaranteed to execute.
|
||||||
static bool isSafeToExecuteUnconditionally(const Instruction &Inst,
|
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
|
||||||
const DominatorTree *DT,
|
const DominatorTree *DT,
|
||||||
const Loop *CurLoop,
|
const Loop *CurLoop,
|
||||||
const LoopSafetyInfo *SafetyInfo,
|
const LoopSafetyInfo *SafetyInfo,
|
||||||
|
OptimizationRemarkEmitter *ORE,
|
||||||
const Instruction *CtxI) {
|
const Instruction *CtxI) {
|
||||||
if (isSafeToSpeculativelyExecute(&Inst, CtxI, DT))
|
if (isSafeToSpeculativelyExecute(&Inst, CtxI, DT))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return isGuaranteedToExecute(Inst, DT, CurLoop, SafetyInfo);
|
bool GuaranteedToExecute =
|
||||||
|
isGuaranteedToExecute(Inst, DT, CurLoop, SafetyInfo);
|
||||||
|
|
||||||
|
if (!GuaranteedToExecute) {
|
||||||
|
auto *LI = dyn_cast<LoadInst>(&Inst);
|
||||||
|
if (LI && CurLoop->isLoopInvariant(LI->getPointerOperand()))
|
||||||
|
ORE->emit(OptimizationRemarkMissed(
|
||||||
|
DEBUG_TYPE, "LoadWithLoopInvariantAddressCondExecuted", LI)
|
||||||
|
<< "failed to hoist load with loop-invariant address "
|
||||||
|
"because load is conditionally executed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GuaranteedToExecute;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1016,14 +1030,14 @@ bool llvm::promoteLoopAccessesToScalars(
|
||||||
|
|
||||||
// If there is an non-load/store instruction in the loop, we can't promote
|
// If there is an non-load/store instruction in the loop, we can't promote
|
||||||
// it.
|
// it.
|
||||||
if (const LoadInst *Load = dyn_cast<LoadInst>(UI)) {
|
if (LoadInst *Load = dyn_cast<LoadInst>(UI)) {
|
||||||
assert(!Load->isVolatile() && "AST broken");
|
assert(!Load->isVolatile() && "AST broken");
|
||||||
if (!Load->isSimple())
|
if (!Load->isSimple())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!DereferenceableInPH)
|
if (!DereferenceableInPH)
|
||||||
DereferenceableInPH = isSafeToExecuteUnconditionally(
|
DereferenceableInPH = isSafeToExecuteUnconditionally(
|
||||||
*Load, DT, CurLoop, SafetyInfo, Preheader->getTerminator());
|
*Load, DT, CurLoop, SafetyInfo, ORE, Preheader->getTerminator());
|
||||||
} else if (const StoreInst *Store = dyn_cast<StoreInst>(UI)) {
|
} else if (const StoreInst *Store = dyn_cast<StoreInst>(UI)) {
|
||||||
// Stores *of* the pointer are not interesting, only stores *to* the
|
// Stores *of* the pointer are not interesting, only stores *to* the
|
||||||
// pointer.
|
// pointer.
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
; RUN: opt < %s -licm -pass-remarks-missed=licm -o /dev/null 2>&1 | FileCheck %s
|
||||||
|
; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,require<opt-remark-emit>,loop(licm)' %s -o /dev/null -pass-remarks-missed=licm 2>&1 | FileCheck %s
|
||||||
|
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
|
||||||
|
|
||||||
|
; With the load from %p conditional, we can't optmize this and the remark
|
||||||
|
; should tell us about it.
|
||||||
|
|
||||||
|
define void @test(i32* %array, i32* noalias %p) {
|
||||||
|
Entry:
|
||||||
|
br label %Loop
|
||||||
|
|
||||||
|
Loop:
|
||||||
|
%j = phi i32 [ 0, %Entry ], [ %Next, %else]
|
||||||
|
%addr = getelementptr i32, i32* %array, i32 %j
|
||||||
|
%a = load i32, i32* %addr
|
||||||
|
%c = icmp eq i32 %a, 0
|
||||||
|
br i1 %c, label %then, label %else
|
||||||
|
|
||||||
|
then:
|
||||||
|
; CHECK: remark: /tmp/kk.c:2:20: failed to hoist load with loop-invariant address because load is conditionally executed
|
||||||
|
%b = load i32, i32* %p, !dbg !8
|
||||||
|
%a2 = add i32 %a, %b
|
||||||
|
store i32 %a2, i32* %addr
|
||||||
|
br label %else
|
||||||
|
|
||||||
|
else:
|
||||||
|
%Next = add i32 %j, 1
|
||||||
|
%cond = icmp eq i32 %Next, 0
|
||||||
|
br i1 %cond, label %Out, label %Loop
|
||||||
|
|
||||||
|
Out:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!3, !4}
|
||||||
|
!llvm.ident = !{!5}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug, enums: !2)
|
||||||
|
!1 = !DIFile(filename: "/tmp/kk.c", directory: "/tmp")
|
||||||
|
!2 = !{}
|
||||||
|
!3 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!4 = !{i32 1, !"PIC Level", i32 2}
|
||||||
|
!5 = !{!"clang version 3.9.0 "}
|
||||||
|
!6 = distinct !DISubprogram(name: "success", scope: !1, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !2)
|
||||||
|
!7 = !DISubroutineType(types: !2)
|
||||||
|
!8 = !DILocation(line: 2, column: 20, scope: !6)
|
Loading…
Reference in New Issue