1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instsimplify -S | FileCheck %s 3 4;; x * 0 ==> 0 when no-nans and no-signed-zero 5define float @mul_zero_1(float %a) #0 { 6; CHECK-LABEL: @mul_zero_1( 7; CHECK-NEXT: ret float 0.000000e+00 8; 9 %b = call nsz nnan float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 10 ret float %b 11} 12 13define float @mul_zero_2(float %a) #0 { 14; CHECK-LABEL: @mul_zero_2( 15; CHECK-NEXT: ret float 0.000000e+00 16; 17 %b = call fast float @llvm.experimental.constrained.fmul.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 18 ret float %b 19} 20 21define <2 x float> @mul_zero_nsz_nnan_vec_undef(<2 x float> %a) #0 { 22; CHECK-LABEL: @mul_zero_nsz_nnan_vec_undef( 23; CHECK-NEXT: ret <2 x float> zeroinitializer 24; 25 %b = call nsz nnan <2 x float> @llvm.experimental.constrained.fmul.v2f32(<2 x float> %a, <2 x float><float 0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 26 ret <2 x float> %b 27} 28 29;; x * 0 =/=> 0 when there could be nans or -0 30define float @no_mul_zero_1(float %a) #0 { 31; CHECK-LABEL: @no_mul_zero_1( 32; CHECK-NEXT: [[B:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0:[0-9]+]] 33; CHECK-NEXT: ret float [[B]] 34; 35 %b = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 36 ret float %b 37} 38 39define float @no_mul_zero_2(float %a) #0 { 40; CHECK-LABEL: @no_mul_zero_2( 41; CHECK-NEXT: [[B:%.*]] = call nnan float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 42; CHECK-NEXT: ret float [[B]] 43; 44 %b = call nnan float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 45 ret float %b 46} 47 48define float @no_mul_zero_3(float %a) #0 { 49; CHECK-LABEL: @no_mul_zero_3( 50; CHECK-NEXT: [[B:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 51; CHECK-NEXT: ret float [[B]] 52; 53 %b = call float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 54 ret float %b 55} 56 57; -X + X --> 0.0 (with nnan on the fadd) 58 59define float @fadd_binary_fnegx(float %x) #0 { 60; CHECK-LABEL: @fadd_binary_fnegx( 61; CHECK-NEXT: [[NEGX:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 62; CHECK-NEXT: [[R:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[NEGX]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 63; CHECK-NEXT: ret float [[R]] 64; 65 %negx = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 66 %r = call nnan float @llvm.experimental.constrained.fadd.f32(float %negx, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 67 ret float %r 68} 69 70define float @fadd_unary_fnegx(float %x) #0 { 71; CHECK-LABEL: @fadd_unary_fnegx( 72; CHECK-NEXT: ret float 0.000000e+00 73; 74 %negx = fneg float %x 75 %r = call nnan float @llvm.experimental.constrained.fadd.f32(float %negx, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 76 ret float %r 77} 78 79; X + -X --> 0.0 (with nnan on the fadd) 80 81define <2 x float> @fadd_binary_fnegx_commute_vec(<2 x float> %x) #0 { 82; CHECK-LABEL: @fadd_binary_fnegx_commute_vec( 83; CHECK-NEXT: [[NEGX:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 84; CHECK-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[X]], <2 x float> [[NEGX]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 85; CHECK-NEXT: ret <2 x float> [[R]] 86; 87 %negx = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.0, float -0.0>, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 88 %r = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %negx, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 89 ret <2 x float> %r 90} 91 92define <2 x float> @fadd_unary_fnegx_commute_vec(<2 x float> %x) #0 { 93; CHECK-LABEL: @fadd_unary_fnegx_commute_vec( 94; CHECK-NEXT: ret <2 x float> zeroinitializer 95; 96 %negx = fneg <2 x float> %x 97 %r = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %negx, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 98 ret <2 x float> %r 99} 100 101define <2 x float> @fadd_fnegx_commute_vec_undef(<2 x float> %x) #0 { 102; CHECK-LABEL: @fadd_fnegx_commute_vec_undef( 103; CHECK-NEXT: [[NEGX:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 104; CHECK-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[X]], <2 x float> [[NEGX]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 105; CHECK-NEXT: ret <2 x float> [[R]] 106; 107 %negx = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.0>, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 108 %r = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %negx, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 109 ret <2 x float> %r 110} 111 112; https://bugs.llvm.org/show_bug.cgi?id=26958 113; https://bugs.llvm.org/show_bug.cgi?id=27151 114 115define float @fadd_binary_fneg_nan(float %x) #0 { 116; CHECK-LABEL: @fadd_binary_fneg_nan( 117; CHECK-NEXT: [[T:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 118; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call ninf float @llvm.experimental.constrained.fadd.f32(float [[T]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 119; CHECK-NEXT: ret float [[COULD_BE_NAN]] 120; 121 %t = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 122 %could_be_nan = call ninf float @llvm.experimental.constrained.fadd.f32(float %t, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 123 ret float %could_be_nan 124} 125 126define float @fadd_unary_fneg_nan(float %x) #0 { 127; CHECK-LABEL: @fadd_unary_fneg_nan( 128; CHECK-NEXT: [[T:%.*]] = fneg nnan float [[X:%.*]] 129; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call ninf float @llvm.experimental.constrained.fadd.f32(float [[T]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 130; CHECK-NEXT: ret float [[COULD_BE_NAN]] 131; 132 %t = fneg nnan float %x 133 %could_be_nan = call ninf float @llvm.experimental.constrained.fadd.f32(float %t, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 134 ret float %could_be_nan 135} 136 137define float @fadd_binary_fneg_nan_commute(float %x) #0 { 138; CHECK-LABEL: @fadd_binary_fneg_nan_commute( 139; CHECK-NEXT: [[T:%.*]] = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 140; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X]], float [[T]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 141; CHECK-NEXT: ret float [[COULD_BE_NAN]] 142; 143 %t = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float -0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 144 %could_be_nan = call float @llvm.experimental.constrained.fadd.f32(float %x, float %t, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 145 ret float %could_be_nan 146} 147 148define float @fadd_unary_fneg_nan_commute(float %x) #0 { 149; CHECK-LABEL: @fadd_unary_fneg_nan_commute( 150; CHECK-NEXT: [[T:%.*]] = fneg nnan ninf float [[X:%.*]] 151; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X]], float [[T]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 152; CHECK-NEXT: ret float [[COULD_BE_NAN]] 153; 154 %t = fneg nnan ninf float %x 155 %could_be_nan = call float @llvm.experimental.constrained.fadd.f32(float %x, float %t, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 156 ret float %could_be_nan 157} 158 159; X + (0.0 - X) --> 0.0 (with nnan on the fadd) 160 161define float @fadd_fsub_nnan_ninf(float %x) #0 { 162; CHECK-LABEL: @fadd_fsub_nnan_ninf( 163; CHECK-NEXT: [[SUB:%.*]] = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 164; CHECK-NEXT: [[ZERO:%.*]] = call nnan ninf float @llvm.experimental.constrained.fadd.f32(float [[X]], float [[SUB]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 165; CHECK-NEXT: ret float [[ZERO]] 166; 167 %sub = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float 0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 168 %zero = call nnan ninf float @llvm.experimental.constrained.fadd.f32(float %x, float %sub, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 169 ret float %zero 170} 171 172; (0.0 - X) + X --> 0.0 (with nnan on the fadd) 173 174define <2 x float> @fadd_fsub_nnan_ninf_commute_vec(<2 x float> %x) #0 { 175; CHECK-LABEL: @fadd_fsub_nnan_ninf_commute_vec( 176; CHECK-NEXT: [[SUB:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 177; CHECK-NEXT: [[ZERO:%.*]] = call nnan ninf <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[SUB]], <2 x float> [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 178; CHECK-NEXT: ret <2 x float> [[ZERO]] 179; 180 %sub = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 181 %zero = call nnan ninf <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %sub, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 182 ret <2 x float> %zero 183} 184 185; 'ninf' is not required because 'nnan' allows us to assume 186; that X is not INF or -INF (adding opposite INFs would be NaN). 187 188define float @fadd_fsub_nnan(float %x) #0 { 189; CHECK-LABEL: @fadd_fsub_nnan( 190; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 191; CHECK-NEXT: [[ZERO:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[SUB]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 192; CHECK-NEXT: ret float [[ZERO]] 193; 194 %sub = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 195 %zero = call nnan float @llvm.experimental.constrained.fadd.f32(float %sub, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 196 ret float %zero 197} 198 199; fsub nnan x, x ==> 0.0 200define float @fsub_x_x(float %a) #0 { 201; X - X ==> 0 202; CHECK-LABEL: @fsub_x_x( 203; CHECK-NEXT: [[NO_ZERO1:%.*]] = call ninf float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 204; CHECK-NEXT: [[NO_ZERO2:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 205; CHECK-NEXT: [[NO_ZERO:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[NO_ZERO1]], float [[NO_ZERO2]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 206; CHECK-NEXT: ret float [[NO_ZERO]] 207; 208 %zero1 = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 209 210; Dont fold 211 %no_zero1 = call ninf float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 212 %no_zero2 = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 213 %no_zero = call float @llvm.experimental.constrained.fadd.f32(float %no_zero1, float %no_zero2, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 214 215; Should get folded 216 %ret = call nsz float @llvm.experimental.constrained.fadd.f32(float %no_zero, float %zero1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 217 218 ret float %ret 219} 220 221; fsub nsz 0.0, (fsub 0.0, X) ==> X 222define float @fsub_0_0_x(float %a) #0 { 223; CHECK-LABEL: @fsub_0_0_x( 224; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 225; CHECK-NEXT: [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 226; CHECK-NEXT: ret float [[RET]] 227; 228 %t1 = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 229 %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 230 ret float %ret 231} 232 233; fsub nsz 0.0, (fneg X) ==> X 234define float @fneg_x(float %a) #0 { 235; CHECK-LABEL: @fneg_x( 236; CHECK-NEXT: ret float [[A:%.*]] 237; 238 %t1 = fneg float %a 239 %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 240 ret float %ret 241} 242 243define <2 x float> @fsub_0_0_x_vec_undef1(<2 x float> %a) #0 { 244; CHECK-LABEL: @fsub_0_0_x_vec_undef1( 245; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.000000e+00, float undef>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 246; CHECK-NEXT: [[RET:%.*]] = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 247; CHECK-NEXT: ret <2 x float> [[RET]] 248; 249 %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.0, float undef>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 250 %ret = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 251 ret <2 x float> %ret 252} 253 254define <2 x float> @fneg_x_vec_undef1(<2 x float> %a) #0 { 255; CHECK-LABEL: @fneg_x_vec_undef1( 256; CHECK-NEXT: ret <2 x float> [[A:%.*]] 257; 258 %t1 = fneg <2 x float> %a 259 %ret = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.0, float undef>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 260 ret <2 x float> %ret 261} 262 263define <2 x float> @fsub_0_0_x_vec_undef2(<2 x float> %a) #0 { 264; CHECK-LABEL: @fsub_0_0_x_vec_undef2( 265; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 266; CHECK-NEXT: [[RET:%.*]] = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 267; CHECK-NEXT: ret <2 x float> [[RET]] 268; 269 %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 270 %ret = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 271 ret <2 x float> %ret 272} 273 274; fadd nsz X, 0 ==> X 275 276define <2 x float> @fadd_zero_nsz_vec(<2 x float> %x) #0 { 277; CHECK-LABEL: @fadd_zero_nsz_vec( 278; CHECK-NEXT: ret <2 x float> [[X:%.*]] 279; 280 %r = call nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> zeroinitializer, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 281 ret <2 x float> %r 282} 283 284define <2 x float> @fadd_zero_nsz_vec_undef(<2 x float> %x) #0 { 285; CHECK-LABEL: @fadd_zero_nsz_vec_undef( 286; CHECK-NEXT: ret <2 x float> [[X:%.*]] 287; 288 %r = call nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> <float 0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 289 ret <2 x float> %r 290} 291 292define float @nofold_fadd_x_0(float %a) #0 { 293; Dont fold 294; CHECK-LABEL: @nofold_fadd_x_0( 295; CHECK-NEXT: [[NO_ZERO1:%.*]] = call ninf float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 296; CHECK-NEXT: [[NO_ZERO2:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[A]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 297; CHECK-NEXT: [[NO_ZERO:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[NO_ZERO1]], float [[NO_ZERO2]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 298; CHECK-NEXT: ret float [[NO_ZERO]] 299; 300 %no_zero1 = call ninf float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 301 %no_zero2 = call nnan float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 302 %no_zero = call float @llvm.experimental.constrained.fadd.f32(float %no_zero1, float %no_zero2, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 303 ret float %no_zero 304} 305 306define float @fold_fadd_nsz_x_0(float %a) #0 { 307; CHECK-LABEL: @fold_fadd_nsz_x_0( 308; CHECK-NEXT: ret float [[A:%.*]] 309; 310 %add = call nsz float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 311 ret float %add 312} 313 314; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify. 315 316define float @fold_fadd_cannot_be_neg0_nsz_src_x_0(float %a, float %b) #0 { 317; CHECK-LABEL: @fold_fadd_cannot_be_neg0_nsz_src_x_0( 318; CHECK-NEXT: [[NSZ:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float [[B:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 319; CHECK-NEXT: [[ADD:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[NSZ]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 320; CHECK-NEXT: ret float [[ADD]] 321; 322 %nsz = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 323 %add = call float @llvm.experimental.constrained.fadd.f32(float %nsz, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 324 ret float %add 325} 326 327define float @fold_fadd_cannot_be_neg0_fabs_src_x_0(float %a) #0 { 328; CHECK-LABEL: @fold_fadd_cannot_be_neg0_fabs_src_x_0( 329; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) 330; CHECK-NEXT: ret float [[FABS]] 331; 332 %fabs = call float @llvm.fabs.f32(float %a) 333 %add = call float @llvm.experimental.constrained.fadd.f32(float %fabs, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 334 ret float %add 335} 336 337; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify. 338 339define float @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(float %a, float %b) #0 { 340; CHECK-LABEL: @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0( 341; CHECK-NEXT: [[NSZ:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float [[B:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 342; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[NSZ]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 343; CHECK-NEXT: [[ADD:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[SQRT]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 344; CHECK-NEXT: ret float [[ADD]] 345; 346 %nsz = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 347 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %nsz, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 348 %add = call float @llvm.experimental.constrained.fadd.f32(float %sqrt, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 349 ret float %add 350} 351 352; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify. 353 354define float @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(float %a, float %b) #0 { 355; CHECK-LABEL: @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0( 356; CHECK-NEXT: [[NSZ:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float [[B:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 357; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSZ]]) 358; CHECK-NEXT: [[ADD:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[CANON]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 359; CHECK-NEXT: ret float [[ADD]] 360; 361 %nsz = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 362 %canon = call float @llvm.canonicalize.f32(float %nsz) 363 %add = call float @llvm.experimental.constrained.fadd.f32(float %canon, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 364 ret float %add 365} 366 367; fdiv nsz nnan 0, X ==> 0 368; 0 / X -> 0 369 370define double @fdiv_zero_by_x(double %x) #0 { 371; CHECK-LABEL: @fdiv_zero_by_x( 372; CHECK-NEXT: ret double 0.000000e+00 373; 374 %r = call nnan nsz double @llvm.experimental.constrained.fdiv.f64(double 0.0, double %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 375 ret double %r 376} 377 378define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) #0 { 379; CHECK-LABEL: @fdiv_zero_by_x_vec_undef( 380; CHECK-NEXT: ret <2 x double> zeroinitializer 381; 382 %r = call nnan nsz <2 x double> @llvm.experimental.constrained.fdiv.v2f64(<2 x double> <double 0.0, double undef>, <2 x double> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 383 ret <2 x double> %r 384} 385 386; 0 % X -> 0 387; nsz is not necessary - frem result always has the sign of the dividend 388 389define double @frem_zero_by_x(double %x) #0 { 390; CHECK-LABEL: @frem_zero_by_x( 391; CHECK-NEXT: ret double 0.000000e+00 392; 393 %r = call nnan double @llvm.experimental.constrained.frem.f64(double 0.0, double %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 394 ret double %r 395} 396 397define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) #0 { 398; CHECK-LABEL: @frem_poszero_by_x_vec_undef( 399; CHECK-NEXT: ret <2 x double> zeroinitializer 400; 401 %r = call nnan <2 x double> @llvm.experimental.constrained.frem.v2f64(<2 x double> <double 0.0, double undef>, <2 x double> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 402 ret <2 x double> %r 403} 404 405; -0 % X -> -0 406; nsz is not necessary - frem result always has the sign of the dividend 407 408define double @frem_negzero_by_x(double %x) #0 { 409; CHECK-LABEL: @frem_negzero_by_x( 410; CHECK-NEXT: ret double -0.000000e+00 411; 412 %r = call nnan double @llvm.experimental.constrained.frem.f64(double -0.0, double %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 413 ret double %r 414} 415 416define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) #0 { 417; CHECK-LABEL: @frem_negzero_by_x_vec_undef( 418; CHECK-NEXT: ret <2 x double> <double -0.000000e+00, double -0.000000e+00> 419; 420 %r = call nnan <2 x double> @llvm.experimental.constrained.frem.v2f64(<2 x double> <double undef, double -0.0>, <2 x double> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 421 ret <2 x double> %r 422} 423 424define float @fdiv_self(float %f) #0 { 425; CHECK-LABEL: @fdiv_self( 426; CHECK-NEXT: ret float 1.000000e+00 427; 428 %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %f, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 429 ret float %div 430} 431 432define float @fdiv_self_invalid(float %f) #0 { 433; CHECK-LABEL: @fdiv_self_invalid( 434; CHECK-NEXT: [[DIV:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[F:%.*]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 435; CHECK-NEXT: ret float [[DIV]] 436; 437 %div = call float @llvm.experimental.constrained.fdiv.f32(float %f, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 438 ret float %div 439} 440 441define float @fdiv_neg1(float %f) #0 { 442; CHECK-LABEL: @fdiv_neg1( 443; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 444; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[NEG]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 445; CHECK-NEXT: ret float [[DIV]] 446; 447 %neg = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 448 %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %neg, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 449 ret float %div 450} 451 452define float @fdiv_neg2(float %f) #0 { 453; CHECK-LABEL: @fdiv_neg2( 454; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 455; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[NEG]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 456; CHECK-NEXT: ret float [[DIV]] 457; 458 %neg = call fast float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 459 %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %neg, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 460 ret float %div 461} 462 463define float @fdiv_neg_invalid(float %f) #0 { 464; CHECK-LABEL: @fdiv_neg_invalid( 465; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 466; CHECK-NEXT: [[DIV:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[NEG]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 467; CHECK-NEXT: ret float [[DIV]] 468; 469 %neg = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 470 %div = call float @llvm.experimental.constrained.fdiv.f32(float %neg, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 471 ret float %div 472} 473 474define float @fdiv_neg_swapped1(float %f) #0 { 475; CHECK-LABEL: @fdiv_neg_swapped1( 476; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 477; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[F]], float [[NEG]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 478; CHECK-NEXT: ret float [[DIV]] 479; 480 %neg = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 481 %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %f, float %neg, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 482 ret float %div 483} 484 485define float @fdiv_neg_swapped2(float %f) #0 { 486; CHECK-LABEL: @fdiv_neg_swapped2( 487; CHECK-NEXT: [[NEG:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 488; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[F]], float [[NEG]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 489; CHECK-NEXT: ret float [[DIV]] 490; 491 %neg = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 492 %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %f, float %neg, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 493 ret float %div 494} 495 496define <2 x float> @fdiv_neg_vec_undef_elt(<2 x float> %f) #0 { 497; CHECK-LABEL: @fdiv_neg_vec_undef_elt( 498; CHECK-NEXT: [[NEG:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.000000e+00, float undef>, <2 x float> [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 499; CHECK-NEXT: [[DIV:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float> [[F]], <2 x float> [[NEG]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 500; CHECK-NEXT: ret <2 x float> [[DIV]] 501; 502 %neg = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.000000e+00, float undef>, <2 x float> %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 503 %div = call nnan <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float> %f, <2 x float> %neg, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 504 ret <2 x float> %div 505} 506 507; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126 508; With loose math, sqrt(X) * sqrt(X) is just X. 509 510declare double @llvm.sqrt.f64(double) 511 512define double @sqrt_squared(double %f) #0 { 513; CHECK-LABEL: @sqrt_squared( 514; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") 515; CHECK-NEXT: [[MUL:%.*]] = call reassoc nnan nsz double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 516; CHECK-NEXT: ret double [[MUL]] 517; 518 %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") 519 %mul = call reassoc nnan nsz double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 520 ret double %mul 521} 522 523; Negative tests for the above transform: we need all 3 of those flags. 524 525define double @sqrt_squared_not_fast_enough1(double %f) #0 { 526; CHECK-LABEL: @sqrt_squared_not_fast_enough1( 527; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") 528; CHECK-NEXT: [[MUL:%.*]] = call nnan nsz double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 529; CHECK-NEXT: ret double [[MUL]] 530; 531 %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") 532 %mul = call nnan nsz double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 533 ret double %mul 534} 535 536define double @sqrt_squared_not_fast_enough2(double %f) #0 { 537; CHECK-LABEL: @sqrt_squared_not_fast_enough2( 538; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") 539; CHECK-NEXT: [[MUL:%.*]] = call reassoc nnan double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 540; CHECK-NEXT: ret double [[MUL]] 541; 542 %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") 543 %mul = call reassoc nnan double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 544 ret double %mul 545} 546 547define double @sqrt_squared_not_fast_enough3(double %f) #0 { 548; CHECK-LABEL: @sqrt_squared_not_fast_enough3( 549; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") 550; CHECK-NEXT: [[MUL:%.*]] = call reassoc nsz double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 551; CHECK-NEXT: ret double [[MUL]] 552; 553 %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") 554 %mul = call reassoc nsz double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 555 ret double %mul 556} 557 558declare float @llvm.fabs.f32(float) 559declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) #0 560declare double @llvm.experimental.constrained.sqrt.f64(double, metadata, metadata) #0 561declare float @llvm.canonicalize.f32(float) 562 563declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #0 564declare <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0 565 566declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0 567declare <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0 568 569declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) #0 570declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) #0 571declare <2 x float> @llvm.experimental.constrained.fmul.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0 572 573declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0 574declare double @llvm.experimental.constrained.fdiv.f64(double, double, metadata, metadata) #0 575declare <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0 576declare <2 x double> @llvm.experimental.constrained.fdiv.v2f64(<2 x double>, <2 x double>, metadata, metadata) #0 577 578declare double @llvm.experimental.constrained.frem.f64(double, double, metadata, metadata) #0 579declare <2 x double> @llvm.experimental.constrained.frem.v2f64(<2 x double>, <2 x double>, metadata, metadata) #0 580 581attributes #0 = { strictfp } 582 583