[llvm] r340256 - [LICM] Hoist guards with invariant conditions

Max Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 21 01:11:32 PDT 2018


Author: mkazantsev
Date: Tue Aug 21 01:11:31 2018
New Revision: 340256

URL: http://llvm.org/viewvc/llvm-project?rev=340256&view=rev
Log:
[LICM] Hoist guards with invariant conditions

This patch teaches LICM to hoist guards from the loop if they are guaranteed to execute and
if there are no side effects that could prevent that.

Differential Revision: https://reviews.llvm.org/D50501
Reviewed By: reames

Modified:
    llvm/trunk/lib/Transforms/Scalar/LICM.cpp
    llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll
    llvm/trunk/test/Transforms/LICM/guards.ll

Modified: llvm/trunk/lib/Transforms/Scalar/LICM.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/LICM.cpp?rev=340256&r1=340255&r2=340256&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/LICM.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/LICM.cpp Tue Aug 21 01:11:31 2018
@@ -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 @@ bool llvm::hoistRegion(DomTreeNode *N, A
     // 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 @@ bool llvm::hoistRegion(DomTreeNode *N, A
         continue;
       }
 
+      using namespace PatternMatch;
+      if (match(&I, m_Intrinsic<Intrinsic::experimental_guard>()) &&
+          IsMustExecute && IsMemoryNotModified &&
+          CurLoop->hasLoopInvariantOperands(&I)) {
+        hoist(I, DT, CurLoop, SafetyInfo, ORE);
+        Changed = true;
+        continue;
+      }
+
       if (IsMustExecute)
         IsMustExecute = isGuaranteedToTransferExecutionToSuccessor(&I);
+      if (IsMemoryNotModified)
+        IsMemoryNotModified = !I.mayWriteToMemory();
     }
   }
 

Modified: llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll?rev=340256&r1=340255&r2=340256&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll (original)
+++ llvm/trunk/test/Transforms/GuardWidening/loop-schedule.ll Tue Aug 21 01:11:31 2018
@@ -41,8 +41,8 @@ define void @within_loop(i32 %a, i32 %b,
 ; 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

Modified: llvm/trunk/test/Transforms/LICM/guards.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LICM/guards.ll?rev=340256&r1=340255&r2=340256&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LICM/guards.ll (original)
+++ llvm/trunk/test/Transforms/LICM/guards.ll Tue Aug 21 01:11:31 2018
@@ -1,13 +1,13 @@
 ; RUN: opt -licm -basicaa < %s -S | FileCheck %s
 ; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,require<opt-remark-emit>,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 @@ loop:
 }
 
 
-; 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 @@ exit:
   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:




More information about the llvm-commits mailing list