1; 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 2 3define void @test(ptr %loc) { 4; CHECK-LABEL: @test 5; CHECK-LABEL: entry: 6; CHECK: store i32 0, ptr %loc 7; CHECK-LABEL: loop: 8entry: 9 br label %loop 10 11loop: 12 %iv = phi i32 [0, %entry], [%iv.next, %loop] 13 store i32 0, ptr %loc 14 %iv.next = add i32 %iv, 1 15 %cmp = icmp slt i32 %iv, 200 16 br i1 %cmp, label %loop, label %exit 17 18exit: 19 ret void 20} 21 22define void @test_multiexit(ptr %loc, i1 %earlycnd) { 23; CHECK-LABEL: @test_multiexit 24; CHECK-LABEL: entry: 25; CHECK: store i32 0, ptr %loc 26; CHECK-LABEL: loop: 27entry: 28 br label %loop 29 30loop: 31 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 32 store i32 0, ptr %loc 33 %iv.next = add i32 %iv, 1 34 br i1 %earlycnd, label %exit1, label %backedge 35 36backedge: 37 %cmp = icmp slt i32 %iv, 200 38 br i1 %cmp, label %loop, label %exit2 39 40exit1: 41 ret void 42exit2: 43 ret void 44} 45 46define ptr @false_negative_2use(ptr %loc) { 47; CHECK-LABEL: @false_negative_2use 48; CHECK-LABEL: entry: 49; CHECK: store i32 0, ptr %loc 50; CHECK-LABEL: loop: 51entry: 52 br label %loop 53 54loop: 55 %iv = phi i32 [0, %entry], [%iv.next, %loop] 56 store i32 0, ptr %loc 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 ptr %loc 63} 64 65define void @neg_lv_value(ptr %loc) { 66; CHECK-LABEL: @neg_lv_value 67; CHECK-LABEL: exit: 68; CHECK: store i32 %iv.lcssa, ptr %loc 69entry: 70 br label %loop 71 72loop: 73 %iv = phi i32 [0, %entry], [%iv.next, %loop] 74 store i32 %iv, ptr %loc 75 %iv.next = add i32 %iv, 1 76 %cmp = icmp slt i32 %iv, 200 77 br i1 %cmp, label %loop, label %exit 78 79exit: 80 ret void 81} 82 83define void @neg_lv_addr(ptr %loc) { 84; CHECK-LABEL: @neg_lv_addr 85; CHECK-LABEL: loop: 86; CHECK: store i32 0, ptr %p 87; CHECK-LABEL: exit: 88entry: 89 br label %loop 90 91loop: 92 %iv = phi i32 [0, %entry], [%iv.next, %loop] 93 %p = getelementptr i32, ptr %loc, i32 %iv 94 store i32 0, ptr %p 95 %iv.next = add i32 %iv, 1 96 %cmp = icmp slt i32 %iv, 200 97 br i1 %cmp, label %loop, label %exit 98 99exit: 100 ret void 101} 102 103define void @neg_mod(ptr %loc) { 104; CHECK-LABEL: @neg_mod 105; CHECK-LABEL: exit: 106; CHECK: store i32 %iv.lcssa, ptr %loc 107entry: 108 br label %loop 109 110loop: 111 %iv = phi i32 [0, %entry], [%iv.next, %loop] 112 store i32 0, ptr %loc 113 store i32 %iv, ptr %loc 114 %iv.next = add i32 %iv, 1 115 %cmp = icmp slt i32 %iv, 200 116 br i1 %cmp, label %loop, label %exit 117 118exit: 119 ret void 120} 121 122; Hoisting the store is actually valid here, as it dominates the load. 123define void @neg_ref(ptr %loc) { 124; CHECK-LABEL: @neg_ref 125; CHECK-LABEL: exit1: 126; CHECK: store i32 0, ptr %loc 127; CHECK-LABEL: exit2: 128; CHECK: store i32 0, ptr %loc 129entry: 130 br label %loop 131 132loop: 133 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 134 store i32 0, ptr %loc 135 %v = load i32, ptr %loc 136 %earlycnd = icmp eq i32 %v, 198 137 br i1 %earlycnd, label %exit1, label %backedge 138 139backedge: 140 %iv.next = add i32 %iv, 1 141 %cmp = icmp slt i32 %iv, 200 142 br i1 %cmp, label %loop, label %exit2 143 144exit1: 145 ret void 146exit2: 147 ret void 148} 149 150; Hoisting the store here leads to a miscompile. 151define void @neg_ref2(ptr %loc) { 152; CHECK-LABEL: @neg_ref2 153; CHECK-LABEL: exit1: 154; CHECK: store i32 0, ptr %loc 155; CHECK-LABEL: exit2: 156; CHECK: store i32 0, ptr %loc 157entry: 158 store i32 198, ptr %loc 159 br label %loop 160 161loop: 162 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 163 %v = load i32, ptr %loc 164 store i32 0, ptr %loc 165 %earlycnd = icmp eq i32 %v, 198 166 br i1 %earlycnd, label %exit1, label %backedge 167 168backedge: 169 %iv.next = add i32 %iv, 1 170 %cmp = icmp slt i32 %iv, 200 171 br i1 %cmp, label %loop, label %exit2 172 173exit1: 174 ret void 175exit2: 176 ret void 177} 178 179declare void @modref() 180 181define void @neg_modref(ptr %loc) { 182; CHECK-LABEL: @neg_modref 183; CHECK-LABEL: loop: 184; CHECK: store i32 0, ptr %loc 185; CHECK-LABEL: exit: 186entry: 187 br label %loop 188 189loop: 190 %iv = phi i32 [0, %entry], [%iv.next, %loop] 191 store i32 0, ptr %loc 192 call void @modref() 193 %iv.next = add i32 %iv, 1 194 %cmp = icmp slt i32 %iv, 200 195 br i1 %cmp, label %loop, label %exit 196 197exit: 198 ret void 199} 200 201define void @neg_fence(ptr %loc) { 202; CHECK-LABEL: @neg_fence 203; CHECK-LABEL: loop: 204; CHECK: store i32 0, ptr %loc 205; CHECK-LABEL: exit: 206entry: 207 br label %loop 208 209loop: 210 %iv = phi i32 [0, %entry], [%iv.next, %loop] 211 store i32 0, ptr %loc 212 fence seq_cst 213 %iv.next = add i32 %iv, 1 214 %cmp = icmp slt i32 %iv, 200 215 br i1 %cmp, label %loop, label %exit 216 217exit: 218 ret void 219} 220 221define void @neg_volatile(ptr %loc) { 222; CHECK-LABEL: @neg_volatile 223; CHECK-LABEL: loop: 224; CHECK: store volatile i32 0, ptr %loc 225; CHECK-LABEL: exit: 226entry: 227 br label %loop 228 229loop: 230 %iv = phi i32 [0, %entry], [%iv.next, %loop] 231 store volatile i32 0, ptr %loc 232 %iv.next = add i32 %iv, 1 233 %cmp = icmp slt i32 %iv, 200 234 br i1 %cmp, label %loop, label %exit 235 236exit: 237 ret void 238} 239 240define void @neg_release(ptr %loc) { 241; CHECK-LABEL: @neg_release 242; CHECK-LABEL: loop: 243; CHECK: store atomic i32 0, ptr %loc release, align 4 244; CHECK-LABEL: exit: 245entry: 246 br label %loop 247 248loop: 249 %iv = phi i32 [0, %entry], [%iv.next, %loop] 250 store atomic i32 0, ptr %loc release, align 4 251 %iv.next = add i32 %iv, 1 252 %cmp = icmp slt i32 %iv, 200 253 br i1 %cmp, label %loop, label %exit 254 255exit: 256 ret void 257} 258 259define void @neg_seq_cst(ptr %loc) { 260; CHECK-LABEL: @neg_seq_cst 261; CHECK-LABEL: loop: 262; CHECK: store atomic i32 0, ptr %loc seq_cst, align 4 263; CHECK-LABEL: exit: 264entry: 265 br label %loop 266 267loop: 268 %iv = phi i32 [0, %entry], [%iv.next, %loop] 269 store atomic i32 0, ptr %loc seq_cst, align 4 270 %iv.next = add i32 %iv, 1 271 %cmp = icmp slt i32 %iv, 200 272 br i1 %cmp, label %loop, label %exit 273 274exit: 275 ret void 276} 277 278declare void @maythrow() inaccessiblememonly 279 280define void @neg_early_exit(ptr %loc) { 281; CHECK-LABEL: @neg_early_exit 282; CHECK-LABEL: body: 283; CHECK: store i32 0, ptr %loc 284; CHECK-LABEL: exit: 285entry: 286 br label %loop 287 288loop: 289 %iv = phi i32 [0, %entry], [%iv.next, %body] 290 %is_null = icmp eq ptr %loc, null 291 br i1 %is_null, label %exit, label %body 292body: 293 call void @maythrow() 294 store i32 0, ptr %loc 295 %iv.next = add i32 %iv, 1 296 %cmp = icmp slt i32 %iv, 200 297 br i1 %cmp, label %loop, label %exit 298 299exit: 300 ret void 301} 302 303define void @neg_early_throw(ptr %loc) { 304; CHECK-LABEL: @neg_early_throw 305; CHECK-LABEL: loop: 306; CHECK: store i32 0, ptr %loc 307; CHECK-LABEL: exit: 308entry: 309 br label %loop 310 311loop: 312 %iv = phi i32 [0, %entry], [%iv.next, %loop] 313 call void @maythrow() 314 store i32 0, ptr %loc 315 %iv.next = add i32 %iv, 1 316 %cmp = icmp slt i32 %iv, 200 317 br i1 %cmp, label %loop, label %exit 318 319exit: 320 ret void 321} 322 323define void @test_late_throw(ptr %loc) { 324; CHECK-LABEL: @test_late_throw 325; CHECK-LABEL: entry: 326; CHECK: store i32 0, ptr %loc 327; CHECK-LABEL: loop: 328entry: 329 br label %loop 330 331loop: 332 %iv = phi i32 [0, %entry], [%iv.next, %loop] 333 store i32 0, ptr %loc 334 call void @maythrow() 335 %iv.next = add i32 %iv, 1 336 %cmp = icmp slt i32 %iv, 200 337 br i1 %cmp, label %loop, label %exit 338 339exit: 340 ret void 341} 342 343; TODO: could validly hoist the store here since we know what value 344; the load must observe. 345define i32 @test_dominated_read(ptr %loc) { 346; CHECK-LABEL: @test_dominated_read 347; CHECK-LABEL: entry: 348; CHECK: store i32 0, ptr %loc 349; CHECK-LABEL: loop: 350entry: 351 br label %loop 352 353loop: 354 %iv = phi i32 [0, %entry], [%iv.next, %loop] 355 store i32 0, ptr %loc 356 %reload = load i32, ptr %loc 357 %iv.next = add i32 %iv, 1 358 %cmp = icmp slt i32 %iv, 200 359 br i1 %cmp, label %loop, label %exit 360 361exit: 362 ret i32 %reload 363} 364 365; TODO: could validly hoist the store since we already hoisted the load and 366; it's no longer in the loop. 367define i32 @test_dominating_read(ptr %loc) { 368; CHECK-LABEL: @test_dominating_read 369; CHECK-LABEL: exit: 370; CHECK: store i32 0, ptr %loc 371entry: 372 br label %loop 373 374loop: 375 %iv = phi i32 [0, %entry], [%iv.next, %loop] 376 %reload = load i32, ptr %loc 377 store i32 0, ptr %loc 378 %iv.next = add i32 %iv, 1 379 %cmp = icmp slt i32 %iv, 200 380 br i1 %cmp, label %loop, label %exit 381 382exit: 383 ret i32 %reload 384} 385 386declare void @readonly() readonly 387 388; TODO: can legally hoist since value read by call is known 389define void @test_dominated_readonly(ptr %loc) { 390; CHECK-LABEL: @test_dominated_readonly 391; CHECK-LABEL: loop: 392; CHECK: store i32 0, ptr %loc 393; CHECK-LABEL: exit: 394entry: 395 br label %loop 396 397loop: 398 %iv = phi i32 [0, %entry], [%iv.next, %loop] 399 store i32 0, ptr %loc 400 call void @readonly() 401 %iv.next = add i32 %iv, 1 402 %cmp = icmp slt i32 %iv, 200 403 br i1 %cmp, label %loop, label %exit 404 405exit: 406 ret void 407} 408 409; While technically possible to hoist the store to %loc, this runs across 410; a funemental limitation of alias sets since both stores and the call are 411; within the same alias set and we can't distinguish them cheaply. 412define void @test_aliasset_fn(ptr %loc, ptr %loc2) { 413; CHECK-LABEL: @test_aliasset_fn 414; CHECK-LABEL: loop: 415; CHECK: store i32 0, ptr %loc 416; CHECK-LABEL: exit: 417entry: 418 br label %loop 419 420loop: 421 %iv = phi i32 [0, %entry], [%iv.next, %loop] 422 store i32 0, ptr %loc 423 call void @readonly() 424 store i32 %iv, ptr %loc2 425 %iv.next = add i32 %iv, 1 426 %cmp = icmp slt i32 %iv, 200 427 br i1 %cmp, label %loop, label %exit 428 429exit: 430 ret void 431} 432 433 434; If we can't tell if the value is read before the write, we can't hoist the 435; write over the potential read (since we don't know the value read) 436define void @neg_may_read(ptr %loc, i1 %maybe) { 437; CHECK-LABEL: @neg_may_read 438; CHECK-LABEL: loop: 439; CHECK: store i32 0, ptr %loc 440; CHECK-LABEL: exit: 441entry: 442 br label %loop 443 444loop: 445 %iv = phi i32 [0, %entry], [%iv.next, %merge] 446 ;; maybe is a placeholder for an unanalyzable condition 447 br i1 %maybe, label %taken, label %merge 448taken: 449 call void @readonly() 450 br label %merge 451merge: 452 store i32 0, ptr %loc 453 %iv.next = add i32 %iv, 1 454 %cmp = icmp slt i32 %iv, 200 455 br i1 %cmp, label %loop, label %exit 456 457exit: 458 ret void 459} 460