[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:
Adam Nemet 2017-01-11 04:39:49 +00:00
parent 81941b3195
commit e2aaf3a35e
2 changed files with 67 additions and 6 deletions

View File

@ -91,10 +91,11 @@ static bool sink(Instruction &I, const LoopInfo *LI, const DominatorTree *DT,
const Loop *CurLoop, AliasSetTracker *CurAST,
const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE);
static bool isSafeToExecuteUnconditionally(const Instruction &Inst,
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
const DominatorTree *DT,
const Loop *CurLoop,
const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE,
const Instruction *CtxI = nullptr);
static bool pointerInvalidatedByLoop(Value *V, uint64_t Size,
const AAMDNodes &AAInfo,
@ -434,7 +435,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
if (CurLoop->hasLoopInvariantOperands(&I) &&
canSinkOrHoistInst(I, AA, DT, CurLoop, CurAST, SafetyInfo, ORE) &&
isSafeToExecuteUnconditionally(
I, DT, CurLoop, SafetyInfo,
I, DT, CurLoop, SafetyInfo, ORE,
CurLoop->getLoopPreheader()->getTerminator()))
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,
/// 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.
static bool isSafeToExecuteUnconditionally(const Instruction &Inst,
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
const DominatorTree *DT,
const Loop *CurLoop,
const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE,
const Instruction *CtxI) {
if (isSafeToSpeculativelyExecute(&Inst, CtxI, DT))
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 {
@ -1016,14 +1030,14 @@ bool llvm::promoteLoopAccessesToScalars(
// If there is an non-load/store instruction in the loop, we can't promote
// it.
if (const LoadInst *Load = dyn_cast<LoadInst>(UI)) {
if (LoadInst *Load = dyn_cast<LoadInst>(UI)) {
assert(!Load->isVolatile() && "AST broken");
if (!Load->isSimple())
return false;
if (!DereferenceableInPH)
DereferenceableInPH = isSafeToExecuteUnconditionally(
*Load, DT, CurLoop, SafetyInfo, Preheader->getTerminator());
*Load, DT, CurLoop, SafetyInfo, ORE, Preheader->getTerminator());
} else if (const StoreInst *Store = dyn_cast<StoreInst>(UI)) {
// Stores *of* the pointer are not interesting, only stores *to* the
// pointer.

View File

@ -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)