Home | History | Annotate | Download | only in JumpThreading
      1 ; RUN: opt < %s -jump-threading -dce -S | FileCheck %s
      2 
      3 declare void @llvm.experimental.guard(i1, ...)
      4 
      5 declare i32 @f1()
      6 declare i32 @f2()
      7 
      8 define 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 
     13 T1:
     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 
     21 F1:
     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 
     31 Merge:
     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 
     41 define 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 
     46 T1:
     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 
     56 F1:
     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 
     64 Merge:
     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 
     74 define 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 
     79 T1:
     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 
     86 F1:
     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 
     93 Merge:
     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 
    104 define 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 
    109 T1:
    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 
    116 F1:
    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 
    123 Merge:
    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 
    134 define i32 @not_a_diamond1(i32 %a, i1 %cond1) {
    135 ; CHECK-LABEL: @not_a_diamond1(
    136   br i1 %cond1, label %Pred, label %Exit
    137 
    138 Pred:
    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 
    146 Merge:
    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 
    153 Exit:
    154 ; CHECK:       Exit:
    155 ; CHECK-NEXT:    ret i32 %a
    156   ret i32 %a
    157 }
    158 
    159 define void @not_a_diamond2(i32 %a, i1 %cond1) {
    160 ; CHECK-LABEL: @not_a_diamond2(
    161   br label %Parent
    162 
    163 Merge:
    164   call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ]
    165   ret void
    166 
    167 Pred:
    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 
    175 Parent:
    176   br label %Pred
    177 
    178 Exit:
    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 
    185 declare 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).
    189 define 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 
    201 BB1:
    202   call void @never_called(i1 %c2)
    203   ret void
    204 
    205 BB2:
    206   ret void
    207 }
    208 
    209 declare 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.
    212 define 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 
    226 BB1:
    227   call void @never_called(i1 %c2)
    228   ret void
    229 
    230 BB2:
    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.
    237 define 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 
    243 BB1:
    244   call void @never_called(i1 %cmp)
    245   ret void
    246 
    247 BB2:
    248   ret void
    249 }
    250 
    251 declare void @f(i1)
    252 ; Same as dont_fold_guard1 but use switch instead of branch.
    253 ; triggers source code `ProcessThreadableEdges`.
    254 define 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
    262 entry:
    263   br i1 %cmp1, label %L0, label %L3 
    264 L0:
    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 
    273 L1:
    274   ret void
    275 L2:
    276   call void @f(i1 %cmp)
    277   ret void
    278 L3:
    279   ret void
    280 }
    281 
    282 ; Make sure that we don't PRE a non-speculable load across a guard.
    283 define 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
    294 entry:
    295   br label %loop
    296 
    297 loop:                                             ; 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 
    303 exit:                                             ; preds = %loop
    304   ret void
    305 }
    306 
    307 ; Make sure that we can safely PRE a speculable load across a guard.
    308 define 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 
    320 entry:
    321   br label %loop
    322 
    323 loop:                                             ; 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 
    329 exit:                                             ; 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.
    335 define 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
    346 entry:
    347   br label %loop
    348 
    349 loop:                                             ; 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 
    355 exit:                                             ; preds = %loop
    356   ret void
    357 }
    358 
    359 ; Make sure that we can safely PRE a speculable load across a call.
    360 define 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 
    372 entry:
    373   br label %loop
    374 
    375 loop:                                             ; 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 
    381 exit:                                             ; preds = %loop
    382   ret void
    383 }
    384