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