Index: llvm/trunk/lib/Transforms/Scalar/LICM.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LICM.cpp +++ llvm/trunk/lib/Transforms/Scalar/LICM.cpp @@ -58,6 +58,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/IR/PredIteratorCache.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -465,6 +466,11 @@ // that the next instruction visited is guaranteed to execute if the loop // is entered. bool IsMustExecute = CurLoop->getHeader() == BB; + // Keep track of whether the prefix instructions could have written memory. + // TODO: This and IsMustExecute may be done smarter if we keep track of all + // throwing and mem-writing operations in every block, e.g. using something + // similar to isGuaranteedToExecute. + bool IsMemoryNotModified = CurLoop->getHeader() == BB; for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;) { Instruction &I = *II++; @@ -523,8 +529,19 @@ continue; } + using namespace PatternMatch; + if (match(&I, m_Intrinsic()) && + IsMustExecute && IsMemoryNotModified && + CurLoop->hasLoopInvariantOperands(&I)) { + hoist(I, DT, CurLoop, SafetyInfo, ORE); + Changed = true; + continue; + } + if (IsMustExecute) IsMustExecute = isGuaranteedToTransferExecutionToSuccessor(&I); + if (IsMemoryNotModified) + IsMemoryNotModified = !I.mayWriteToMemory(); } } Index: llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll =================================================================== --- llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll +++ llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll @@ -41,8 +41,8 @@ ; CHECK: %cond_0 = icmp ult i32 %a, 10 ; CHECK: %cond_1 = icmp ult i32 %b, 10 ; CHECK: %wide.chk = and i1 %cond_0, %cond_1 -; CHECK-LABEL: loop: ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] +; CHECK-LABEL: loop: entry: br label %loop Index: llvm/trunk/test/Transforms/LICM/guards.ll =================================================================== --- llvm/trunk/test/Transforms/LICM/guards.ll +++ llvm/trunk/test/Transforms/LICM/guards.ll @@ -1,13 +1,13 @@ ; RUN: opt -licm -basicaa < %s -S | FileCheck %s ; RUN: opt -aa-pipeline=basic-aa -passes='require,require,require,require,loop(licm)' < %s -S | FileCheck %s -; TODO: should be able to hoist both guard and load +; Hoist guard and load. define void @test1(i1 %cond, i32* %ptr) { ; CHECK-LABEL: @test1( ; CHECK-LABEL: entry: -; CHECK-LABEL: loop: ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %cond) ; CHECK: %val = load i32, i32* %ptr +; CHECK-LABEL: loop: entry: br label %loop @@ -62,13 +62,14 @@ } -; Could hoist, but don't +; Hoist guard. Cannot hoist load because of aliasing. define void @test3(i1 %cond, i32* %ptr) { ; CHECK-LABEL: @test3( ; CHECK-LABEL: entry: -; CHECK-LABEL: loop: ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %cond) +; CHECK-LABEL: loop: ; CHECK: %val = load i32, i32* %ptr +; CHECK: store i32 0, i32* %ptr entry: br label %loop @@ -228,16 +229,16 @@ ret void } -; We can hoist an invariant guard, leave the following variant guard in the loop. +; Hoist an invariant guard, leave the following variant guard in the loop. define void @test5a(i1 %c, i32* %p, i32* %q) { ; CHECK-LABEL: @test5a( ; CHECK-LABEL: entry: ; CHECK: %a = load i32, i32* %p ; CHECK: %invariant_cond = icmp ne i32 %a, 100 +; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) ; CHECK-LABEL: loop: ; CHECK: %variant_cond = icmp ne i32 %a, %iv -; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %variant_cond) entry: