Home | History | Annotate | Download | only in InstSimplify
      1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
      2 ; RUN: opt < %s -instsimplify -S | FileCheck %s
      3 
      4 ;; x * 0 ==> 0 when no-nans and no-signed-zero
      5 define float @mul_zero_1(float %a) {
      6 ; CHECK-LABEL: @mul_zero_1(
      7 ; CHECK-NEXT:    ret float 0.000000e+00
      8 ;
      9   %b = fmul nsz nnan float %a, 0.0
     10   ret float %b
     11 }
     12 
     13 define float @mul_zero_2(float %a) {
     14 ; CHECK-LABEL: @mul_zero_2(
     15 ; CHECK-NEXT:    ret float 0.000000e+00
     16 ;
     17   %b = fmul fast float 0.0, %a
     18   ret float %b
     19 }
     20 
     21 define <2 x float> @mul_zero_nsz_nnan_vec_undef(<2 x float> %a) {
     22 ; CHECK-LABEL: @mul_zero_nsz_nnan_vec_undef(
     23 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
     24 ;
     25   %b = fmul nsz nnan <2 x float> %a, <float 0.0, float undef>
     26   ret <2 x float> %b
     27 }
     28 
     29 ;; x * 0 =/=> 0 when there could be nans or -0
     30 define float @no_mul_zero_1(float %a) {
     31 ; CHECK-LABEL: @no_mul_zero_1(
     32 ; CHECK-NEXT:    [[B:%.*]] = fmul nsz float [[A:%.*]], 0.000000e+00
     33 ; CHECK-NEXT:    ret float [[B]]
     34 ;
     35   %b = fmul nsz float %a, 0.0
     36   ret float %b
     37 }
     38 
     39 define float @no_mul_zero_2(float %a) {
     40 ; CHECK-LABEL: @no_mul_zero_2(
     41 ; CHECK-NEXT:    [[B:%.*]] = fmul nnan float [[A:%.*]], 0.000000e+00
     42 ; CHECK-NEXT:    ret float [[B]]
     43 ;
     44   %b = fmul nnan float %a, 0.0
     45   ret float %b
     46 }
     47 
     48 define float @no_mul_zero_3(float %a) {
     49 ; CHECK-LABEL: @no_mul_zero_3(
     50 ; CHECK-NEXT:    [[B:%.*]] = fmul float [[A:%.*]], 0.000000e+00
     51 ; CHECK-NEXT:    ret float [[B]]
     52 ;
     53   %b = fmul float %a, 0.0
     54   ret float %b
     55 }
     56 
     57 ; -X + X --> 0.0 (with nnan on the fadd)
     58 
     59 define float @fadd_fnegx(float %x) {
     60 ; CHECK-LABEL: @fadd_fnegx(
     61 ; CHECK-NEXT:    ret float 0.000000e+00
     62 ;
     63   %negx = fsub float -0.0, %x
     64   %r = fadd nnan float %negx, %x
     65   ret float %r
     66 }
     67 
     68 ; X + -X --> 0.0 (with nnan on the fadd)
     69 
     70 define <2 x float> @fadd_fnegx_commute_vec(<2 x float> %x) {
     71 ; CHECK-LABEL: @fadd_fnegx_commute_vec(
     72 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
     73 ;
     74   %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
     75   %r = fadd nnan <2 x float> %x, %negx
     76   ret <2 x float> %r
     77 }
     78 
     79 define <2 x float> @fadd_fnegx_commute_vec_undef(<2 x float> %x) {
     80 ; CHECK-LABEL: @fadd_fnegx_commute_vec_undef(
     81 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
     82 ;
     83   %negx = fsub <2 x float> <float undef, float -0.0>, %x
     84   %r = fadd nnan <2 x float> %x, %negx
     85   ret <2 x float> %r
     86 }
     87 
     88 ; https://bugs.llvm.org/show_bug.cgi?id=26958
     89 ; https://bugs.llvm.org/show_bug.cgi?id=27151
     90 
     91 define float @fadd_fneg_nan(float %x) {
     92 ; CHECK-LABEL: @fadd_fneg_nan(
     93 ; CHECK-NEXT:    [[T:%.*]] = fsub nnan float -0.000000e+00, [[X:%.*]]
     94 ; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd ninf float [[T]], [[X]]
     95 ; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
     96 ;
     97   %t = fsub nnan float -0.0, %x
     98   %could_be_nan = fadd ninf float %t, %x
     99   ret float %could_be_nan
    100 }
    101 
    102 define float @fadd_fneg_nan_commute(float %x) {
    103 ; CHECK-LABEL: @fadd_fneg_nan_commute(
    104 ; CHECK-NEXT:    [[T:%.*]] = fsub nnan ninf float -0.000000e+00, [[X:%.*]]
    105 ; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd float [[X]], [[T]]
    106 ; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
    107 ;
    108   %t = fsub nnan ninf float -0.0, %x
    109   %could_be_nan = fadd float %x, %t
    110   ret float %could_be_nan
    111 }
    112 
    113 ; X + (0.0 - X) --> 0.0 (with nnan on the fadd)
    114 
    115 define float @fadd_fsub_nnan_ninf(float %x) {
    116 ; CHECK-LABEL: @fadd_fsub_nnan_ninf(
    117 ; CHECK-NEXT:    ret float 0.000000e+00
    118 ;
    119   %sub = fsub float 0.0, %x
    120   %zero = fadd nnan ninf float %x, %sub
    121   ret float %zero
    122 }
    123 
    124 ; (0.0 - X) + X --> 0.0 (with nnan on the fadd)
    125 
    126 define <2 x float> @fadd_fsub_nnan_ninf_commute_vec(<2 x float> %x) {
    127 ; CHECK-LABEL: @fadd_fsub_nnan_ninf_commute_vec(
    128 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
    129 ;
    130   %sub = fsub <2 x float> zeroinitializer, %x
    131   %zero = fadd nnan ninf <2 x float> %sub, %x
    132   ret <2 x float> %zero
    133 }
    134 
    135 ; 'ninf' is not required because 'nnan' allows us to assume
    136 ; that X is not INF or -INF (adding opposite INFs would be NaN).
    137 
    138 define float @fadd_fsub_nnan(float %x) {
    139 ; CHECK-LABEL: @fadd_fsub_nnan(
    140 ; CHECK-NEXT:    ret float 0.000000e+00
    141 ;
    142   %sub = fsub float 0.0, %x
    143   %zero = fadd nnan float %sub, %x
    144   ret float %zero
    145 }
    146 
    147 ; fsub nnan x, x ==> 0.0
    148 define float @fsub_x_x(float %a) {
    149 ; CHECK-LABEL: @fsub_x_x(
    150 ; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fsub ninf float [[A:%.*]], [[A]]
    151 ; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fsub float [[A]], [[A]]
    152 ; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
    153 ; CHECK-NEXT:    ret float [[NO_ZERO]]
    154 ;
    155 ; X - X ==> 0
    156   %zero1 = fsub nnan float %a, %a
    157 
    158 ; Dont fold
    159   %no_zero1 = fsub ninf float %a, %a
    160   %no_zero2 = fsub float %a, %a
    161   %no_zero = fadd float %no_zero1, %no_zero2
    162 
    163 ; Should get folded
    164   %ret = fadd nsz float %no_zero, %zero1
    165 
    166   ret float %ret
    167 }
    168 
    169 ; fsub nsz 0.0, (fsub 0.0, X) ==> X
    170 define float @fsub_0_0_x(float %a) {
    171 ; CHECK-LABEL: @fsub_0_0_x(
    172 ; CHECK-NEXT:    ret float [[A:%.*]]
    173 ;
    174   %t1 = fsub float 0.0, %a
    175   %ret = fsub nsz float 0.0, %t1
    176   ret float %ret
    177 }
    178 
    179 define <2 x float> @fsub_0_0_x_vec_undef1(<2 x float> %a) {
    180 ; CHECK-LABEL: @fsub_0_0_x_vec_undef1(
    181 ; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
    182 ;
    183   %t1 = fsub <2 x float> <float 0.0, float undef>, %a
    184   %ret = fsub nsz <2 x float> zeroinitializer, %t1
    185   ret <2 x float> %ret
    186 }
    187 
    188 define <2 x float> @fsub_0_0_x_vec_undef2(<2 x float> %a) {
    189 ; CHECK-LABEL: @fsub_0_0_x_vec_undef2(
    190 ; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
    191 ;
    192   %t1 = fsub <2 x float> zeroinitializer, %a
    193   %ret = fsub nsz <2 x float> <float undef, float -0.0>, %t1
    194   ret <2 x float> %ret
    195 }
    196 
    197 ; fadd nsz X, 0 ==> X
    198 
    199 define <2 x float> @fadd_zero_nsz_vec(<2 x float> %x) {
    200 ; CHECK-LABEL: @fadd_zero_nsz_vec(
    201 ; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
    202 ;
    203   %r = fadd nsz <2 x float> %x, zeroinitializer
    204   ret <2 x float> %r
    205 }
    206 
    207 define <2 x float> @fadd_zero_nsz_vec_undef(<2 x float> %x) {
    208 ; CHECK-LABEL: @fadd_zero_nsz_vec_undef(
    209 ; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
    210 ;
    211   %r = fadd nsz <2 x float> %x, <float 0.0, float undef>
    212   ret <2 x float> %r
    213 }
    214 
    215 define float @nofold_fadd_x_0(float %a) {
    216 ; CHECK-LABEL: @nofold_fadd_x_0(
    217 ; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fadd ninf float [[A:%.*]], 0.000000e+00
    218 ; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fadd nnan float [[A]], 0.000000e+00
    219 ; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
    220 ; CHECK-NEXT:    ret float [[NO_ZERO]]
    221 ;
    222 ; Dont fold
    223   %no_zero1 = fadd ninf float %a, 0.0
    224   %no_zero2 = fadd nnan float %a, 0.0
    225   %no_zero = fadd float %no_zero1, %no_zero2
    226   ret float %no_zero
    227 }
    228 
    229 ; fdiv nsz nnan 0, X ==> 0
    230 ; 0 / X -> 0
    231 
    232 define double @fdiv_zero_by_x(double %x) {
    233 ; CHECK-LABEL: @fdiv_zero_by_x(
    234 ; CHECK-NEXT:    ret double 0.000000e+00
    235 ;
    236   %r = fdiv nnan nsz double 0.0, %x
    237   ret double %r
    238 }
    239 
    240 define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) {
    241 ; CHECK-LABEL: @fdiv_zero_by_x_vec_undef(
    242 ; CHECK-NEXT:    ret <2 x double> zeroinitializer
    243 ;
    244   %r = fdiv nnan nsz <2 x double> <double 0.0, double undef>, %x
    245   ret <2 x double> %r
    246 }
    247 
    248 ; 0 % X -> 0
    249 ; nsz is not necessary - frem result always has the sign of the dividend
    250 
    251 define double @frem_zero_by_x(double %x) {
    252 ; CHECK-LABEL: @frem_zero_by_x(
    253 ; CHECK-NEXT:    ret double 0.000000e+00
    254 ;
    255   %r = frem nnan double 0.0, %x
    256   ret double %r
    257 }
    258 
    259 define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) {
    260 ; CHECK-LABEL: @frem_poszero_by_x_vec_undef(
    261 ; CHECK-NEXT:    ret <2 x double> zeroinitializer
    262 ;
    263   %r = frem nnan <2 x double> <double 0.0, double undef>, %x
    264   ret <2 x double> %r
    265 }
    266 
    267 ; -0 % X -> -0
    268 ; nsz is not necessary - frem result always has the sign of the dividend
    269 
    270 define double @frem_negzero_by_x(double %x) {
    271 ; CHECK-LABEL: @frem_negzero_by_x(
    272 ; CHECK-NEXT:    ret double -0.000000e+00
    273 ;
    274   %r = frem nnan double -0.0, %x
    275   ret double %r
    276 }
    277 
    278 define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) {
    279 ; CHECK-LABEL: @frem_negzero_by_x_vec_undef(
    280 ; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
    281 ;
    282   %r = frem nnan <2 x double> <double undef, double -0.0>, %x
    283   ret <2 x double> %r
    284 }
    285 
    286 define float @fdiv_self(float %f) {
    287 ; CHECK-LABEL: @fdiv_self(
    288 ; CHECK-NEXT:    ret float 1.000000e+00
    289 ;
    290   %div = fdiv nnan float %f, %f
    291   ret float %div
    292 }
    293 
    294 define float @fdiv_self_invalid(float %f) {
    295 ; CHECK-LABEL: @fdiv_self_invalid(
    296 ; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[F:%.*]], [[F]]
    297 ; CHECK-NEXT:    ret float [[DIV]]
    298 ;
    299   %div = fdiv float %f, %f
    300   ret float %div
    301 }
    302 
    303 define float @fdiv_neg1(float %f) {
    304 ; CHECK-LABEL: @fdiv_neg1(
    305 ; CHECK-NEXT:    ret float -1.000000e+00
    306 ;
    307   %neg = fsub fast float -0.000000e+00, %f
    308   %div = fdiv nnan float %neg, %f
    309   ret float %div
    310 }
    311 
    312 define float @fdiv_neg2(float %f) {
    313 ; CHECK-LABEL: @fdiv_neg2(
    314 ; CHECK-NEXT:    ret float -1.000000e+00
    315 ;
    316   %neg = fsub fast float 0.000000e+00, %f
    317   %div = fdiv nnan float %neg, %f
    318   ret float %div
    319 }
    320 
    321 define float @fdiv_neg_invalid(float %f) {
    322 ; CHECK-LABEL: @fdiv_neg_invalid(
    323 ; CHECK-NEXT:    [[NEG:%.*]] = fsub fast float -0.000000e+00, [[F:%.*]]
    324 ; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[NEG]], [[F]]
    325 ; CHECK-NEXT:    ret float [[DIV]]
    326 ;
    327   %neg = fsub fast float -0.000000e+00, %f
    328   %div = fdiv float %neg, %f
    329   ret float %div
    330 }
    331 
    332 define float @fdiv_neg_swapped1(float %f) {
    333 ; CHECK-LABEL: @fdiv_neg_swapped1(
    334 ; CHECK-NEXT:    ret float -1.000000e+00
    335 ;
    336   %neg = fsub float -0.000000e+00, %f
    337   %div = fdiv nnan float %f, %neg
    338   ret float %div
    339 }
    340 
    341 define float @fdiv_neg_swapped2(float %f) {
    342 ; CHECK-LABEL: @fdiv_neg_swapped2(
    343 ; CHECK-NEXT:    ret float -1.000000e+00
    344 ;
    345   %neg = fsub float 0.000000e+00, %f
    346   %div = fdiv nnan float %f, %neg
    347   ret float %div
    348 }
    349 
    350 ; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126
    351 ; With loose math, sqrt(X) * sqrt(X) is just X.
    352 
    353 declare double @llvm.sqrt.f64(double)
    354 
    355 define double @sqrt_squared(double %f) {
    356 ; CHECK-LABEL: @sqrt_squared(
    357 ; CHECK-NEXT:    ret double [[F:%.*]]
    358 ;
    359   %sqrt = call double @llvm.sqrt.f64(double %f)
    360   %mul = fmul reassoc nnan nsz double %sqrt, %sqrt
    361   ret double %mul
    362 }
    363 
    364 ; Negative tests for the above transform: we need all 3 of those flags.
    365 
    366 define double @sqrt_squared_not_fast_enough1(double %f) {
    367 ; CHECK-LABEL: @sqrt_squared_not_fast_enough1(
    368 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
    369 ; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan nsz double [[SQRT]], [[SQRT]]
    370 ; CHECK-NEXT:    ret double [[MUL]]
    371 ;
    372   %sqrt = call double @llvm.sqrt.f64(double %f)
    373   %mul = fmul nnan nsz double %sqrt, %sqrt
    374   ret double %mul
    375 }
    376 
    377 define double @sqrt_squared_not_fast_enough2(double %f) {
    378 ; CHECK-LABEL: @sqrt_squared_not_fast_enough2(
    379 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
    380 ; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nnan double [[SQRT]], [[SQRT]]
    381 ; CHECK-NEXT:    ret double [[MUL]]
    382 ;
    383   %sqrt = call double @llvm.sqrt.f64(double %f)
    384   %mul = fmul reassoc nnan double %sqrt, %sqrt
    385   ret double %mul
    386 }
    387 
    388 define double @sqrt_squared_not_fast_enough3(double %f) {
    389 ; CHECK-LABEL: @sqrt_squared_not_fast_enough3(
    390 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
    391 ; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz double [[SQRT]], [[SQRT]]
    392 ; CHECK-NEXT:    ret double [[MUL]]
    393 ;
    394   %sqrt = call double @llvm.sqrt.f64(double %f)
    395   %mul = fmul reassoc nsz double %sqrt, %sqrt
    396   ret double %mul
    397 }
    398 
    399