Home | History | Annotate | Download | only in EarlyCSE
      1 ; RUN: opt -S -early-cse < %s | FileCheck %s
      2 
      3 declare void @llvm.experimental.guard(i1,...)
      4 
      5 define i32 @test0(i32* %ptr, i1 %cond) {
      6 ; We can do store to load forwarding over a guard, since it does not
      7 ; clobber memory
      8 
      9 ; CHECK-LABEL: @test0(
     10 ; CHECK-NEXT:  store i32 40, i32* %ptr
     11 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
     12 ; CHECK-NEXT:  ret i32 40
     13 
     14   store i32 40, i32* %ptr
     15   call void(i1,...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
     16   %rval = load i32, i32* %ptr
     17   ret i32 %rval
     18 }
     19 
     20 define i32 @test1(i32* %val, i1 %cond) {
     21 ; We can CSE loads over a guard, since it does not clobber memory
     22 
     23 ; CHECK-LABEL: @test1(
     24 ; CHECK-NEXT:  %val0 = load i32, i32* %val
     25 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
     26 ; CHECK-NEXT:  ret i32 0
     27 
     28   %val0 = load i32, i32* %val
     29   call void(i1,...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
     30   %val1 = load i32, i32* %val
     31   %rval = sub i32 %val0, %val1
     32   ret i32 %rval
     33 }
     34 
     35 define i32 @test2() {
     36 ; Guards on "true" get removed
     37 
     38 ; CHECK-LABEL: @test2(
     39 ; CHECK-NEXT: ret i32 0
     40   call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
     41   ret i32 0
     42 }
     43 
     44 define i32 @test3(i32 %val) {
     45 ; After a guard has executed the condition it was guarding is known to
     46 ; be true.
     47 
     48 ; CHECK-LABEL: @test3(
     49 ; CHECK-NEXT:  %cond0 = icmp slt i32 %val, 40
     50 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ]
     51 ; CHECK-NEXT:  ret i32 -1
     52 
     53   %cond0 = icmp slt i32 %val, 40
     54   call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ]
     55   %cond1 = icmp slt i32 %val, 40
     56   call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
     57 
     58   %cond2 = icmp slt i32 %val, 40
     59   %rval = sext i1 %cond2 to i32
     60   ret i32 %rval
     61 }
     62 
     63 define i32 @test3.unhandled(i32 %val) {
     64 ; After a guard has executed the condition it was guarding is known to
     65 ; be true.
     66 
     67 ; CHECK-LABEL: @test3.unhandled(
     68 ; CHECK-NEXT:  %cond0 = icmp slt i32 %val, 40
     69 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ]
     70 ; CHECK-NEXT:  %cond1 = icmp sge i32 %val, 40
     71 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
     72 ; CHECK-NEXT:  ret i32 0
     73 
     74 ; Demonstrates a case we do not yet handle (it is legal to fold %cond2
     75 ; to false)
     76   %cond0 = icmp slt i32 %val, 40
     77   call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ]
     78   %cond1 = icmp sge i32 %val, 40
     79   call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
     80   ret i32 0
     81 }
     82 
     83 define i32 @test4(i32 %val, i1 %c) {
     84 ; Same as test3, but with some control flow involved.
     85 
     86 ; CHECK-LABEL: @test4(
     87 ; CHECK: entry:
     88 ; CHECK-NEXT:  %cond0 = icmp slt i32 %val, 40
     89 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond0
     90 ; CHECK-NEXT:  br label %bb0
     91 
     92 ; CHECK:     bb0:
     93 ; CHECK-NEXT:  %cond2 = icmp ult i32 %val, 200
     94 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond2
     95 ; CHECK-NEXT:  br i1 %c, label %left, label %right
     96 
     97 ; CHECK:     left:
     98 ; CHECK-NEXT:  ret i32 0
     99 
    100 ; CHECK:     right:
    101 ; CHECK-NEXT:  ret i32 20
    102 
    103 entry:
    104   %cond0 = icmp slt i32 %val, 40
    105   call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ]
    106   %cond1 = icmp slt i32 %val, 40
    107   call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
    108   br label %bb0
    109 
    110 bb0:
    111   %cond2 = icmp ult i32 %val, 200
    112   call void(i1,...) @llvm.experimental.guard(i1 %cond2) [ "deopt"() ]
    113   br i1 %c, label %left, label %right
    114 
    115 left:
    116   %cond3 = icmp ult i32 %val, 200
    117   call void(i1,...) @llvm.experimental.guard(i1 %cond3) [ "deopt"() ]
    118   ret i32 0
    119 
    120 right:
    121  ret i32 20
    122 }
    123 
    124 define i32 @test5(i32 %val, i1 %c) {
    125 ; Same as test4, but the %left block has mutliple predecessors.
    126 
    127 ; CHECK-LABEL: @test5(
    128 
    129 ; CHECK: entry:
    130 ; CHECK-NEXT:  %cond0 = icmp slt i32 %val, 40
    131 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond0
    132 ; CHECK-NEXT:  br label %bb0
    133 
    134 ; CHECK: bb0:
    135 ; CHECK-NEXT:  %cond2 = icmp ult i32 %val, 200
    136 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %cond2
    137 ; CHECK-NEXT:  br i1 %c, label %left, label %right
    138 
    139 ; CHECK: left:
    140 ; CHECK-NEXT:  br label %right
    141 
    142 ; CHECK: right:
    143 ; CHECK-NEXT:  br label %left
    144 
    145 entry:
    146   %cond0 = icmp slt i32 %val, 40
    147   call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ]
    148   %cond1 = icmp slt i32 %val, 40
    149   call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
    150   br label %bb0
    151 
    152 bb0:
    153   %cond2 = icmp ult i32 %val, 200
    154   call void(i1,...) @llvm.experimental.guard(i1 %cond2) [ "deopt"() ]
    155   br i1 %c, label %left, label %right
    156 
    157 left:
    158   %cond3 = icmp ult i32 %val, 200
    159   call void(i1,...) @llvm.experimental.guard(i1 %cond3) [ "deopt"() ]
    160   br label %right
    161 
    162 right:
    163   br label %left
    164 }
    165 
    166 define void @test6(i1 %c, i32* %ptr) {
    167 ; Check that we do not DSE over calls to @llvm.experimental.guard.
    168 ; Guard intrinsics do _read_ memory, so th call to guard below needs
    169 ; to see the store of 500 to %ptr
    170 
    171 ; CHECK-LABEL: @test6(
    172 ; CHECK-NEXT:  store i32 500, i32* %ptr
    173 ; CHECK-NEXT:  call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ]
    174 ; CHECK-NEXT:  store i32 600, i32* %ptr
    175 
    176 
    177   store i32 500, i32* %ptr
    178   call void(i1,...) @llvm.experimental.guard(i1 %c) [ "deopt"() ]
    179   store i32 600, i32* %ptr
    180   ret void
    181 }
    182