Skip to content

Commit 787dba7

Browse files
committed
[LICM] Hoisting of widenable conditions out of loops
The change itself is straight forward and obvious, but ... there's an existing test checking for exactly the opposite. Both I and Artur think this is simply conservatism in the initial implementation. If anyone bisects a problem to this, a counter example will be very interesting. Differential Revision: https://reviews.llvm.org/D69907
1 parent 0703db3 commit 787dba7

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,7 @@ def int_experimental_guard : Intrinsic<[], [llvm_i1_ty, llvm_vararg_ty],
10701070

10711071
// Supports widenable conditions for guards represented as explicit branches.
10721072
def int_experimental_widenable_condition : Intrinsic<[llvm_i1_ty], [],
1073-
[IntrInaccessibleMemOnly, IntrWillReturn]>;
1073+
[IntrInaccessibleMemOnly, IntrWillReturn, IntrSpeculatable]>;
10741074

10751075
// NOP: calls/invokes to this intrinsic are removed by codegen
10761076
def int_donothing : Intrinsic<[], [], [IntrNoMem, IntrWillReturn]>;

llvm/lib/Transforms/Scalar/LICM.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,10 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT,
11441144
// Assumes don't actually alias anything or throw
11451145
return true;
11461146

1147+
if (match(CI, m_Intrinsic<Intrinsic::experimental_widenable_condition>()))
1148+
// Widenable conditions don't actually alias anything or throw
1149+
return true;
1150+
11471151
// Handle simple cases by querying alias analysis.
11481152
FunctionModRefBehavior Behavior = AA->getModRefBehavior(CI);
11491153
if (Behavior == FMRB_DoesNotAccessMemory)

llvm/test/Transforms/LICM/explicit_guards.ll

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,54 @@
22
; RUN: opt -S -make-guards-explicit -basicaa -licm < %s | FileCheck %s
33
; RUN: opt -S -aa-pipeline=basic-aa -passes='require<opt-remark-emit>,make-guards-explicit,loop(licm)' < %s | FileCheck %s
44

5-
; Test interaction between explicit guards and LICM: make sure that we do not
6-
; hoist explicit conditions while we can hoist invariant loads in presence of
7-
; explicit guards.
8-
95
declare void @llvm.experimental.guard(i1,...)
6+
declare void @maythrow()
107

118
; Make sure that we do not hoist widenable_cond out of loop.
12-
define void @do_not_hoist_widenable_cond(i1 %cond, i32 %N, i32 %M) {
13-
; CHECK-LABEL: @do_not_hoist_widenable_cond(
9+
define void @hoist_widenable_cond(i1 %cond, i32 %N, i32 %M) {
10+
; CHECK-LABEL: @hoist_widenable_cond(
1411
; CHECK-NEXT: entry:
12+
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
1513
; CHECK-NEXT: br label [[LOOP:%.*]]
1614
; CHECK: loop:
1715
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
1816
; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]]
17+
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
18+
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
19+
; CHECK: deopt:
20+
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
21+
; CHECK-NEXT: ret void
22+
; CHECK: guarded:
23+
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]]
24+
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
25+
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
26+
; CHECK: exit:
27+
; CHECK-NEXT: ret void
28+
;
29+
entry:
30+
br label %loop
31+
32+
loop:
33+
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
34+
%guard_cond = icmp slt i32 %iv, %N
35+
call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ]
36+
%loop_cond = icmp slt i32 %iv, %M
37+
%iv.next = add i32 %iv, 1
38+
br i1 %loop_cond, label %loop, label %exit
39+
40+
exit:
41+
ret void
42+
}
43+
44+
define void @hoist_widenable_cond_speculate(i1 %cond, i32 %N, i32 %M) {
45+
; CHECK-LABEL: @hoist_widenable_cond_speculate(
46+
; CHECK-NEXT: entry:
1947
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
48+
; CHECK-NEXT: br label [[LOOP:%.*]]
49+
; CHECK: loop:
50+
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
51+
; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]]
52+
; CHECK-NEXT: call void @maythrow()
2053
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
2154
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
2255
; CHECK: deopt:
@@ -35,6 +68,7 @@ entry:
3568
loop:
3669
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
3770
%guard_cond = icmp slt i32 %iv, %N
71+
call void @maythrow()
3872
call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ]
3973
%loop_cond = icmp slt i32 %iv, %M
4074
%iv.next = add i32 %iv, 1
@@ -44,15 +78,16 @@ exit:
4478
ret void
4579
}
4680

81+
4782
define void @hoist_invariant_load(i1 %cond, i32* %np, i32 %M) {
4883
; CHECK-LABEL: @hoist_invariant_load(
4984
; CHECK-NEXT: entry:
5085
; CHECK-NEXT: [[N:%.*]] = load i32, i32* [[NP:%.*]]
86+
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
5187
; CHECK-NEXT: br label [[LOOP:%.*]]
5288
; CHECK: loop:
5389
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
5490
; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N]]
55-
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
5691
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
5792
; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
5893
; CHECK: deopt:

0 commit comments

Comments
 (0)