1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=guard-widening < %s | FileCheck %s 3; RUN: opt -S -passes=guard-widening < %s | FileCheck %s 4 5declare void @llvm.experimental.guard(i1,...) 6 7; Basic test case: we wide the first check to check both the 8; conditions. 9define void @f_0(i1 %cond_0, i1 %cond_1) { 10; CHECK-LABEL: @f_0( 11; CHECK-NEXT: entry: 12; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]] 13; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]] 14; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 15; CHECK-NEXT: ret void 16; 17entry: 18 19 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 20 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 21 ret void 22} 23 24; Same as @f_0, but with using a more general notion of postdominance. 25define void @f_1(i1 %cond_0, i1 %cond_1, i1 %arg) { 26; CHECK-LABEL: @f_1( 27; CHECK-NEXT: entry: 28; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]] 29; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]] 30; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 31; CHECK-NEXT: br i1 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]] 32; CHECK: left: 33; CHECK-NEXT: br label [[MERGE:%.*]] 34; CHECK: right: 35; CHECK-NEXT: br label [[MERGE]] 36; CHECK: merge: 37; CHECK-NEXT: ret void 38; 39entry: 40 41 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 42 br i1 %arg, label %left, label %right 43 44left: 45 br label %merge 46 47right: 48 br label %merge 49 50merge: 51 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 52 ret void 53} 54 55; Like @f_1, but we have some code we need to hoist before we can 56; widen a dominanting check. 57define void @f_2(i32 %a, i32 %b, i1 %arg) { 58; CHECK-LABEL: @f_2( 59; CHECK-NEXT: entry: 60; CHECK-NEXT: [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]] 61; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 62; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10 63; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] 64; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 65; CHECK-NEXT: br i1 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]] 66; CHECK: left: 67; CHECK-NEXT: br label [[MERGE:%.*]] 68; CHECK: right: 69; CHECK-NEXT: br label [[MERGE]] 70; CHECK: merge: 71; CHECK-NEXT: ret void 72; 73entry: 74 75 %cond_0 = icmp ult i32 %a, 10 76 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 77 br i1 %arg, label %left, label %right 78 79left: 80 br label %merge 81 82right: 83 br label %merge 84 85merge: 86 %cond_1 = icmp ult i32 %b, 10 87 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 88 ret void 89} 90 91; Negative test: don't hoist stuff out of control flow 92; indiscriminately, since that can make us do more work than needed. 93define void @f_3(i32 %a, i32 %b, i1 %arg) { 94; CHECK-LABEL: @f_3( 95; CHECK-NEXT: entry: 96; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 97; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ] 98; CHECK-NEXT: br i1 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]] 99; CHECK: left: 100; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 101; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ] 102; CHECK-NEXT: ret void 103; CHECK: right: 104; CHECK-NEXT: ret void 105; 106entry: 107 108 %cond_0 = icmp ult i32 %a, 10 109 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 110 br i1 %arg, label %left, label %right 111 112left: 113 114 %cond_1 = icmp ult i32 %b, 10 115 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 116 ret void 117 118right: 119 ret void 120} 121 122; But hoisting out of control flow is fine if it makes a loop computed 123; condition loop invariant. This behavior may require some tuning in 124; the future. 125define void @f_4(i32 %a, i32 %b, i1 %arg) { 126; CHECK-LABEL: @f_4( 127; CHECK-NEXT: entry: 128; CHECK-NEXT: [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]] 129; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 130; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10 131; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] 132; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 133; CHECK-NEXT: br i1 %arg, label [[LOOP:%.*]], label [[LEAVE:%.*]] 134; CHECK: loop: 135; CHECK-NEXT: br i1 %arg, label [[LOOP]], label [[LEAVE]] 136; CHECK: leave: 137; CHECK-NEXT: ret void 138; 139entry: 140 141 %cond_0 = icmp ult i32 %a, 10 142 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 143 br i1 %arg, label %loop, label %leave 144 145loop: 146 %cond_1 = icmp ult i32 %b, 10 147 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 148 br i1 %arg, label %loop, label %leave 149 150leave: 151 ret void 152} 153 154; Hoisting out of control flow is also fine if we can widen the 155; dominating check without doing any extra work. 156define void @f_5(i32 %a, i1 %arg) { 157; CHECK-LABEL: @f_5( 158; CHECK-NEXT: entry: 159; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[A:%.*]], 7 160; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[A]], 11 161; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 162; CHECK-NEXT: br i1 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]] 163; CHECK: left: 164; CHECK-NEXT: [[COND_1:%.*]] = icmp ugt i32 [[A]], 10 165; CHECK-NEXT: ret void 166; CHECK: right: 167; CHECK-NEXT: ret void 168; 169entry: 170 171 %cond_0 = icmp ugt i32 %a, 7 172 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 173 br i1 %arg, label %left, label %right 174 175left: 176 %cond_1 = icmp ugt i32 %a, 10 177 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 178 ret void 179 180right: 181 ret void 182} 183 184; Negative test: the load from %a can be safely speculated to before 185; the first guard, but there is no guarantee that it will produce the 186; same value. 187define void @f_6(ptr dereferenceable(32) %a, ptr %b, i1 %unknown) { 188; CHECK-LABEL: @f_6( 189; CHECK-NEXT: entry: 190; CHECK-NEXT: [[COND_0:%.*]] = load i1, ptr [[A:%.*]], align 1 191; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ] 192; CHECK-NEXT: store i1 [[UNKNOWN:%.*]], ptr [[B:%.*]], align 1 193; CHECK-NEXT: [[COND_1:%.*]] = load i1, ptr [[A]], align 1 194; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ] 195; CHECK-NEXT: ret void 196; 197entry: 198 %cond_0 = load i1, ptr %a 199 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 200 store i1 %unknown, ptr %b 201 %cond_1 = load i1, ptr %a 202 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 203 ret void 204} 205 206; All else equal, we try to widen the earliest guard we can. This 207; heuristic can use some tuning. 208define void @f_7(i32 %a, ptr %cond_buf, i1 %arg) { 209; CHECK-LABEL: @f_7( 210; CHECK-NEXT: entry: 211; CHECK-NEXT: [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]] 212; CHECK-NEXT: [[COND_1:%.*]] = load volatile i1, ptr [[COND_BUF:%.*]], align 1 213; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7 214; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]] 215; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 216; CHECK-NEXT: [[COND_2:%.*]] = load volatile i1, ptr [[COND_BUF]], align 1 217; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ] 218; CHECK-NEXT: br i1 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]] 219; CHECK: left: 220; CHECK-NEXT: br label [[LEFT]] 221; CHECK: right: 222; CHECK-NEXT: ret void 223; 224entry: 225 226 %cond_1 = load volatile i1, ptr %cond_buf 227 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 228 %cond_2 = load volatile i1, ptr %cond_buf 229 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ] 230 br i1 %arg, label %left, label %right 231 232left: 233 %cond_3 = icmp ult i32 %a, 7 234 call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ] 235 br label %left 236 237right: 238 ret void 239} 240 241; In this case the earliest dominating guard is in a loop, and we 242; don't want to put extra work in there. This heuristic can use some 243; tuning. 244define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2, i1 %arg) { 245; CHECK-LABEL: @f_8( 246; CHECK-NEXT: entry: 247; CHECK-NEXT: [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]] 248; CHECK-NEXT: br label [[LOOP:%.*]] 249; CHECK: loop: 250; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ] 251; CHECK-NEXT: br i1 %arg, label [[LOOP]], label [[LEAVE:%.*]] 252; CHECK: leave: 253; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7 254; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]] 255; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 256; CHECK-NEXT: br i1 %arg, label [[LOOP2:%.*]], label [[LEAVE2:%.*]] 257; CHECK: loop2: 258; CHECK-NEXT: br label [[LOOP2]] 259; CHECK: leave2: 260; CHECK-NEXT: ret void 261; 262entry: 263 br label %loop 264 265loop: 266 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 267 br i1 %arg, label %loop, label %leave 268 269leave: 270 271 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ] 272 br i1 %arg, label %loop2, label %leave2 273 274loop2: 275 %cond_3 = icmp ult i32 %a, 7 276 call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ] 277 br label %loop2 278 279leave2: 280 ret void 281} 282 283; In cases like these where there isn't any "obviously profitable" 284; widening sites, we refuse to do anything. 285define void @f_9(i32 %a, i1 %cond_0, i1 %cond_1, i1 %arg) { 286; CHECK-LABEL: @f_9( 287; CHECK-NEXT: entry: 288; CHECK-NEXT: br label [[FIRST_LOOP:%.*]] 289; CHECK: first_loop: 290; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] 291; CHECK-NEXT: br i1 %arg, label [[FIRST_LOOP]], label [[SECOND_LOOP:%.*]] 292; CHECK: second_loop: 293; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ] 294; CHECK-NEXT: br label [[SECOND_LOOP]] 295; 296entry: 297 br label %first_loop 298 299first_loop: 300 301 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 302 br i1 %arg, label %first_loop, label %second_loop 303 304second_loop: 305 306 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 307 br label %second_loop 308} 309 310; Same situation as in @f_9: no "obviously profitable" widening sites, 311; so we refuse to do anything. 312define void @f_10(i32 %a, i1 %cond_0, i1 %cond_1, i1 %arg) { 313; CHECK-LABEL: @f_10( 314; CHECK-NEXT: entry: 315; CHECK-NEXT: br label [[LOOP:%.*]] 316; CHECK: loop: 317; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] 318; CHECK-NEXT: br i1 %arg, label [[LOOP]], label [[NO_LOOP:%.*]] 319; CHECK: no_loop: 320; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ] 321; CHECK-NEXT: ret void 322; 323entry: 324 br label %loop 325 326loop: 327 328 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 329 br i1 %arg, label %loop, label %no_loop 330 331no_loop: 332 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 333 ret void 334} 335 336; With guards in loops, we're okay hoisting out the guard into the 337; containing loop. 338define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1, i1 %arg) { 339; CHECK-LABEL: @f_11( 340; CHECK-NEXT: entry: 341; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]] 342; CHECK-NEXT: br label [[INNER:%.*]] 343; CHECK: inner: 344; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]] 345; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 346; CHECK-NEXT: br i1 %arg, label [[INNER]], label [[OUTER:%.*]] 347; CHECK: outer: 348; CHECK-NEXT: br label [[INNER]] 349; 350entry: 351 br label %inner 352 353inner: 354 355 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 356 br i1 %arg, label %inner, label %outer 357 358outer: 359 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 360 br label %inner 361} 362 363; Checks that we are adequately guarded against exponential-time 364; behavior when hoisting code. 365define void @f_12(i32 %a0) { 366; CHECK-LABEL: @f_12( 367; CHECK-NEXT: entry: 368; CHECK-NEXT: [[A0_GW_FR:%.*]] = freeze i32 [[A0:%.*]] 369; CHECK-NEXT: [[A1:%.*]] = mul i32 [[A0_GW_FR]], [[A0_GW_FR]] 370; CHECK-NEXT: [[A2:%.*]] = mul i32 [[A1]], [[A1]] 371; CHECK-NEXT: [[A3:%.*]] = mul i32 [[A2]], [[A2]] 372; CHECK-NEXT: [[A4:%.*]] = mul i32 [[A3]], [[A3]] 373; CHECK-NEXT: [[A5:%.*]] = mul i32 [[A4]], [[A4]] 374; CHECK-NEXT: [[A6:%.*]] = mul i32 [[A5]], [[A5]] 375; CHECK-NEXT: [[A7:%.*]] = mul i32 [[A6]], [[A6]] 376; CHECK-NEXT: [[A8:%.*]] = mul i32 [[A7]], [[A7]] 377; CHECK-NEXT: [[A9:%.*]] = mul i32 [[A8]], [[A8]] 378; CHECK-NEXT: [[A10:%.*]] = mul i32 [[A9]], [[A9]] 379; CHECK-NEXT: [[A11:%.*]] = mul i32 [[A10]], [[A10]] 380; CHECK-NEXT: [[A12:%.*]] = mul i32 [[A11]], [[A11]] 381; CHECK-NEXT: [[A13:%.*]] = mul i32 [[A12]], [[A12]] 382; CHECK-NEXT: [[A14:%.*]] = mul i32 [[A13]], [[A13]] 383; CHECK-NEXT: [[A15:%.*]] = mul i32 [[A14]], [[A14]] 384; CHECK-NEXT: [[A16:%.*]] = mul i32 [[A15]], [[A15]] 385; CHECK-NEXT: [[A17:%.*]] = mul i32 [[A16]], [[A16]] 386; CHECK-NEXT: [[A18:%.*]] = mul i32 [[A17]], [[A17]] 387; CHECK-NEXT: [[A19:%.*]] = mul i32 [[A18]], [[A18]] 388; CHECK-NEXT: [[A20:%.*]] = mul i32 [[A19]], [[A19]] 389; CHECK-NEXT: [[A21:%.*]] = mul i32 [[A20]], [[A20]] 390; CHECK-NEXT: [[A22:%.*]] = mul i32 [[A21]], [[A21]] 391; CHECK-NEXT: [[A23:%.*]] = mul i32 [[A22]], [[A22]] 392; CHECK-NEXT: [[A24:%.*]] = mul i32 [[A23]], [[A23]] 393; CHECK-NEXT: [[A25:%.*]] = mul i32 [[A24]], [[A24]] 394; CHECK-NEXT: [[A26:%.*]] = mul i32 [[A25]], [[A25]] 395; CHECK-NEXT: [[A27:%.*]] = mul i32 [[A26]], [[A26]] 396; CHECK-NEXT: [[A28:%.*]] = mul i32 [[A27]], [[A27]] 397; CHECK-NEXT: [[A29:%.*]] = mul i32 [[A28]], [[A28]] 398; CHECK-NEXT: [[A30:%.*]] = mul i32 [[A29]], [[A29]] 399; CHECK-NEXT: [[COND:%.*]] = trunc i32 [[A30]] to i1 400; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND]] 401; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 402; CHECK-NEXT: ret void 403; 404 405; Eliding the earlier 29 multiplications for brevity 406 407entry: 408 call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] 409 %a1 = mul i32 %a0, %a0 410 %a2 = mul i32 %a1, %a1 411 %a3 = mul i32 %a2, %a2 412 %a4 = mul i32 %a3, %a3 413 %a5 = mul i32 %a4, %a4 414 %a6 = mul i32 %a5, %a5 415 %a7 = mul i32 %a6, %a6 416 %a8 = mul i32 %a7, %a7 417 %a9 = mul i32 %a8, %a8 418 %a10 = mul i32 %a9, %a9 419 %a11 = mul i32 %a10, %a10 420 %a12 = mul i32 %a11, %a11 421 %a13 = mul i32 %a12, %a12 422 %a14 = mul i32 %a13, %a13 423 %a15 = mul i32 %a14, %a14 424 %a16 = mul i32 %a15, %a15 425 %a17 = mul i32 %a16, %a16 426 %a18 = mul i32 %a17, %a17 427 %a19 = mul i32 %a18, %a18 428 %a20 = mul i32 %a19, %a19 429 %a21 = mul i32 %a20, %a20 430 %a22 = mul i32 %a21, %a21 431 %a23 = mul i32 %a22, %a22 432 %a24 = mul i32 %a23, %a23 433 %a25 = mul i32 %a24, %a24 434 %a26 = mul i32 %a25, %a25 435 %a27 = mul i32 %a26, %a26 436 %a28 = mul i32 %a27, %a27 437 %a29 = mul i32 %a28, %a28 438 %a30 = mul i32 %a29, %a29 439 %cond = trunc i32 %a30 to i1 440 call void(i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 441 ret void 442} 443 444define void @f_13(i32 %a, i1 %arg) { 445; CHECK-LABEL: @f_13( 446; CHECK-NEXT: entry: 447; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14 448; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp ult i32 [[A]], 10 449; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] 450; CHECK-NEXT: br i1 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]] 451; CHECK: left: 452; CHECK-NEXT: [[COND_1:%.*]] = icmp slt i32 [[A]], 10 453; CHECK-NEXT: ret void 454; CHECK: right: 455; CHECK-NEXT: ret void 456; 457entry: 458 459 %cond_0 = icmp ult i32 %a, 14 460 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 461 br i1 %arg, label %left, label %right 462 463left: 464 %cond_1 = icmp slt i32 %a, 10 465 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 466 ret void 467 468right: 469 ret void 470} 471 472define void @f_14(i32 %a, i1 %arg) { 473; CHECK-LABEL: @f_14( 474; CHECK-NEXT: entry: 475; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14 476; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ] 477; CHECK-NEXT: br i1 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]] 478; CHECK: left: 479; CHECK-NEXT: [[COND_1:%.*]] = icmp sgt i32 [[A]], 10 480; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ] 481; CHECK-NEXT: ret void 482; CHECK: right: 483; CHECK-NEXT: ret void 484; 485entry: 486 487 %cond_0 = icmp ult i32 %a, 14 488 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 489 br i1 %arg, label %left, label %right 490 491left: 492 493 %cond_1 = icmp sgt i32 %a, 10 494 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] 495 ret void 496 497right: 498 ret void 499} 500 501; Make sure we do not widen guard by trivial true conditions into something. 502define void @f_15(i1 %cond_0, i1 %cond_1) { 503; CHECK-LABEL: @f_15( 504; CHECK-NEXT: entry: 505; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] 506; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] 507; CHECK-NEXT: ret void 508; 509entry: 510 511 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 512 call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] 513 ret void 514} 515 516; Make sure we do not widen guard by trivial false conditions into something. 517define void @f_16(i1 %cond_0, i1 %cond_1) { 518; CHECK-LABEL: @f_16( 519; CHECK-NEXT: entry: 520; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] 521; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 522; CHECK-NEXT: ret void 523; 524entry: 525 526 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] 527 call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] 528 ret void 529} 530