1; RUN: opt -S -passes=licm %s | FileCheck %s 2; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<target-ir>,require<scalar-evolution>,require<opt-remark-emit>,loop-mssa(licm)' < %s -S | FileCheck %s 3 4declare i32 @load(ptr %p) argmemonly readonly nounwind 5 6define void @test_load(ptr noalias %loc, ptr noalias %sink) { 7; CHECK-LABEL: @test_load 8; CHECK-LABEL: entry: 9; CHECK: call i32 @load 10; CHECK-LABEL: loop: 11entry: 12 br label %loop 13 14loop: 15 %iv = phi i32 [0, %entry], [%iv.next, %loop] 16 %ret = call i32 @load(ptr %loc) 17 store volatile i32 %ret, ptr %sink 18 %iv.next = add i32 %iv, 1 19 %cmp = icmp slt i32 %iv, 200 20 br i1 %cmp, label %loop, label %exit 21 22exit: 23 ret void 24} 25 26declare i32 @spec(ptr %p, ptr %q) readonly argmemonly nounwind speculatable 27 28; We should strip the dereferenceable callsite attribute on spec call's argument since it is 29; can cause UB in the speculatable call when hoisted to preheader. 30; However, we need not strip the nonnull attribute since it just propagates 31; poison if the parameter was indeed null. 32define void @test_strip_attribute(ptr noalias %loc, ptr noalias %sink, ptr %q) { 33; CHECK-LABEL: @test_strip_attribute( 34; CHECK-NEXT: entry: 35; CHECK-NEXT: [[RET:%.*]] = call i32 @load(ptr [[LOC:%.*]]) 36; CHECK-NEXT: [[NULLCHK:%.*]] = icmp eq ptr [[Q:%.*]], null 37; CHECK-NEXT: [[RET2:%.*]] = call i32 @spec(ptr nonnull [[Q]], ptr [[LOC]]) 38; CHECK-NEXT: br label [[LOOP:%.*]] 39; CHECK: loop: 40; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[ISNULL:%.*]] ] 41; CHECK-NEXT: br i1 [[NULLCHK]], label [[ISNULL]], label [[NONNULLBB:%.*]] 42entry: 43 br label %loop 44 45loop: 46 %iv = phi i32 [0, %entry], [%iv.next, %isnull ] 47 %ret = call i32 @load(ptr %loc) 48 %nullchk = icmp eq ptr %q, null 49 br i1 %nullchk, label %isnull, label %nonnullbb 50 51nonnullbb: 52 %ret2 = call i32 @spec(ptr nonnull %q, ptr dereferenceable(12) %loc) 53 br label %isnull 54 55isnull: 56 store volatile i32 %ret, ptr %sink 57 %iv.next = add i32 %iv, 1 58 %cmp = icmp slt i32 %iv, 200 59 br i1 %cmp, label %loop, label %exit 60 61exit: 62 ret void 63} 64 65declare void @store(i32 %val, ptr %p) argmemonly writeonly nounwind 66 67define void @test(ptr %loc) { 68; CHECK-LABEL: @test 69; CHECK-LABEL: loop: 70; CHECK: call void @store 71; CHECK-LABEL: exit: 72entry: 73 br label %loop 74 75loop: 76 %iv = phi i32 [0, %entry], [%iv.next, %loop] 77 call void @store(i32 0, ptr %loc) 78 %iv.next = add i32 %iv, 1 79 %cmp = icmp slt i32 %iv, 200 80 br i1 %cmp, label %loop, label %exit 81 82exit: 83 ret void 84} 85 86define void @test_multiexit(ptr %loc, i1 %earlycnd) { 87; CHECK-LABEL: @test_multiexit 88; CHECK-LABEL: loop: 89; CHECK: call void @store 90; CHECK-LABEL: backedge: 91entry: 92 br label %loop 93 94loop: 95 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 96 call void @store(i32 0, ptr %loc) 97 %iv.next = add i32 %iv, 1 98 br i1 %earlycnd, label %exit1, label %backedge 99 100backedge: 101 %cmp = icmp slt i32 %iv, 200 102 br i1 %cmp, label %loop, label %exit2 103 104exit1: 105 ret void 106exit2: 107 ret void 108} 109 110define void @neg_lv_value(ptr %loc) { 111; CHECK-LABEL: @neg_lv_value 112; CHECK-LABEL: loop: 113; CHECK: call void @store 114; CHECK-LABEL: exit: 115entry: 116 br label %loop 117 118loop: 119 %iv = phi i32 [0, %entry], [%iv.next, %loop] 120 call void @store(i32 %iv, ptr %loc) 121 %iv.next = add i32 %iv, 1 122 %cmp = icmp slt i32 %iv, 200 123 br i1 %cmp, label %loop, label %exit 124 125exit: 126 ret void 127} 128 129define void @neg_lv_addr(ptr %loc) { 130; CHECK-LABEL: @neg_lv_addr 131; CHECK-LABEL: loop: 132; CHECK: call void @store 133; CHECK-LABEL: exit: 134entry: 135 br label %loop 136 137loop: 138 %iv = phi i32 [0, %entry], [%iv.next, %loop] 139 %p = getelementptr i32, ptr %loc, i32 %iv 140 call void @store(i32 0, ptr %p) 141 %iv.next = add i32 %iv, 1 142 %cmp = icmp slt i32 %iv, 200 143 br i1 %cmp, label %loop, label %exit 144 145exit: 146 ret void 147} 148 149define void @neg_mod(ptr %loc) { 150; CHECK-LABEL: @neg_mod 151; CHECK-LABEL: loop: 152; CHECK: call void @store 153; CHECK-LABEL: exit: 154entry: 155 br label %loop 156 157loop: 158 %iv = phi i32 [0, %entry], [%iv.next, %loop] 159 call void @store(i32 0, ptr %loc) 160 store i32 %iv, ptr %loc 161 %iv.next = add i32 %iv, 1 162 %cmp = icmp slt i32 %iv, 200 163 br i1 %cmp, label %loop, label %exit 164 165exit: 166 ret void 167} 168 169define void @neg_ref(ptr %loc) { 170; CHECK-LABEL: @neg_ref 171; CHECK-LABEL: loop: 172; CHECK: call void @store 173; CHECK-LABEL: exit1: 174entry: 175 br label %loop 176 177loop: 178 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 179 call void @store(i32 0, ptr %loc) 180 %v = load i32, ptr %loc 181 %earlycnd = icmp eq i32 %v, 198 182 br i1 %earlycnd, label %exit1, label %backedge 183 184backedge: 185 %iv.next = add i32 %iv, 1 186 %cmp = icmp slt i32 %iv, 200 187 br i1 %cmp, label %loop, label %exit2 188 189exit1: 190 ret void 191exit2: 192 ret void 193} 194 195declare void @modref() 196 197define void @neg_modref(ptr %loc) { 198; CHECK-LABEL: @neg_modref 199; CHECK-LABEL: loop: 200; CHECK: call void @store 201; CHECK-LABEL: exit: 202entry: 203 br label %loop 204 205loop: 206 %iv = phi i32 [0, %entry], [%iv.next, %loop] 207 call void @store(i32 0, ptr %loc) 208 call void @modref() 209 %iv.next = add i32 %iv, 1 210 %cmp = icmp slt i32 %iv, 200 211 br i1 %cmp, label %loop, label %exit 212 213exit: 214 ret void 215} 216 217define void @neg_fence(ptr %loc) { 218; CHECK-LABEL: @neg_fence 219; CHECK-LABEL: loop: 220; CHECK: call void @store 221; CHECK-LABEL: exit: 222entry: 223 br label %loop 224 225loop: 226 %iv = phi i32 [0, %entry], [%iv.next, %loop] 227 call void @store(i32 0, ptr %loc) 228 fence seq_cst 229 %iv.next = add i32 %iv, 1 230 %cmp = icmp slt i32 %iv, 200 231 br i1 %cmp, label %loop, label %exit 232 233exit: 234 ret void 235} 236 237declare void @not_nounwind(i32 %v, ptr %p) writeonly argmemonly 238declare void @not_argmemonly(i32 %v, ptr %p) writeonly nounwind 239declare void @not_writeonly(i32 %v, ptr %p) argmemonly nounwind 240 241define void @neg_not_nounwind(ptr %loc) { 242; CHECK-LABEL: @neg_not_nounwind 243; CHECK-LABEL: loop: 244; CHECK: call void @not_nounwind 245; CHECK-LABEL: exit: 246entry: 247 br label %loop 248 249loop: 250 %iv = phi i32 [0, %entry], [%iv.next, %loop] 251 call void @not_nounwind(i32 0, ptr %loc) 252 %iv.next = add i32 %iv, 1 253 %cmp = icmp slt i32 %iv, 200 254 br i1 %cmp, label %loop, label %exit 255 256exit: 257 ret void 258} 259 260define void @neg_not_argmemonly(ptr %loc) { 261; CHECK-LABEL: @neg_not_argmemonly 262; CHECK-LABEL: loop: 263; CHECK: call void @not_argmemonly 264; CHECK-LABEL: exit: 265entry: 266 br label %loop 267 268loop: 269 %iv = phi i32 [0, %entry], [%iv.next, %loop] 270 call void @not_argmemonly(i32 0, ptr %loc) 271 %iv.next = add i32 %iv, 1 272 %cmp = icmp slt i32 %iv, 200 273 br i1 %cmp, label %loop, label %exit 274 275exit: 276 ret void 277} 278 279define void @neg_not_writeonly(ptr %loc) { 280; CHECK-LABEL: @neg_not_writeonly 281; CHECK-LABEL: loop: 282; CHECK: call void @not_writeonly 283; CHECK-LABEL: exit: 284entry: 285 br label %loop 286 287loop: 288 %iv = phi i32 [0, %entry], [%iv.next, %loop] 289 call void @not_writeonly(i32 0, ptr %loc) 290 %iv.next = add i32 %iv, 1 291 %cmp = icmp slt i32 %iv, 200 292 br i1 %cmp, label %loop, label %exit 293 294exit: 295 ret void 296} 297 298