1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=jump-threading,dce < %s | FileCheck %s 3 4declare void @llvm.experimental.guard(i1, ...) 5 6declare i32 @f1() 7declare i32 @f2() 8 9define i32 @branch_implies_guard(i32 %a) { 10; CHECK-LABEL: @branch_implies_guard( 11; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], 10 12; CHECK-NEXT: br i1 [[COND]], label [[T1_SPLIT:%.*]], label [[F1_SPLIT:%.*]] 13; CHECK: T1.split: 14; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() 15; CHECK-NEXT: [[RETVAL3:%.*]] = add i32 [[V1]], 10 16; CHECK-NEXT: br label [[MERGE:%.*]] 17; CHECK: F1.split: 18; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() 19; CHECK-NEXT: [[RETVAL1:%.*]] = add i32 [[V2]], 10 20; CHECK-NEXT: [[CONDGUARD2:%.*]] = icmp slt i32 [[A]], 20 21; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD2]]) [ "deopt"() ] 22; CHECK-NEXT: br label [[MERGE]] 23; CHECK: Merge: 24; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[RETVAL3]], [[T1_SPLIT]] ], [ [[RETVAL1]], [[F1_SPLIT]] ] 25; CHECK-NEXT: ret i32 [[TMP1]] 26; 27 %cond = icmp slt i32 %a, 10 28 br i1 %cond, label %T1, label %F1 29 30T1: 31 %v1 = call i32 @f1() 32 br label %Merge 33 34F1: 35 %v2 = call i32 @f2() 36 br label %Merge 37 38Merge: 39 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 40 %retVal = add i32 %retPhi, 10 41 %condGuard = icmp slt i32 %a, 20 42 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 43 ret i32 %retVal 44} 45 46define i32 @not_branch_implies_guard(i32 %a) { 47; CHECK-LABEL: @not_branch_implies_guard( 48; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], 20 49; CHECK-NEXT: br i1 [[COND]], label [[T1_SPLIT:%.*]], label [[F1_SPLIT:%.*]] 50; CHECK: T1.split: 51; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() 52; CHECK-NEXT: [[RETVAL1:%.*]] = add i32 [[V1]], 10 53; CHECK-NEXT: [[CONDGUARD2:%.*]] = icmp sgt i32 [[A]], 10 54; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD2]]) [ "deopt"() ] 55; CHECK-NEXT: br label [[MERGE:%.*]] 56; CHECK: F1.split: 57; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() 58; CHECK-NEXT: [[RETVAL3:%.*]] = add i32 [[V2]], 10 59; CHECK-NEXT: br label [[MERGE]] 60; CHECK: Merge: 61; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[RETVAL3]], [[F1_SPLIT]] ], [ [[RETVAL1]], [[T1_SPLIT]] ] 62; CHECK-NEXT: ret i32 [[TMP1]] 63; 64 %cond = icmp slt i32 %a, 20 65 br i1 %cond, label %T1, label %F1 66 67T1: 68 %v1 = call i32 @f1() 69 br label %Merge 70 71F1: 72 %v2 = call i32 @f2() 73 br label %Merge 74 75Merge: 76 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 77 %retVal = add i32 %retPhi, 10 78 %condGuard = icmp sgt i32 %a, 10 79 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 80 ret i32 %retVal 81} 82 83define i32 @branch_overlaps_guard(i32 %a) { 84; CHECK-LABEL: @branch_overlaps_guard( 85; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], 20 86; CHECK-NEXT: br i1 [[COND]], label [[T1:%.*]], label [[F1:%.*]] 87; CHECK: T1: 88; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() 89; CHECK-NEXT: br label [[MERGE:%.*]] 90; CHECK: F1: 91; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() 92; CHECK-NEXT: br label [[MERGE]] 93; CHECK: Merge: 94; CHECK-NEXT: [[RETPHI:%.*]] = phi i32 [ [[V1]], [[T1]] ], [ [[V2]], [[F1]] ] 95; CHECK-NEXT: [[RETVAL:%.*]] = add i32 [[RETPHI]], 10 96; CHECK-NEXT: [[CONDGUARD:%.*]] = icmp slt i32 [[A]], 10 97; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD]]) [ "deopt"() ] 98; CHECK-NEXT: ret i32 [[RETVAL]] 99; 100 %cond = icmp slt i32 %a, 20 101 br i1 %cond, label %T1, label %F1 102 103T1: 104 %v1 = call i32 @f1() 105 br label %Merge 106 107F1: 108 %v2 = call i32 @f2() 109 br label %Merge 110 111Merge: 112 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 113 %retVal = add i32 %retPhi, 10 114 %condGuard = icmp slt i32 %a, 10 115 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 116 ret i32 %retVal 117} 118 119define i32 @branch_doesnt_overlap_guard(i32 %a) { 120; CHECK-LABEL: @branch_doesnt_overlap_guard( 121; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], 10 122; CHECK-NEXT: br i1 [[COND]], label [[T1:%.*]], label [[F1:%.*]] 123; CHECK: T1: 124; CHECK-NEXT: [[V1:%.*]] = call i32 @f1() 125; CHECK-NEXT: br label [[MERGE:%.*]] 126; CHECK: F1: 127; CHECK-NEXT: [[V2:%.*]] = call i32 @f2() 128; CHECK-NEXT: br label [[MERGE]] 129; CHECK: Merge: 130; CHECK-NEXT: [[RETPHI:%.*]] = phi i32 [ [[V1]], [[T1]] ], [ [[V2]], [[F1]] ] 131; CHECK-NEXT: [[RETVAL:%.*]] = add i32 [[RETPHI]], 10 132; CHECK-NEXT: [[CONDGUARD:%.*]] = icmp sgt i32 [[A]], 20 133; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD]]) [ "deopt"() ] 134; CHECK-NEXT: ret i32 [[RETVAL]] 135; 136 %cond = icmp slt i32 %a, 10 137 br i1 %cond, label %T1, label %F1 138 139T1: 140 %v1 = call i32 @f1() 141 br label %Merge 142 143F1: 144 %v2 = call i32 @f2() 145 br label %Merge 146 147Merge: 148 %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] 149 %retVal = add i32 %retPhi, 10 150 %condGuard = icmp sgt i32 %a, 20 151 call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] 152 ret i32 %retVal 153} 154 155define i32 @not_a_diamond1(i32 %a, i1 %cond1) { 156; CHECK-LABEL: @not_a_diamond1( 157; CHECK-NEXT: br i1 [[COND1:%.*]], label [[PRED:%.*]], label [[EXIT:%.*]] 158; CHECK: Pred: 159; CHECK-NEXT: switch i32 [[A:%.*]], label [[EXIT]] [ 160; CHECK-NEXT: i32 10, label [[MERGE:%.*]] 161; CHECK-NEXT: i32 20, label [[MERGE]] 162; CHECK-NEXT: ] 163; CHECK: Merge: 164; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND1]]) [ "deopt"() ] 165; CHECK-NEXT: br label [[EXIT]] 166; CHECK: Exit: 167; CHECK-NEXT: ret i32 [[A]] 168; 169 br i1 %cond1, label %Pred, label %Exit 170 171Pred: 172 switch i32 %a, label %Exit [ 173 i32 10, label %Merge 174 i32 20, label %Merge 175 ] 176 177Merge: 178 call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] 179 br label %Exit 180 181Exit: 182 ret i32 %a 183} 184 185define void @not_a_diamond2(i32 %a, i1 %cond1) { 186; CHECK-LABEL: @not_a_diamond2( 187; CHECK-NEXT: Pred: 188; CHECK-NEXT: switch i32 [[A:%.*]], label [[EXIT:%.*]] [ 189; CHECK-NEXT: i32 10, label [[MERGE:%.*]] 190; CHECK-NEXT: i32 20, label [[MERGE]] 191; CHECK-NEXT: ] 192; CHECK: Merge: 193; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND1:%.*]]) [ "deopt"() ] 194; CHECK-NEXT: ret void 195; CHECK: Exit: 196; CHECK-NEXT: ret void 197; 198 br label %Parent 199 200Merge: 201 call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ] 202 ret void 203 204Pred: 205 switch i32 %a, label %Exit [ 206 i32 10, label %Merge 207 i32 20, label %Merge 208 ] 209 210Parent: 211 br label %Pred 212 213Exit: 214 ret void 215} 216 217declare void @never_called(i1) 218 219; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that 220; guard with guard(true & c1). 221define void @dont_fold_guard(ptr %addr, i32 %i, i32 %length) { 222; CHECK-LABEL: @dont_fold_guard( 223; CHECK-NEXT: BB1: 224; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[I:%.*]], [[LENGTH:%.*]] 225; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[I]], 0 226; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]] 227; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 228; CHECK-NEXT: call void @never_called(i1 true) 229; CHECK-NEXT: ret void 230; 231 %c1 = icmp ult i32 %i, %length 232 %c2 = icmp eq i32 %i, 0 233 %wide.chk = and i1 %c1, %c2 234 call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] 235 br i1 %c2, label %BB1, label %BB2 236 237BB1: 238 call void @never_called(i1 %c2) 239 ret void 240 241BB2: 242 ret void 243} 244 245declare void @dummy(i1) nounwind willreturn 246; same as dont_fold_guard1 but there's a use immediately after guard and before 247; branch. We can fold that use. 248define void @dont_fold_guard2(ptr %addr, i32 %i, i32 %length) { 249; CHECK-LABEL: @dont_fold_guard2( 250; CHECK-NEXT: BB1: 251; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[I:%.*]], [[LENGTH:%.*]] 252; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[I]], 0 253; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]] 254; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 255; CHECK-NEXT: call void @dummy(i1 true) 256; CHECK-NEXT: call void @never_called(i1 true) 257; CHECK-NEXT: ret void 258; 259 %c1 = icmp ult i32 %i, %length 260 %c2 = icmp eq i32 %i, 0 261 %wide.chk = and i1 %c1, %c2 262 call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] 263 call void @dummy(i1 %c2) 264 br i1 %c2, label %BB1, label %BB2 265 266BB1: 267 call void @never_called(i1 %c2) 268 ret void 269 270BB2: 271 ret void 272} 273 274; same as dont_fold_guard1 but condition %cmp is not an instruction. 275; We cannot fold the guard under any circumstance. 276; FIXME: We can merge unreachableBB2 into not_zero. 277define void @dont_fold_guard3(ptr %addr, i1 %cmp, i32 %i, i32 %length) { 278; CHECK-LABEL: @dont_fold_guard3( 279; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CMP:%.*]]) [ "deopt"() ] 280; CHECK-NEXT: br i1 [[CMP]], label [[BB1:%.*]], label [[BB2:%.*]] 281; CHECK: BB1: 282; CHECK-NEXT: call void @never_called(i1 [[CMP]]) 283; CHECK-NEXT: ret void 284; CHECK: BB2: 285; CHECK-NEXT: ret void 286; 287 call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 288 br i1 %cmp, label %BB1, label %BB2 289 290BB1: 291 call void @never_called(i1 %cmp) 292 ret void 293 294BB2: 295 ret void 296} 297 298declare void @f(i1) 299; Same as dont_fold_guard1 but use switch instead of branch. 300; triggers source code `ProcessThreadableEdges`. 301define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind { 302; CHECK-LABEL: @dont_fold_guard4( 303; CHECK-NEXT: entry: 304; CHECK-NEXT: br i1 [[CMP1:%.*]], label [[L2:%.*]], label [[L3:%.*]] 305; CHECK: L2: 306; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 307; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CMP]]) [ "deopt"() ] 308; CHECK-NEXT: call void @dummy(i1 true) 309; CHECK-NEXT: call void @f(i1 true) 310; CHECK-NEXT: ret void 311; CHECK: L3: 312; CHECK-NEXT: ret void 313; 314entry: 315 br i1 %cmp1, label %L0, label %L3 316L0: 317 %cmp = icmp eq i32 %i, 0 318 call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 319 call void @dummy(i1 %cmp) 320 switch i1 %cmp, label %L3 [ 321 i1 false, label %L1 322 i1 true, label %L2 323 ] 324 325L1: 326 ret void 327L2: 328 call void @f(i1 %cmp) 329 ret void 330L3: 331 ret void 332} 333 334; Make sure that we don't PRE a non-speculable load across a guard. 335define void @unsafe_pre_across_guard(ptr %p, i1 %load.is.valid) { 336; CHECK-LABEL: @unsafe_pre_across_guard( 337; CHECK-NEXT: entry: 338; CHECK-NEXT: br label [[LOOP:%.*]] 339; CHECK: loop: 340; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[LOAD_IS_VALID:%.*]]) [ "deopt"() ] 341; CHECK-NEXT: [[LOADED:%.*]] = load i8, ptr [[P:%.*]], align 1 342; CHECK-NEXT: [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0 343; CHECK-NEXT: br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]] 344; CHECK: exit: 345; CHECK-NEXT: ret void 346; 347entry: 348 br label %loop 349 350loop: ; preds = %loop, %entry 351 call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] 352 %loaded = load i8, ptr %p 353 %continue = icmp eq i8 %loaded, 0 354 br i1 %continue, label %exit, label %loop 355 356exit: ; preds = %loop 357 ret void 358} 359 360; Make sure that we can safely PRE a speculable load across a guard. 361define void @safe_pre_across_guard(ptr noalias nocapture readonly dereferenceable(8) %p, i1 %load.is.valid) nofree nosync { 362; CHECK-LABEL: @safe_pre_across_guard( 363; CHECK-NEXT: entry: 364; CHECK-NEXT: [[LOADED_PR:%.*]] = load i8, ptr [[P:%.*]], align 1 365; CHECK-NEXT: br label [[LOOP:%.*]] 366; CHECK: loop: 367; CHECK-NEXT: [[LOADED:%.*]] = phi i8 [ [[LOADED]], [[LOOP]] ], [ [[LOADED_PR]], [[ENTRY:%.*]] ] 368; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[LOAD_IS_VALID:%.*]]) [ "deopt"() ] 369; CHECK-NEXT: [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0 370; CHECK-NEXT: br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]] 371; CHECK: exit: 372; CHECK-NEXT: ret void 373; 374 375entry: 376 br label %loop 377 378loop: ; preds = %loop, %entry 379 call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] 380 %loaded = load i8, ptr %p 381 %continue = icmp eq i8 %loaded, 0 382 br i1 %continue, label %exit, label %loop 383 384exit: ; preds = %loop 385 ret void 386} 387 388; Make sure that we don't PRE a non-speculable load across a call which may 389; alias with the load. 390define void @unsafe_pre_across_call(ptr %p) { 391; CHECK-LABEL: @unsafe_pre_across_call( 392; CHECK-NEXT: entry: 393; CHECK-NEXT: br label [[LOOP:%.*]] 394; CHECK: loop: 395; CHECK-NEXT: [[TMP0:%.*]] = call i32 @f1() 396; CHECK-NEXT: [[LOADED:%.*]] = load i8, ptr [[P:%.*]], align 1 397; CHECK-NEXT: [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0 398; CHECK-NEXT: br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]] 399; CHECK: exit: 400; CHECK-NEXT: ret void 401; 402entry: 403 br label %loop 404 405loop: ; preds = %loop, %entry 406 call i32 @f1() 407 %loaded = load i8, ptr %p 408 %continue = icmp eq i8 %loaded, 0 409 br i1 %continue, label %exit, label %loop 410 411exit: ; preds = %loop 412 ret void 413} 414 415; Make sure that we can safely PRE a speculable load across a call. 416define void @safe_pre_across_call(ptr noalias nocapture readonly dereferenceable(8) %p) nofree nosync { 417; CHECK-LABEL: @safe_pre_across_call( 418; CHECK-NEXT: entry: 419; CHECK-NEXT: [[LOADED_PR:%.*]] = load i8, ptr [[P:%.*]], align 1 420; CHECK-NEXT: br label [[LOOP:%.*]] 421; CHECK: loop: 422; CHECK-NEXT: [[LOADED:%.*]] = phi i8 [ [[LOADED]], [[LOOP]] ], [ [[LOADED_PR]], [[ENTRY:%.*]] ] 423; CHECK-NEXT: [[TMP0:%.*]] = call i32 @f1() 424; CHECK-NEXT: [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0 425; CHECK-NEXT: br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]] 426; CHECK: exit: 427; CHECK-NEXT: ret void 428; 429 430entry: 431 br label %loop 432 433loop: ; preds = %loop, %entry 434 call i32 @f1() 435 %loaded = load i8, ptr %p 436 %continue = icmp eq i8 %loaded, 0 437 br i1 %continue, label %exit, label %loop 438 439exit: ; preds = %loop 440 ret void 441} 442