Home | History | Annotate | Download | only in GuardWidening
      1 ; RUN: opt -S -guard-widening < %s | FileCheck %s
      2 
      3 declare void @llvm.experimental.guard(i1,...)
      4 
      5 define void @f_0(i32 %x, i32* %length_buf) {
      6 ; CHECK-LABEL: @f_0(
      7 ; CHECK-NOT: @llvm.experimental.guard
      8 ; CHECK:  %wide.chk2 = and i1 %chk3, %chk0
      9 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ]
     10 ; CHECK:  ret void
     11 entry:
     12   %length = load i32, i32* %length_buf, !range !0
     13   %chk0 = icmp ult i32 %x, %length
     14   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
     15 
     16   %x.inc1 = add i32 %x, 1
     17   %chk1 = icmp ult i32 %x.inc1, %length
     18   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
     19 
     20   %x.inc2 = add i32 %x, 2
     21   %chk2 = icmp ult i32 %x.inc2, %length
     22   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
     23 
     24   %x.inc3 = add i32 %x, 3
     25   %chk3 = icmp ult i32 %x.inc3, %length
     26   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
     27   ret void
     28 }
     29 
     30 define void @f_1(i32 %x, i32* %length_buf) {
     31 ; CHECK-LABEL: @f_1(
     32 ; CHECK-NOT: llvm.experimental.guard
     33 ; CHECK:  %wide.chk2 = and i1 %chk3, %chk0
     34 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ]
     35 ; CHECK:  ret void
     36 entry:
     37   %length = load i32, i32* %length_buf, !range !0
     38   %chk0 = icmp ult i32 %x, %length
     39   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
     40 
     41   %x.inc1 = add i32 %x, 1
     42   %chk1 = icmp ult i32 %x.inc1, %length
     43   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
     44 
     45   %x.inc2 = add i32 %x.inc1, 2
     46   %chk2 = icmp ult i32 %x.inc2, %length
     47   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
     48 
     49   %x.inc3 = add i32 %x.inc2, 3
     50   %chk3 = icmp ult i32 %x.inc3, %length
     51   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
     52   ret void
     53 }
     54 
     55 define void @f_2(i32 %a, i32* %length_buf) {
     56 ; CHECK-LABEL: @f_2(
     57 ; CHECK-NOT: llvm.experimental.guard
     58 ; CHECK:  %wide.chk2 = and i1 %chk3, %chk0
     59 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ]
     60 ; CHECK:  ret void
     61 entry:
     62   %x = and i32 %a, 4294967040 ;; 4294967040 == 0xffffff00
     63   %length = load i32, i32* %length_buf, !range !0
     64   %chk0 = icmp ult i32 %x, %length
     65   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
     66 
     67   %x.inc1 = or i32 %x, 1
     68   %chk1 = icmp ult i32 %x.inc1, %length
     69   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
     70 
     71   %x.inc2 = or i32 %x, 2
     72   %chk2 = icmp ult i32 %x.inc2, %length
     73   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
     74 
     75   %x.inc3 = or i32 %x, 3
     76   %chk3 = icmp ult i32 %x.inc3, %length
     77   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
     78   ret void
     79 }
     80 
     81 define void @f_3(i32 %a, i32* %length_buf) {
     82 ; CHECK-LABEL: @f_3(
     83 ; CHECK-NOT: llvm.experimental.guard
     84 ; CHECK:  %wide.chk2 = and i1 %chk3, %chk0
     85 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ]
     86 ; CHECK:  ret void
     87 entry:
     88   %x = and i32 %a, 4294967040 ;; 4294967040 == 0xffffff00
     89   %length = load i32, i32* %length_buf, !range !0
     90   %chk0 = icmp ult i32 %x, %length
     91   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
     92 
     93   %x.inc1 = add i32 %x, 1
     94   %chk1 = icmp ult i32 %x.inc1, %length
     95   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
     96 
     97   %x.inc2 = or i32 %x.inc1, 2
     98   %chk2 = icmp ult i32 %x.inc2, %length
     99   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
    100 
    101   %x.inc3 = add i32 %x.inc2, 3
    102   %chk3 = icmp ult i32 %x.inc3, %length
    103   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
    104   ret void
    105 }
    106 
    107 define void @f_4(i32 %x, i32* %length_buf) {
    108 ; CHECK-LABEL: @f_4(
    109 ; CHECK-NOT: llvm.experimental.guard
    110 
    111 ; Note: we NOT guarding on "and i1 %chk3, %chk0", that would be incorrect.
    112 ; CHECK:  %wide.chk2 = and i1 %chk3, %chk1
    113 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ]
    114 ; CHECK:  ret void
    115 entry:
    116   %length = load i32, i32* %length_buf, !range !0
    117   %chk0 = icmp ult i32 %x, %length
    118   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
    119 
    120   %x.inc1 = add i32 %x, -1024
    121   %chk1 = icmp ult i32 %x.inc1, %length
    122   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
    123 
    124   %x.inc2 = add i32 %x, 2
    125   %chk2 = icmp ult i32 %x.inc2, %length
    126   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
    127 
    128   %x.inc3 = add i32 %x, 3
    129   %chk3 = icmp ult i32 %x.inc3, %length
    130   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
    131   ret void
    132 }
    133 
    134 define void @f_5(i32 %x, i32* %length_buf) {
    135 ; CHECK-LABEL: @f_5(
    136 ; CHECK-NOT: llvm.experimental.guard
    137 ; CHECK:  %wide.chk2 = and i1 %chk1, %chk2
    138 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ]
    139 ; CHECK:  ret void
    140 entry:
    141   %length = load i32, i32* %length_buf, !range !0
    142   %chk0 = icmp ult i32 %x, %length
    143   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
    144 
    145   %x.inc1 = add i32 %x, 1
    146   %chk1 = icmp ult i32 %x.inc1, %length
    147   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
    148 
    149   %x.inc2 = add i32 %x.inc1, -200
    150   %chk2 = icmp ult i32 %x.inc2, %length
    151   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
    152 
    153   %x.inc3 = add i32 %x.inc2, 3
    154   %chk3 = icmp ult i32 %x.inc3, %length
    155   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
    156   ret void
    157 }
    158 
    159 
    160 ; Negative test: we can't merge these checks into
    161 ;
    162 ;  (%x + -2147483647) u< L && (%x + 3) u< L
    163 ;
    164 ; because if %length == INT_MAX and %x == -3 then
    165 ;
    166 ; (%x + -2147483647) == i32 2147483646  u< L   (L is 2147483647)
    167 ; (%x + 3) == 0 u< L
    168 ;
    169 ; But (%x + 2) == -1 is not u< L
    170 ;
    171 define void @f_6(i32 %x, i32* %length_buf) {
    172 ; CHECK-LABEL: @f_6(
    173 ; CHECK-NOT: llvm.experimental.guard
    174 ; CHECK:  %wide.chk = and i1 %chk0, %chk1
    175 ; CHECK:  %wide.chk1 = and i1 %wide.chk, %chk2
    176 ; CHECK:  %wide.chk2 = and i1 %wide.chk1, %chk3
    177 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk2) [ "deopt"() ]
    178 entry:
    179   %length = load i32, i32* %length_buf, !range !0
    180   %chk0 = icmp ult i32 %x, %length
    181   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
    182 
    183   %x.inc1 = add i32 %x, -2147483647 ;; -2147483647 == (i32 INT_MIN)+1 == -(i32 INT_MAX)
    184   %chk1 = icmp ult i32 %x.inc1, %length
    185   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
    186 
    187   %x.inc2 = add i32 %x, 2
    188   %chk2 = icmp ult i32 %x.inc2, %length
    189   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
    190 
    191   %x.inc3 = add i32 %x, 3
    192   %chk3 = icmp ult i32 %x.inc3, %length
    193   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
    194   ret void
    195 }
    196 
    197 
    198 define void @f_7(i32 %x, i32* %length_buf) {
    199 ; CHECK-LABEL: @f_7(
    200 
    201 ; CHECK:  [[COND_0:%[^ ]+]] = and i1 %chk3.b, %chk0.b
    202 ; CHECK:  [[COND_1:%[^ ]+]] = and i1 %chk0.a, [[COND_0]]
    203 ; CHECK:  [[COND_2:%[^ ]+]] = and i1 %chk3.a, [[COND_1]]
    204 ; CHECK:  call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ]
    205 
    206 entry:
    207   %length_a = load volatile i32, i32* %length_buf, !range !0
    208   %length_b = load volatile i32, i32* %length_buf, !range !0
    209   %chk0.a = icmp ult i32 %x, %length_a
    210   %chk0.b = icmp ult i32 %x, %length_b
    211   %chk0 = and i1 %chk0.a, %chk0.b
    212   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
    213 
    214   %x.inc1 = add i32 %x, 1
    215   %chk1.a = icmp ult i32 %x.inc1, %length_a
    216   %chk1.b = icmp ult i32 %x.inc1, %length_b
    217   %chk1 = and i1 %chk1.a, %chk1.b
    218   call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
    219 
    220   %x.inc2 = add i32 %x, 2
    221   %chk2.a = icmp ult i32 %x.inc2, %length_a
    222   %chk2.b = icmp ult i32 %x.inc2, %length_b
    223   %chk2 = and i1 %chk2.a, %chk2.b
    224   call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
    225 
    226   %x.inc3 = add i32 %x, 3
    227   %chk3.a = icmp ult i32 %x.inc3, %length_a
    228   %chk3.b = icmp ult i32 %x.inc3, %length_b
    229   %chk3 = and i1 %chk3.a, %chk3.b
    230   call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
    231   ret void
    232 }
    233 
    234 
    235 !0 = !{i32 0, i32 2147483648}
    236