Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / GVN / loadpre-context.ll
blobb0738892d84000e8502f56ac13147f71d2d05db9
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=gvn -S | FileCheck %s
4 ; load may be speculated, address is not null using context search.
5 ; There is a critical edge.
6 define i32 @loadpre_critical_edge(ptr align 8 dereferenceable_or_null(48) %arg, i32 %N) nofree nosync {
7 ; CHECK-LABEL: @loadpre_critical_edge(
8 ; CHECK-NEXT:  entry:
9 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ARG:%.*]], null
10 ; CHECK-NEXT:    br i1 [[CMP]], label [[NULL_EXIT:%.*]], label [[ENTRY_HEADER_CRIT_EDGE:%.*]]
11 ; CHECK:       entry.header_crit_edge:
12 ; CHECK-NEXT:    [[V_PRE:%.*]] = load i32, ptr [[ARG]], align 4
13 ; CHECK-NEXT:    br label [[HEADER:%.*]]
14 ; CHECK:       header:
15 ; CHECK-NEXT:    [[V:%.*]] = phi i32 [ [[V_PRE]], [[ENTRY_HEADER_CRIT_EDGE]] ], [ [[SUM:%.*]], [[HEADER]] ]
16 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_HEADER_CRIT_EDGE]] ], [ [[IV_NEXT:%.*]], [[HEADER]] ]
17 ; CHECK-NEXT:    [[NEW_V:%.*]] = call i32 @ro_foo(i32 [[IV]]) #[[ATTR0:[0-9]+]]
18 ; CHECK-NEXT:    [[SUM]] = add i32 [[NEW_V]], [[V]]
19 ; CHECK-NEXT:    store i32 [[SUM]], ptr [[ARG]], align 4
20 ; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
21 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[IV_NEXT]], [[N:%.*]]
22 ; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[HEADER]]
23 ; CHECK:       exit:
24 ; CHECK-NEXT:    ret i32 [[SUM]]
25 ; CHECK:       null_exit:
26 ; CHECK-NEXT:    ret i32 0
28 entry:
29   %cmp = icmp eq ptr %arg, null
30   br i1 %cmp, label %null_exit, label %header
32 header:
33   %iv = phi i32 [0, %entry], [%iv.next, %header]
34 ; Call prevents to move load over due to it does not guarantee to return.
35   %new_v = call i32 @ro_foo(i32 %iv) readnone
36   %v = load i32, ptr %arg
37   %sum = add i32 %new_v, %v
38   store i32 %sum, ptr %arg
39   %iv.next = add i32 %iv, 1
40   %cond = icmp eq i32 %iv.next, %N
41   br i1 %cond, label %exit, label %header
43 exit:
44   ret i32 %sum
46 null_exit:
47   ret i32 0
50 ; load may be speculated, address is not null using context search.
51 define i32 @loadpre_basic(ptr align 8 dereferenceable_or_null(48) %arg, i32 %N) nofree nosync {
52 ; CHECK-LABEL: @loadpre_basic(
53 ; CHECK-NEXT:  entry:
54 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ARG:%.*]], null
55 ; CHECK-NEXT:    br i1 [[CMP]], label [[NULL_EXIT:%.*]], label [[PREHEADER:%.*]]
56 ; CHECK:       preheader:
57 ; CHECK-NEXT:    [[V_PRE:%.*]] = load i32, ptr [[ARG]], align 4
58 ; CHECK-NEXT:    br label [[HEADER:%.*]]
59 ; CHECK:       header:
60 ; CHECK-NEXT:    [[V:%.*]] = phi i32 [ [[V_PRE]], [[PREHEADER]] ], [ [[SUM:%.*]], [[HEADER]] ]
61 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[HEADER]] ]
62 ; CHECK-NEXT:    [[NEW_V:%.*]] = call i32 @ro_foo(i32 [[IV]]) #[[ATTR0]]
63 ; CHECK-NEXT:    [[SUM]] = add i32 [[NEW_V]], [[V]]
64 ; CHECK-NEXT:    store i32 [[SUM]], ptr [[ARG]], align 4
65 ; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
66 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[IV_NEXT]], [[N:%.*]]
67 ; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[HEADER]]
68 ; CHECK:       exit:
69 ; CHECK-NEXT:    ret i32 [[SUM]]
70 ; CHECK:       null_exit:
71 ; CHECK-NEXT:    ret i32 0
73 entry:
74   %cmp = icmp eq ptr %arg, null
75   br i1 %cmp, label %null_exit, label %preheader
77 preheader:
78   br label %header
80 header:
81   %iv = phi i32 [0, %preheader], [%iv.next, %header]
82 ; Call prevents to move load over due to it does not guarantee to return.
83   %new_v = call i32 @ro_foo(i32 %iv) readnone
84   %v = load i32, ptr %arg
85   %sum = add i32 %new_v, %v
86   store i32 %sum, ptr %arg
87   %iv.next = add i32 %iv, 1
88   %cond = icmp eq i32 %iv.next, %N
89   br i1 %cond, label %exit, label %header
91 exit:
92   ret i32 %sum
94 null_exit:
95   ret i32 0
98 ; load cannot be speculated, check "address is not null" does not dominate the loop.
99 define i32 @loadpre_maybe_null(ptr align 8 dereferenceable_or_null(48) %arg, i32 %N, i1 %c) nofree nosync {
100 ; CHECK-LABEL: @loadpre_maybe_null(
101 ; CHECK-NEXT:  entry:
102 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[NULL_CHECK:%.*]], label [[PREHEADER:%.*]]
103 ; CHECK:       null_check:
104 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ARG:%.*]], null
105 ; CHECK-NEXT:    br i1 [[CMP]], label [[NULL_EXIT:%.*]], label [[PREHEADER]]
106 ; CHECK:       preheader:
107 ; CHECK-NEXT:    br label [[HEADER:%.*]]
108 ; CHECK:       header:
109 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[HEADER]] ]
110 ; CHECK-NEXT:    [[NEW_V:%.*]] = call i32 @ro_foo(i32 [[IV]]) #[[ATTR0]]
111 ; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[ARG]], align 4
112 ; CHECK-NEXT:    [[SUM:%.*]] = add i32 [[NEW_V]], [[V]]
113 ; CHECK-NEXT:    store i32 [[SUM]], ptr [[ARG]], align 4
114 ; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
115 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[IV_NEXT]], [[N:%.*]]
116 ; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[HEADER]]
117 ; CHECK:       exit:
118 ; CHECK-NEXT:    ret i32 [[SUM]]
119 ; CHECK:       null_exit:
120 ; CHECK-NEXT:    ret i32 0
122 entry:
123   br i1 %c, label %null_check, label %preheader
125 null_check:
126   %cmp = icmp eq ptr %arg, null
127   br i1 %cmp, label %null_exit, label %preheader
129 preheader:
130   br label %header
132 header:
133   %iv = phi i32 [0, %preheader], [%iv.next, %header]
134 ; Call prevents to move load over due to it does not guarantee to return.
135   %new_v = call i32 @ro_foo(i32 %iv) readnone
136   %v = load i32, ptr %arg
137   %sum = add i32 %new_v, %v
138   store i32 %sum, ptr %arg
139   %iv.next = add i32 %iv, 1
140   %cond = icmp eq i32 %iv.next, %N
141   br i1 %cond, label %exit, label %header
143 exit:
144   ret i32 %sum
146 null_exit:
147   ret i32 0
150 ; Does not guarantee that returns.
151 declare i32 @ro_foo(i32) readnone