1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes 2; RUN: opt < %s -passes=licm -S | FileCheck %s 3; RUN: opt -aa-pipeline=tbaa,basic-aa -passes='require<aa>,require<target-ir>,require<scalar-evolution>,require<opt-remark-emit>,loop-mssa(licm)' -S %s | FileCheck %s 4target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" 5 6@X = global i32 7 ; <ptr> [#uses=4] 7 8define void @test1(i32 %i) { 9; CHECK-LABEL: @test1( 10; CHECK-NEXT: Entry: 11; CHECK-NEXT: [[X_PROMOTED:%.*]] = load i32, ptr @X, align 4 12; CHECK-NEXT: br label [[LOOP:%.*]] 13; CHECK: Loop: 14; CHECK-NEXT: [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ] 15; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ] 16; CHECK-NEXT: [[X2]] = add i32 [[X21]], 1 17; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 18; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 19; CHECK-NEXT: br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]] 20; CHECK: Out: 21; CHECK-NEXT: [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ] 22; CHECK-NEXT: store i32 [[X2_LCSSA]], ptr @X, align 4 23; CHECK-NEXT: ret void 24; 25Entry: 26 br label %Loop 27 28Loop: ; preds = %Loop, %0 29 %j = phi i32 [ 0, %Entry ], [ %Next, %Loop ] ; <i32> [#uses=1] 30 %x = load i32, ptr @X ; <i32> [#uses=1] 31 %x2 = add i32 %x, 1 ; <i32> [#uses=1] 32 store i32 %x2, ptr @X 33 %Next = add i32 %j, 1 ; <i32> [#uses=2] 34 %cond = icmp eq i32 %Next, 0 ; <i1> [#uses=1] 35 br i1 %cond, label %Out, label %Loop 36 37Out: 38 ret void 39} 40 41define void @test2(i32 %i) { 42; CHECK-LABEL: @test2( 43; CHECK-NEXT: Entry: 44; CHECK-NEXT: [[X1:%.*]] = getelementptr i32, ptr @X, i64 1 45; CHECK-NEXT: [[X2:%.*]] = getelementptr i32, ptr @X, i64 1 46; CHECK-NEXT: [[X1_PROMOTED:%.*]] = load i32, ptr [[X1]], align 4 47; CHECK-NEXT: br label [[LOOP:%.*]] 48; CHECK: Loop: 49; CHECK-NEXT: [[A1:%.*]] = phi i32 [ [[V:%.*]], [[LOOP]] ], [ [[X1_PROMOTED]], [[ENTRY:%.*]] ] 50; CHECK-NEXT: [[V]] = add i32 [[A1]], 1 51; CHECK-NEXT: br i1 false, label [[LOOP]], label [[EXIT:%.*]] 52; CHECK: Exit: 53; CHECK-NEXT: [[V_LCSSA:%.*]] = phi i32 [ [[V]], [[LOOP]] ] 54; CHECK-NEXT: store i32 [[V_LCSSA]], ptr [[X1]], align 4 55; CHECK-NEXT: ret void 56; 57Entry: 58 br label %Loop 59 60Loop: ; preds = %Loop, %0 61 %X1 = getelementptr i32, ptr @X, i64 1 ; <ptr> [#uses=1] 62 %A = load i32, ptr %X1 ; <i32> [#uses=1] 63 %V = add i32 %A, 1 ; <i32> [#uses=1] 64 %X2 = getelementptr i32, ptr @X, i64 1 ; <ptr> [#uses=1] 65 store i32 %V, ptr %X2 66 br i1 false, label %Loop, label %Exit 67 68Exit: ; preds = %Loop 69 ret void 70} 71 72define void @test3(i32 %i) { 73; CHECK-LABEL: @test3( 74; CHECK-NEXT: br label [[LOOP:%.*]] 75; CHECK: Loop: 76; CHECK-NEXT: [[X:%.*]] = load volatile i32, ptr @X, align 4 77; CHECK-NEXT: [[X2:%.*]] = add i32 [[X]], 1 78; CHECK-NEXT: store i32 [[X2]], ptr @X, align 4 79; CHECK-NEXT: br i1 true, label [[OUT:%.*]], label [[LOOP]] 80; CHECK: Out: 81; CHECK-NEXT: ret void 82; 83 br label %Loop 84Loop: 85 ; Should not promote this to a register 86 %x = load volatile i32, ptr @X 87 %x2 = add i32 %x, 1 88 store i32 %x2, ptr @X 89 br i1 true, label %Out, label %Loop 90 91Out: ; preds = %Loop 92 ret void 93} 94 95; Should not promote this to a register 96define void @test3b(i32 %i) { 97; CHECK-LABEL: @test3b( 98; CHECK-NEXT: br label [[LOOP:%.*]] 99; CHECK: Loop: 100; CHECK-NEXT: [[X:%.*]] = load i32, ptr @X, align 4 101; CHECK-NEXT: [[X2:%.*]] = add i32 [[X]], 1 102; CHECK-NEXT: store volatile i32 [[X2]], ptr @X, align 4 103; CHECK-NEXT: br i1 true, label [[OUT:%.*]], label [[LOOP]] 104; CHECK: Out: 105; CHECK-NEXT: ret void 106; 107 br label %Loop 108Loop: 109 %x = load i32, ptr @X 110 %x2 = add i32 %x, 1 111 store volatile i32 %x2, ptr @X 112 br i1 true, label %Out, label %Loop 113 114Out: ; preds = %Loop 115 ret void 116} 117 118; PR8041 119; Should have promoted 'handle2' accesses. 120; Should not have promoted offsetx1 loads. 121define void @test4(ptr %x, i8 %n) { 122; CHECK-LABEL: @test4( 123; CHECK-NEXT: [[HANDLE1:%.*]] = alloca ptr, align 8 124; CHECK-NEXT: [[HANDLE2:%.*]] = alloca ptr, align 8 125; CHECK-NEXT: store ptr [[X:%.*]], ptr [[HANDLE1]], align 8 126; CHECK-NEXT: [[TMP:%.*]] = getelementptr i8, ptr [[X]], i64 8 127; CHECK-NEXT: [[OFFSETX1:%.*]] = load ptr, ptr [[HANDLE1]], align 8 128; CHECK-NEXT: br label [[LOOP:%.*]] 129; CHECK: loop: 130; CHECK-NEXT: br label [[SUBLOOP:%.*]] 131; CHECK: subloop: 132; CHECK-NEXT: [[NEWOFFSETX21:%.*]] = phi ptr [ [[TMP]], [[LOOP]] ], [ [[NEWOFFSETX2:%.*]], [[SUBLOOP]] ] 133; CHECK-NEXT: [[COUNT:%.*]] = phi i8 [ 0, [[LOOP]] ], [ [[NEXTCOUNT:%.*]], [[SUBLOOP]] ] 134; CHECK-NEXT: store i8 [[N:%.*]], ptr [[NEWOFFSETX21]], align 1 135; CHECK-NEXT: [[NEWOFFSETX2]] = getelementptr i8, ptr [[NEWOFFSETX21]], i64 -1 136; CHECK-NEXT: [[NEXTCOUNT]] = add i8 [[COUNT]], 1 137; CHECK-NEXT: [[INNEREXITCOND:%.*]] = icmp sge i8 [[NEXTCOUNT]], 8 138; CHECK-NEXT: br i1 [[INNEREXITCOND]], label [[INNEREXIT:%.*]], label [[SUBLOOP]] 139; CHECK: innerexit: 140; CHECK-NEXT: [[NEWOFFSETX2_LCSSA:%.*]] = phi ptr [ [[NEWOFFSETX2]], [[SUBLOOP]] ] 141; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[OFFSETX1]], align 1 142; CHECK-NEXT: [[COND:%.*]] = icmp eq i8 [[VAL]], [[N]] 143; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] 144; CHECK: exit: 145; CHECK-NEXT: [[NEWOFFSETX2_LCSSA_LCSSA:%.*]] = phi ptr [ [[NEWOFFSETX2_LCSSA]], [[INNEREXIT]] ] 146; CHECK-NEXT: store ptr [[NEWOFFSETX2_LCSSA_LCSSA]], ptr [[HANDLE2]], align 8 147; CHECK-NEXT: ret void 148; 149 %handle1 = alloca ptr 150 %handle2 = alloca ptr 151 store ptr %x, ptr %handle1 152 br label %loop 153 154loop: 155 %tmp = getelementptr i8, ptr %x, i64 8 156 store ptr %tmp, ptr %handle2 157 br label %subloop 158 159subloop: 160 %count = phi i8 [ 0, %loop ], [ %nextcount, %subloop ] 161 %offsetx2 = load ptr, ptr %handle2 162 store i8 %n, ptr %offsetx2 163 %newoffsetx2 = getelementptr i8, ptr %offsetx2, i64 -1 164 store ptr %newoffsetx2, ptr %handle2 165 %nextcount = add i8 %count, 1 166 %innerexitcond = icmp sge i8 %nextcount, 8 167 br i1 %innerexitcond, label %innerexit, label %subloop 168 169innerexit: 170 %offsetx1 = load ptr, ptr %handle1 171 %val = load i8, ptr %offsetx1 172 %cond = icmp eq i8 %val, %n 173 br i1 %cond, label %exit, label %loop 174 175exit: 176 ret void 177} 178 179define void @test5(i32 %i, ptr noalias %P2) { 180; CHECK-LABEL: @test5( 181; CHECK-NEXT: Entry: 182; CHECK-NEXT: [[X_PROMOTED:%.*]] = load i32, ptr @X, align 4 183; CHECK-NEXT: br label [[LOOP:%.*]] 184; CHECK: Loop: 185; CHECK-NEXT: [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ] 186; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ] 187; CHECK-NEXT: [[X2]] = add i32 [[X21]], 1 188; CHECK-NEXT: store atomic ptr @X, ptr [[P2:%.*]] monotonic, align 8 189; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 190; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 191; CHECK-NEXT: br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]] 192; CHECK: Out: 193; CHECK-NEXT: [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ] 194; CHECK-NEXT: store i32 [[X2_LCSSA]], ptr @X, align 4 195; CHECK-NEXT: ret void 196; 197Entry: 198 br label %Loop 199 200Loop: ; preds = %Loop, %0 201 %j = phi i32 [ 0, %Entry ], [ %Next, %Loop ] ; <i32> [#uses=1] 202 %x = load i32, ptr @X ; <i32> [#uses=1] 203 %x2 = add i32 %x, 1 ; <i32> [#uses=1] 204 store i32 %x2, ptr @X 205 206 store atomic ptr @X, ptr %P2 monotonic, align 8 207 208 %Next = add i32 %j, 1 ; <i32> [#uses=2] 209 %cond = icmp eq i32 %Next, 0 ; <i1> [#uses=1] 210 br i1 %cond, label %Out, label %Loop 211 212Out: 213 ret void 214 215} 216 217 218; PR14753 - Preserve TBAA tags when promoting values in a loop. 219define void @test6(i32 %n, ptr nocapture %a, ptr %gi) { 220; CHECK-LABEL: @test6( 221; CHECK-NEXT: entry: 222; CHECK-NEXT: store i32 0, ptr [[GI:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]] 223; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[N:%.*]] 224; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_BODY_LR_PH:%.*]], label [[FOR_END:%.*]] 225; CHECK: for.body.lr.ph: 226; CHECK-NEXT: [[GI_PROMOTED:%.*]] = load i32, ptr [[GI]], align 4, !tbaa [[TBAA0]] 227; CHECK-NEXT: br label [[FOR_BODY:%.*]] 228; CHECK: for.body: 229; CHECK-NEXT: [[INC1:%.*]] = phi i32 [ [[GI_PROMOTED]], [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY]] ] 230; CHECK-NEXT: [[STOREMERGE2:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC]], [[FOR_BODY]] ] 231; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[STOREMERGE2]] to i64 232; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, ptr [[A:%.*]], i64 [[IDXPROM]] 233; CHECK-NEXT: store float 0.000000e+00, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4:![0-9]+]] 234; CHECK-NEXT: [[INC]] = add nsw i32 [[INC1]], 1 235; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N]] 236; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]] 237; CHECK: for.cond.for.end_crit_edge: 238; CHECK-NEXT: [[INC_LCSSA:%.*]] = phi i32 [ [[INC]], [[FOR_BODY]] ] 239; CHECK-NEXT: store i32 [[INC_LCSSA]], ptr [[GI]], align 4, !tbaa [[TBAA0]] 240; CHECK-NEXT: br label [[FOR_END]] 241; CHECK: for.end: 242; CHECK-NEXT: ret void 243; 244entry: 245 store i32 0, ptr %gi, align 4, !tbaa !0 246 %cmp1 = icmp slt i32 0, %n 247 br i1 %cmp1, label %for.body.lr.ph, label %for.end 248 249for.body.lr.ph: ; preds = %entry 250 br label %for.body 251 252for.body: ; preds = %for.body.lr.ph, %for.body 253 %storemerge2 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ] 254 %idxprom = sext i32 %storemerge2 to i64 255 %arrayidx = getelementptr inbounds float, ptr %a, i64 %idxprom 256 store float 0.000000e+00, ptr %arrayidx, align 4, !tbaa !3 257 %0 = load i32, ptr %gi, align 4, !tbaa !0 258 %inc = add nsw i32 %0, 1 259 store i32 %inc, ptr %gi, align 4, !tbaa !0 260 %cmp = icmp slt i32 %inc, %n 261 br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge 262 263for.cond.for.end_crit_edge: ; preds = %for.body 264 br label %for.end 265 266for.end: ; preds = %for.cond.for.end_crit_edge, %entry 267 ret void 268 269} 270 271declare i32 @opaque(i32) argmemonly 272declare void @capture(ptr) 273 274; We can promote even if opaque may throw. 275define i32 @test7() { 276; CHECK-LABEL: @test7( 277; CHECK-NEXT: entry: 278; CHECK-NEXT: [[LOCAL:%.*]] = alloca i32, align 4 279; CHECK-NEXT: call void @capture(ptr [[LOCAL]]) 280; CHECK-NEXT: [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4 281; CHECK-NEXT: br label [[LOOP:%.*]] 282; CHECK: loop: 283; CHECK-NEXT: [[X21:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ] 284; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ] 285; CHECK-NEXT: [[X2]] = call i32 @opaque(i32 [[X21]]) 286; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 287; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 288; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] 289; CHECK: exit: 290; CHECK-NEXT: [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ] 291; CHECK-NEXT: store i32 [[X2_LCSSA]], ptr [[LOCAL]], align 4 292; CHECK-NEXT: [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4 293; CHECK-NEXT: ret i32 [[RET]] 294; 295entry: 296 %local = alloca i32 297 call void @capture(ptr %local) 298 br label %loop 299 300loop: 301 %j = phi i32 [ 0, %entry ], [ %next, %loop ] 302 %x = load i32, ptr %local 303 %x2 = call i32 @opaque(i32 %x) ; Note this does not capture %local 304 store i32 %x2, ptr %local 305 %next = add i32 %j, 1 306 %cond = icmp eq i32 %next, 0 307 br i1 %cond, label %exit, label %loop 308 309exit: 310 %ret = load i32, ptr %local 311 ret i32 %ret 312} 313 314; Hoist the load even if we cannot sink the store, since the store is really 315; control-flow dependent. 316define i32 @test7bad() { 317; CHECK-LABEL: @test7bad( 318; CHECK-NEXT: entry: 319; CHECK-NEXT: [[LOCAL:%.*]] = alloca i32, align 4 320; CHECK-NEXT: call void @capture(ptr [[LOCAL]]) 321; CHECK-NEXT: [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4 322; CHECK-NEXT: br label [[LOOP:%.*]] 323; CHECK: loop: 324; CHECK-NEXT: [[X22:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X21:%.*]], [[ELSE:%.*]] ] 325; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[ELSE]] ] 326; CHECK-NEXT: [[X2:%.*]] = call i32 @opaque(i32 [[X22]]) 327; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X2]], 0 328; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[ELSE]] 329; CHECK: if: 330; CHECK-NEXT: store i32 [[X2]], ptr [[LOCAL]], align 4 331; CHECK-NEXT: br label [[ELSE]] 332; CHECK: else: 333; CHECK-NEXT: [[X21]] = phi i32 [ [[X2]], [[IF]] ], [ [[X22]], [[LOOP]] ] 334; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 335; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 336; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] 337; CHECK: exit: 338; CHECK-NEXT: [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4 339; CHECK-NEXT: ret i32 [[RET]] 340; 341entry: 342 %local = alloca i32 343 call void @capture(ptr %local) 344 br label %loop 345loop: 346 %j = phi i32 [ 0, %entry ], [ %next, %else ] 347 %x = load i32, ptr %local 348 %x2 = call i32 @opaque(i32 %x) ; Note this does not capture %local 349 %cmp = icmp eq i32 %x2, 0 350 br i1 %cmp, label %if, label %else 351 352if: 353 store i32 %x2, ptr %local 354 br label %else 355 356else: 357 %next = add i32 %j, 1 358 %cond = icmp eq i32 %next, 0 359 br i1 %cond, label %exit, label %loop 360 361exit: 362 %ret = load i32, ptr %local 363 ret i32 %ret 364} 365 366; Even if neither the load nor the store or guaranteed to execute because 367; opaque() may throw, we can still promote - the load not being guaranteed 368; doesn't block us, because %local is always dereferenceable. 369define i32 @test8() { 370; CHECK-LABEL: @test8( 371; CHECK-NEXT: entry: 372; CHECK-NEXT: [[LOCAL:%.*]] = alloca i32, align 4 373; CHECK-NEXT: call void @capture(ptr [[LOCAL]]) 374; CHECK-NEXT: [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4 375; CHECK-NEXT: br label [[LOOP:%.*]] 376; CHECK: loop: 377; CHECK-NEXT: [[X21:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ] 378; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ] 379; CHECK-NEXT: [[THROWAWAY:%.*]] = call i32 @opaque(i32 [[J]]) 380; CHECK-NEXT: [[X2]] = call i32 @opaque(i32 [[X21]]) 381; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 382; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 383; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] 384; CHECK: exit: 385; CHECK-NEXT: [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ] 386; CHECK-NEXT: store i32 [[X2_LCSSA]], ptr [[LOCAL]], align 4 387; CHECK-NEXT: [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4 388; CHECK-NEXT: ret i32 [[RET]] 389; 390entry: 391 %local = alloca i32 392 call void @capture(ptr %local) 393 br label %loop 394 395loop: 396 %j = phi i32 [ 0, %entry ], [ %next, %loop ] 397 %throwaway = call i32 @opaque(i32 %j) 398 %x = load i32, ptr %local 399 %x2 = call i32 @opaque(i32 %x) 400 store i32 %x2, ptr %local 401 %next = add i32 %j, 1 402 %cond = icmp eq i32 %next, 0 403 br i1 %cond, label %exit, label %loop 404 405exit: 406 %ret = load i32, ptr %local 407 ret i32 %ret 408} 409 410 411; If the store is "guaranteed modulo exceptions", and the load depends on 412; control flow, we can only promote if the pointer is otherwise known to be 413; dereferenceable 414define i32 @test9() { 415; CHECK-LABEL: @test9( 416; CHECK-NEXT: entry: 417; CHECK-NEXT: [[LOCAL:%.*]] = alloca i32, align 4 418; CHECK-NEXT: call void @capture(ptr [[LOCAL]]) 419; CHECK-NEXT: [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4 420; CHECK-NEXT: br label [[LOOP:%.*]] 421; CHECK: loop: 422; CHECK-NEXT: [[X21:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[ELSE:%.*]] ] 423; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[ELSE]] ] 424; CHECK-NEXT: [[J2:%.*]] = call i32 @opaque(i32 [[J]]) 425; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[J2]], 0 426; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[ELSE]] 427; CHECK: if: 428; CHECK-NEXT: br label [[ELSE]] 429; CHECK: else: 430; CHECK-NEXT: [[X2]] = phi i32 [ 0, [[LOOP]] ], [ [[X21]], [[IF]] ] 431; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 432; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 433; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] 434; CHECK: exit: 435; CHECK-NEXT: [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[ELSE]] ] 436; CHECK-NEXT: store i32 [[X2_LCSSA]], ptr [[LOCAL]], align 4 437; CHECK-NEXT: [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4 438; CHECK-NEXT: ret i32 [[RET]] 439; 440entry: 441 %local = alloca i32 442 call void @capture(ptr %local) 443 br label %loop 444 445loop: 446 %j = phi i32 [ 0, %entry ], [ %next, %else ] 447 %j2 = call i32 @opaque(i32 %j) 448 %cmp = icmp eq i32 %j2, 0 449 br i1 %cmp, label %if, label %else 450 451if: 452 %x = load i32, ptr %local 453 br label %else 454 455else: 456 %x2 = phi i32 [ 0, %loop ], [ %x, %if] 457 store i32 %x2, ptr %local 458 %next = add i32 %j, 1 459 %cond = icmp eq i32 %next, 0 460 br i1 %cond, label %exit, label %loop 461 462exit: 463 %ret = load i32, ptr %local 464 ret i32 %ret 465} 466 467define i32 @test9bad(i32 %i) { 468; CHECK-LABEL: @test9bad( 469; CHECK-NEXT: entry: 470; CHECK-NEXT: [[LOCAL:%.*]] = alloca i32, align 4 471; CHECK-NEXT: call void @capture(ptr [[LOCAL]]) 472; CHECK-NEXT: [[NOTDEREF:%.*]] = getelementptr i32, ptr [[LOCAL]], i32 [[I:%.*]] 473; CHECK-NEXT: br label [[LOOP:%.*]] 474; CHECK: loop: 475; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[ELSE:%.*]] ] 476; CHECK-NEXT: [[J2:%.*]] = call i32 @opaque(i32 [[J]]) 477; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[J2]], 0 478; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[ELSE]] 479; CHECK: if: 480; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[NOTDEREF]], align 4 481; CHECK-NEXT: br label [[ELSE]] 482; CHECK: else: 483; CHECK-NEXT: [[X2:%.*]] = phi i32 [ 0, [[LOOP]] ], [ [[X]], [[IF]] ] 484; CHECK-NEXT: store i32 [[X2]], ptr [[NOTDEREF]], align 4 485; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 486; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 487; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]] 488; CHECK: exit: 489; CHECK-NEXT: [[RET:%.*]] = load i32, ptr [[NOTDEREF]], align 4 490; CHECK-NEXT: ret i32 [[RET]] 491; 492entry: 493 %local = alloca i32 494 call void @capture(ptr %local) 495 %notderef = getelementptr i32, ptr %local, i32 %i 496 br label %loop 497 498loop: 499 %j = phi i32 [ 0, %entry ], [ %next, %else ] 500 %j2 = call i32 @opaque(i32 %j) 501 %cmp = icmp eq i32 %j2, 0 502 br i1 %cmp, label %if, label %else 503 504if: 505 %x = load i32, ptr %notderef 506 br label %else 507 508else: 509 %x2 = phi i32 [ 0, %loop ], [ %x, %if] 510 store i32 %x2, ptr %notderef 511 %next = add i32 %j, 1 512 %cond = icmp eq i32 %next, 0 513 br i1 %cond, label %exit, label %loop 514 515exit: 516 %ret = load i32, ptr %notderef 517 ret i32 %ret 518} 519 520define void @test10(i32 %i) { 521; CHECK-LABEL: @test10( 522; CHECK-NEXT: Entry: 523; CHECK-NEXT: [[X_PROMOTED:%.*]] = load atomic i32, ptr @X unordered, align 4 524; CHECK-NEXT: br label [[LOOP:%.*]] 525; CHECK: Loop: 526; CHECK-NEXT: [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ] 527; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ] 528; CHECK-NEXT: [[X2]] = add i32 [[X21]], 1 529; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 530; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 531; CHECK-NEXT: br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]] 532; CHECK: Out: 533; CHECK-NEXT: [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ] 534; CHECK-NEXT: store atomic i32 [[X2_LCSSA]], ptr @X unordered, align 4 535; CHECK-NEXT: ret void 536; 537Entry: 538 br label %Loop 539 540 541Loop: ; preds = %Loop, %0 542 %j = phi i32 [ 0, %Entry ], [ %Next, %Loop ] ; <i32> [#uses=1] 543 %x = load atomic i32, ptr @X unordered, align 4 544 %x2 = add i32 %x, 1 545 store atomic i32 %x2, ptr @X unordered, align 4 546 %Next = add i32 %j, 1 547 %cond = icmp eq i32 %Next, 0 548 br i1 %cond, label %Out, label %Loop 549 550Out: 551 ret void 552 553} 554 555; Early exit is known not to be taken on first iteration and thus doesn't 556; effect whether load is known to execute. 557define void @test11(i32 %i) { 558; CHECK-LABEL: @test11( 559; CHECK-NEXT: Entry: 560; CHECK-NEXT: [[X_PROMOTED:%.*]] = load i32, ptr @X, align 4 561; CHECK-NEXT: br label [[LOOP:%.*]] 562; CHECK: Loop: 563; CHECK-NEXT: [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[BODY:%.*]] ] 564; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[BODY]] ] 565; CHECK-NEXT: [[EARLY_TEST:%.*]] = icmp ult i32 [[J]], 32 566; CHECK-NEXT: br i1 [[EARLY_TEST]], label [[BODY]], label [[EARLY:%.*]] 567; CHECK: body: 568; CHECK-NEXT: [[X2]] = add i32 [[X21]], 1 569; CHECK-NEXT: [[NEXT]] = add i32 [[J]], 1 570; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[NEXT]], 0 571; CHECK-NEXT: br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]] 572; CHECK: Early: 573; CHECK-NEXT: [[X21_LCSSA:%.*]] = phi i32 [ [[X21]], [[LOOP]] ] 574; CHECK-NEXT: store i32 [[X21_LCSSA]], ptr @X, align 4 575; CHECK-NEXT: ret void 576; CHECK: Out: 577; CHECK-NEXT: [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[BODY]] ] 578; CHECK-NEXT: store i32 [[X2_LCSSA]], ptr @X, align 4 579; CHECK-NEXT: ret void 580; 581Entry: 582 br label %Loop 583 584 585Loop: ; preds = %Loop, %0 586 %j = phi i32 [ 0, %Entry ], [ %Next, %body ] ; <i32> [#uses=1] 587 %early.test = icmp ult i32 %j, 32 588 br i1 %early.test, label %body, label %Early 589body: 590 %x = load i32, ptr @X ; <i32> [#uses=1] 591 %x2 = add i32 %x, 1 ; <i32> [#uses=1] 592 store i32 %x2, ptr @X 593 %Next = add i32 %j, 1 ; <i32> [#uses=2] 594 %cond = icmp eq i32 %Next, 0 ; <i1> [#uses=1] 595 br i1 %cond, label %Out, label %Loop 596 597Early: 598 ret void 599Out: 600 ret void 601 602} 603 604define i8 @test_hoistable_existing_load_sinkable_store_writeonly(ptr dereferenceable(8) %ptr, i8 %start) writeonly { 605; CHECK: Function Attrs: memory(write) 606; CHECK-LABEL: @test_hoistable_existing_load_sinkable_store_writeonly( 607; CHECK-NEXT: entry: 608; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i8, ptr [[PTR:%.*]], align 1 609; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 610; CHECK: loop.header: 611; CHECK-NEXT: [[INC1:%.*]] = phi i8 [ [[PTR_PROMOTED]], [[ENTRY:%.*]] ], [ [[INC1]], [[LOOP_LATCH:%.*]] ] 612; CHECK-NEXT: [[I:%.*]] = phi i8 [ [[START:%.*]], [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ] 613; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], 4 614; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] 615; CHECK: loop.latch: 616; CHECK-NEXT: store i8 [[INC1]], ptr [[PTR]], align 1 617; CHECK-NEXT: [[ADD]] = add i8 [[I]], [[INC1]] 618; CHECK-NEXT: br label [[LOOP_HEADER]] 619; CHECK: exit: 620; CHECK-NEXT: [[I_LCSSA:%.*]] = phi i8 [ [[I]], [[LOOP_HEADER]] ] 621; CHECK-NEXT: ret i8 [[I_LCSSA]] 622; 623entry: 624 br label %loop.header 625 626loop.header: 627 %i = phi i8 [ %start, %entry ], [ %add, %loop.latch ] 628 %cmp = icmp ult i8 %i, 4 629 br i1 %cmp, label %loop.latch, label %exit 630 631loop.latch: 632 %div = sdiv i8 %i, 3 633 %inc = load i8, ptr %ptr 634 store i8 %inc, ptr %ptr 635 %add = add i8 %i, %inc 636 br label %loop.header 637 638exit: 639 ret i8 %i 640} 641 642@glb = external global i8, align 1 643 644; Test case for PR51248. 645define void @test_sink_store_only() writeonly { 646; CHECK: Function Attrs: memory(write) 647; CHECK-LABEL: @test_sink_store_only( 648; CHECK-NEXT: entry: 649; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 650; CHECK: loop.header: 651; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ poison, [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] 652; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ] 653; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], 4 654; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] 655; CHECK: loop.latch: 656; CHECK-NEXT: [[DIV]] = sdiv i8 [[I]], 3 657; CHECK-NEXT: [[ADD]] = add i8 [[I]], 4 658; CHECK-NEXT: br label [[LOOP_HEADER]] 659; CHECK: exit: 660; CHECK-NEXT: [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ] 661; CHECK-NEXT: store i8 [[DIV1_LCSSA]], ptr @glb, align 1 662; CHECK-NEXT: ret void 663; 664entry: 665 br label %loop.header 666 667loop.header: 668 %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ] 669 %cmp = icmp ult i8 %i, 4 670 br i1 %cmp, label %loop.latch, label %exit 671 672loop.latch: 673 %div = sdiv i8 %i, 3 674 store i8 %div, ptr @glb, align 1 675 %add = add i8 %i, 4 676 br label %loop.header 677 678exit: 679 ret void 680} 681 682define void @test_sink_store_to_local_object_only_loop_must_execute() writeonly { 683; CHECK: Function Attrs: memory(write) 684; CHECK-LABEL: @test_sink_store_to_local_object_only_loop_must_execute( 685; CHECK-NEXT: entry: 686; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 687; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 688; CHECK: loop.header: 689; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ poison, [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] 690; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ] 691; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], 4 692; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] 693; CHECK: loop.latch: 694; CHECK-NEXT: [[DIV]] = sdiv i8 [[I]], 3 695; CHECK-NEXT: [[ADD]] = add i8 [[I]], 4 696; CHECK-NEXT: br label [[LOOP_HEADER]] 697; CHECK: exit: 698; CHECK-NEXT: [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ] 699; CHECK-NEXT: store i8 [[DIV1_LCSSA]], ptr [[A]], align 1 700; CHECK-NEXT: ret void 701; 702entry: 703 %a = alloca i8 704 br label %loop.header 705 706loop.header: 707 %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ] 708 %cmp = icmp ult i8 %i, 4 709 br i1 %cmp, label %loop.latch, label %exit 710 711loop.latch: 712 %div = sdiv i8 %i, 3 713 store i8 %div, ptr %a, align 1 714 %add = add i8 %i, 4 715 br label %loop.header 716 717exit: 718 ret void 719} 720 721; The store in the loop may not execute, so we need to introduce a load in the 722; pre-header. Make sure the writeonly attribute is dropped. 723define void @test_sink_store_to_local_object_only_loop_may_not_execute(i8 %n) writeonly { 724; CHECK: Function Attrs: memory(write) 725; CHECK-LABEL: @test_sink_store_to_local_object_only_loop_may_not_execute( 726; CHECK-NEXT: entry: 727; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 728; CHECK-NEXT: [[A_PROMOTED:%.*]] = load i8, ptr [[A]], align 1 729; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 730; CHECK: loop.header: 731; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ [[A_PROMOTED]], [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] 732; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ] 733; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], [[N:%.*]] 734; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] 735; CHECK: loop.latch: 736; CHECK-NEXT: [[DIV]] = sdiv i8 [[I]], 3 737; CHECK-NEXT: [[ADD]] = add i8 [[I]], 4 738; CHECK-NEXT: br label [[LOOP_HEADER]] 739; CHECK: exit: 740; CHECK-NEXT: [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ] 741; CHECK-NEXT: store i8 [[DIV1_LCSSA]], ptr [[A]], align 1 742; CHECK-NEXT: ret void 743; 744entry: 745 %a = alloca i8 746 br label %loop.header 747 748loop.header: 749 %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ] 750 %cmp = icmp ult i8 %i, %n 751 br i1 %cmp, label %loop.latch, label %exit 752 753loop.latch: 754 %div = sdiv i8 %i, 3 755 store i8 %div, ptr %a, align 1 756 %add = add i8 %i, 4 757 br label %loop.header 758 759exit: 760 ret void 761} 762 763declare dereferenceable(8) noalias ptr @alloc_writeonly() writeonly 764 765define void @test_sink_store_to_noalias_call_object_only_loop_may_not_execute1(i8 %n) writeonly { 766; CHECK: Function Attrs: memory(write) 767; CHECK-LABEL: @test_sink_store_to_noalias_call_object_only_loop_may_not_execute1( 768; CHECK-NEXT: entry: 769; CHECK-NEXT: [[A:%.*]] = call noalias dereferenceable(8) ptr @alloc_writeonly() 770; CHECK-NEXT: [[A_PROMOTED:%.*]] = load i8, ptr [[A]], align 1 771; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 772; CHECK: loop.header: 773; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ [[A_PROMOTED]], [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] 774; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ] 775; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], [[N:%.*]] 776; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] 777; CHECK: loop.latch: 778; CHECK-NEXT: [[DIV]] = sdiv i8 [[I]], 3 779; CHECK-NEXT: [[ADD]] = add i8 [[I]], 4 780; CHECK-NEXT: br label [[LOOP_HEADER]] 781; CHECK: exit: 782; CHECK-NEXT: [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ] 783; CHECK-NEXT: store i8 [[DIV1_LCSSA]], ptr [[A]], align 1 784; CHECK-NEXT: ret void 785; 786entry: 787 %a = call dereferenceable(8) noalias ptr @alloc_writeonly() 788 br label %loop.header 789 790loop.header: 791 %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ] 792 %cmp = icmp ult i8 %i, %n 793 br i1 %cmp, label %loop.latch, label %exit 794 795loop.latch: 796 %div = sdiv i8 %i, 3 797 store i8 %div, ptr %a, align 1 798 %add = add i8 %i, 4 799 br label %loop.header 800 801exit: 802 ret void 803} 804 805define void @test_sink_store_only_no_phi_needed() writeonly { 806; CHECK: Function Attrs: memory(write) 807; CHECK-LABEL: @test_sink_store_only_no_phi_needed( 808; CHECK-NEXT: entry: 809; CHECK-NEXT: br label [[LOOP:%.*]] 810; CHECK: loop: 811; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[LOOP]] ] 812; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], 4 813; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[I]], 3 814; CHECK-NEXT: [[ADD]] = add i8 [[I]], 4 815; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]] 816; CHECK: exit: 817; CHECK-NEXT: [[DIV_LCSSA:%.*]] = phi i8 [ [[DIV]], [[LOOP]] ] 818; CHECK-NEXT: store i8 [[DIV_LCSSA]], ptr @glb, align 1 819; CHECK-NEXT: ret void 820; 821entry: 822 br label %loop 823 824loop: 825 %i = phi i8 [ 0, %entry ], [ %add, %loop ] 826 %cmp = icmp ult i8 %i, 4 827 %div = sdiv i8 %i, 3 828 store i8 %div, ptr @glb, align 1 829 %add = add i8 %i, 4 830 br i1 %cmp, label %loop, label %exit 831 832exit: 833 ret void 834} 835 836define void @sink_store_lcssa_phis(ptr %ptr, i1 %c) { 837; CHECK-LABEL: @sink_store_lcssa_phis( 838; CHECK-NEXT: entry: 839; CHECK-NEXT: br label [[LOOP_1_HEADER:%.*]] 840; CHECK: loop.1.header: 841; CHECK-NEXT: br label [[LOOP_2_HEADER:%.*]] 842; CHECK: loop.2.header: 843; CHECK-NEXT: br i1 false, label [[LOOP_3_HEADER_PREHEADER:%.*]], label [[LOOP_1_LATCH:%.*]] 844; CHECK: loop.3.header.preheader: 845; CHECK-NEXT: br label [[LOOP_3_HEADER:%.*]] 846; CHECK: loop.3.header: 847; CHECK-NEXT: [[I_11:%.*]] = phi i32 [ [[I_1:%.*]], [[LOOP_3_LATCH:%.*]] ], [ poison, [[LOOP_3_HEADER_PREHEADER]] ] 848; CHECK-NEXT: [[I_1]] = phi i32 [ 1, [[LOOP_3_LATCH]] ], [ 0, [[LOOP_3_HEADER_PREHEADER]] ] 849; CHECK-NEXT: br i1 true, label [[LOOP_3_LATCH]], label [[LOOP_2_LATCH:%.*]] 850; CHECK: loop.3.latch: 851; CHECK-NEXT: br label [[LOOP_3_HEADER]] 852; CHECK: loop.2.latch: 853; CHECK-NEXT: [[I_11_LCSSA:%.*]] = phi i32 [ [[I_11]], [[LOOP_3_HEADER]] ] 854; CHECK-NEXT: store i32 [[I_11_LCSSA]], ptr [[PTR:%.*]], align 4 855; CHECK-NEXT: br label [[LOOP_2_HEADER]] 856; CHECK: loop.1.latch: 857; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP_1_HEADER]], label [[EXIT:%.*]] 858; CHECK: exit: 859; CHECK-NEXT: ret void 860; 861entry: 862 br label %loop.1.header 863 864loop.1.header: 865 br label %loop.2.header 866 867loop.2.header: 868 br i1 false, label %loop.3.header, label %loop.1.latch 869 870loop.3.header: 871 %i.1 = phi i32 [ 1, %loop.3.latch ], [ 0, %loop.2.header ] 872 br i1 true, label %loop.3.latch, label %loop.2.latch 873 874loop.3.latch: 875 store i32 %i.1, ptr %ptr, align 4 876 br label %loop.3.header 877 878loop.2.latch: 879 br label %loop.2.header 880 881loop.1.latch: 882 br i1 %c, label %loop.1.header, label %exit 883 884exit: 885 ret void 886} 887 888define void @cond_store_writable_dereferenceable(ptr noalias writable dereferenceable(4) %ptr) { 889; CHECK-LABEL: @cond_store_writable_dereferenceable( 890; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4 891; CHECK-NEXT: br label [[LOOP:%.*]] 892; CHECK: loop: 893; CHECK-NEXT: [[V_INC1:%.*]] = phi i32 [ [[V_INC:%.*]], [[LOOP_LATCH:%.*]] ], [ [[PTR_PROMOTED]], [[TMP0:%.*]] ] 894; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[V_INC1]], 10 895; CHECK-NEXT: br i1 [[C]], label [[LOOP_LATCH]], label [[EXIT:%.*]] 896; CHECK: loop.latch: 897; CHECK-NEXT: [[V_INC]] = add i32 [[V_INC1]], 1 898; CHECK-NEXT: br label [[LOOP]] 899; CHECK: exit: 900; CHECK-NEXT: [[V_INC1_LCSSA:%.*]] = phi i32 [ [[V_INC1]], [[LOOP]] ] 901; CHECK-NEXT: store i32 [[V_INC1_LCSSA]], ptr [[PTR]], align 4 902; CHECK-NEXT: ret void 903; 904 br label %loop 905 906loop: 907 %v = load i32, ptr %ptr 908 %c = icmp ult i32 %v, 10 909 br i1 %c, label %loop.latch, label %exit 910 911loop.latch: 912 %v.inc = add i32 %v, 1 913 store i32 %v.inc, ptr %ptr 914 br label %loop 915 916exit: 917 ret void 918} 919 920define void @cond_store_writable_not_sufficiently_dereferenceable(ptr noalias writable dereferenceable(2) %ptr) { 921; CHECK-LABEL: @cond_store_writable_not_sufficiently_dereferenceable( 922; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4 923; CHECK-NEXT: br label [[LOOP:%.*]] 924; CHECK: loop: 925; CHECK-NEXT: [[V_INC1:%.*]] = phi i32 [ [[V_INC:%.*]], [[LOOP_LATCH:%.*]] ], [ [[PTR_PROMOTED]], [[TMP0:%.*]] ] 926; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[V_INC1]], 10 927; CHECK-NEXT: br i1 [[C]], label [[LOOP_LATCH]], label [[EXIT:%.*]] 928; CHECK: loop.latch: 929; CHECK-NEXT: [[V_INC]] = add i32 [[V_INC1]], 1 930; CHECK-NEXT: store i32 [[V_INC]], ptr [[PTR]], align 4 931; CHECK-NEXT: br label [[LOOP]] 932; CHECK: exit: 933; CHECK-NEXT: ret void 934; 935 br label %loop 936 937loop: 938 %v = load i32, ptr %ptr 939 %c = icmp ult i32 %v, 10 940 br i1 %c, label %loop.latch, label %exit 941 942loop.latch: 943 %v.inc = add i32 %v, 1 944 store i32 %v.inc, ptr %ptr 945 br label %loop 946 947exit: 948 ret void 949} 950 951!0 = !{!4, !4, i64 0} 952!1 = !{!"omnipotent char", !2} 953!2 = !{!"Simple C/C++ TBAA"} 954!3 = !{!5, !5, i64 0} 955!4 = !{!"int", !1} 956!5 = !{!"float", !1} 957