1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instsimplify -S | FileCheck %s 3 4; fneg (fsub -0.0, X) ==> X 5define float @fsub_-0_x(float %a) #0 { 6; CHECK-LABEL: @fsub_-0_x( 7; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0:[0-9]+]] 8; CHECK-NEXT: [[RET:%.*]] = fneg float [[T1]] 9; CHECK-NEXT: ret float [[RET]] 10; 11 %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 12 %ret = fneg float %t1 13 ret float %ret 14} 15 16define <2 x float> @fsub_-0_x_vec(<2 x float> %a) #0 { 17; CHECK-LABEL: @fsub_-0_x_vec( 18; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 19; CHECK-NEXT: [[RET:%.*]] = fneg <2 x float> [[T1]] 20; CHECK-NEXT: ret <2 x float> [[RET]] 21; 22 %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 23 %ret = fneg <2 x float> %t1 24 ret <2 x float> %ret 25} 26 27define <2 x float> @fsub_-0_x_vec_undef_elts(<2 x float> %a) #0 { 28; CHECK-LABEL: @fsub_-0_x_vec_undef_elts( 29; 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]] 30; CHECK-NEXT: [[RET:%.*]] = fneg <2 x float> [[T1]] 31; CHECK-NEXT: ret <2 x float> [[RET]] 32; 33 %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 34 %ret = fneg <2 x float> %t1 35 ret <2 x float> %ret 36} 37 38define <2 x float> @fsub_negzero_vec_undef_elts(<2 x float> %x) #0 { 39; CHECK-LABEL: @fsub_negzero_vec_undef_elts( 40; CHECK-NEXT: [[R:%.*]] = call nsz <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]] 41; CHECK-NEXT: ret <2 x float> [[R]] 42; 43 %r = call nsz <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 44 ret <2 x float> %r 45} 46 47; fsub -0.0, (fsub -0.0, X) ==> X 48define float @fsub_-0_-0_x(float %a) #0 { 49; CHECK-LABEL: @fsub_-0_-0_x( 50; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 51; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 52; CHECK-NEXT: ret float [[RET]] 53; 54 %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 55 %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 56 ret float %ret 57} 58 59; fsub -0.0, (fneg X) ==> X 60define float @fneg_x(float %a) #0 { 61; CHECK-LABEL: @fneg_x( 62; CHECK-NEXT: ret float [[A:%.*]] 63; 64 %t1 = fneg float %a 65 %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 66 ret float %ret 67} 68 69define <2 x float> @fsub_-0_-0_x_vec(<2 x float> %a) #0 { 70; CHECK-LABEL: @fsub_-0_-0_x_vec( 71; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 72; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 73; CHECK-NEXT: ret <2 x float> [[RET]] 74; 75 %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 76 %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 77 ret <2 x float> %ret 78} 79 80define <2 x float> @fneg_x_vec(<2 x float> %a) #0 { 81; CHECK-LABEL: @fneg_x_vec( 82; CHECK-NEXT: ret <2 x float> [[A:%.*]] 83; 84 %t1 = fneg <2 x float> %a 85 %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 86 ret <2 x float> %ret 87} 88 89define <2 x float> @fsub_-0_-0_x_vec_undef_elts(<2 x float> %a) #0 { 90; CHECK-LABEL: @fsub_-0_-0_x_vec_undef_elts( 91; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 92; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float undef>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 93; CHECK-NEXT: ret <2 x float> [[RET]] 94; 95 %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float undef, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 96 %ret = call <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 97 ret <2 x float> %ret 98} 99 100define <2 x float> @fneg_x_vec_undef_elts(<2 x float> %a) #0 { 101; CHECK-LABEL: @fneg_x_vec_undef_elts( 102; CHECK-NEXT: ret <2 x float> [[A:%.*]] 103; 104 %t1 = fneg <2 x float> %a 105 %ret = call <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 106 ret <2 x float> %ret 107} 108 109; fsub -0.0, (fsub 0.0, X) != X 110define float @fsub_-0_0_x(float %a) #0 { 111; CHECK-LABEL: @fsub_-0_0_x( 112; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 113; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 114; CHECK-NEXT: ret float [[RET]] 115; 116 %t1 = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 117 %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 118 ret float %ret 119} 120 121; fsub 0.0, (fsub -0.0, X) != X 122define float @fsub_0_-0_x(float %a) #0 { 123; CHECK-LABEL: @fsub_0_-0_x( 124; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 125; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 126; CHECK-NEXT: ret float [[RET]] 127; 128 %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 129 %ret = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 130 ret float %ret 131} 132 133; fsub X, 0 ==> X 134define float @fsub_x_0(float %x) #0 { 135; CHECK-LABEL: @fsub_x_0( 136; CHECK-NEXT: ret float [[X:%.*]] 137; 138 %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 139 ret float %r 140} 141 142define <2 x float> @fsub_x_0_vec_undef(<2 x float> %x) #0 { 143; CHECK-LABEL: @fsub_x_0_vec_undef( 144; CHECK-NEXT: ret <2 x float> [[X:%.*]] 145; 146 %r = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %x, <2 x float><float undef, float 0.0>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 147 ret <2 x float> %r 148} 149 150; fadd X, -0 ==> X 151define float @fadd_x_n0(float %a) #0 { 152; CHECK-LABEL: @fadd_x_n0( 153; CHECK-NEXT: ret float [[A:%.*]] 154; 155 %ret = call float @llvm.experimental.constrained.fadd.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 156 ret float %ret 157} 158 159define <2 x float> @fadd_x_n0_vec_undef_elt(<2 x float> %a) #0 { 160; CHECK-LABEL: @fadd_x_n0_vec_undef_elt( 161; CHECK-NEXT: ret <2 x float> [[A:%.*]] 162; 163 %ret = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float> <float -0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 164 ret <2 x float> %ret 165} 166 167; fadd X, 0 ==> X 168define float @fadd_x_p0(float %a) #0 { 169; CHECK-LABEL: @fadd_x_p0( 170; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 171; CHECK-NEXT: ret float [[RET]] 172; 173 %ret = call float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 174 ret float %ret 175} 176 177define <2 x float> @fadd_x_p0_vec_undef_elt(<2 x float> %a) #0 { 178; CHECK-LABEL: @fadd_x_p0_vec_undef_elt( 179; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[A:%.*]], <2 x float> <float 0.000000e+00, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 180; CHECK-NEXT: ret <2 x float> [[RET]] 181; 182 %ret = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float> <float 0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 183 ret <2 x float> %ret 184} 185 186; fmul X, 1.0 ==> X 187define double @fmul_X_1(double %a) #0 { 188; CHECK-LABEL: @fmul_X_1( 189; CHECK-NEXT: ret double [[A:%.*]] 190; 191 %b = call double @llvm.experimental.constrained.fmul.f64(double 1.0, double %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 192 ret double %b 193} 194 195; Originally PR2642 196define <4 x float> @fmul_X_1_vec(<4 x float> %x) { 197; CHECK-LABEL: @fmul_X_1_vec( 198; CHECK-NEXT: ret <4 x float> [[X:%.*]] 199; 200 %m = call <4 x float> @llvm.experimental.constrained.fmul.v4f32(<4 x float> %x, <4 x float> <float 1.0, float 1.0, float 1.0, float 1.0>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 201 ret <4 x float> %m 202} 203 204; fdiv X, 1.0 ==> X 205define float @fdiv_x_1(float %a) #0 { 206; CHECK-LABEL: @fdiv_x_1( 207; CHECK-NEXT: ret float [[A:%.*]] 208; 209 %ret = call float @llvm.experimental.constrained.fdiv.f32(float %a, float 1.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 210 211 ret float %ret 212} 213 214 215; The fabs can't be eliminated because llvm.experimental.constrained.sqrt.f32 may return -0 or NaN with 216; an arbitrary sign bit. 217define float @fabs_sqrt(float %a) #0 { 218; CHECK-LABEL: @fabs_sqrt( 219; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 220; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) 221; CHECK-NEXT: ret float [[FABS]] 222; 223 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 224 %fabs = call float @llvm.fabs.f32(float %sqrt) 225 ret float %fabs 226} 227 228; The fabs can't be eliminated because the nnan sqrt may still return -0. 229define float @fabs_sqrt_nnan(float %a) #0 { 230; CHECK-LABEL: @fabs_sqrt_nnan( 231; CHECK-NEXT: [[SQRT:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 232; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) 233; CHECK-NEXT: ret float [[FABS]] 234; 235 %sqrt = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 236 %fabs = call float @llvm.fabs.f32(float %sqrt) 237 ret float %fabs 238} 239 240; The fabs can't be eliminated because the nsz sqrt may still return NaN. 241define float @fabs_sqrt_nsz(float %a) #0 { 242; CHECK-LABEL: @fabs_sqrt_nsz( 243; CHECK-NEXT: [[SQRT:%.*]] = call nsz float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 244; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) 245; CHECK-NEXT: ret float [[FABS]] 246; 247 %sqrt = call nsz float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 248 %fabs = call float @llvm.fabs.f32(float %sqrt) 249 ret float %fabs 250} 251 252; The fabs can be eliminated because we're nsz and nnan. 253define float @fabs_sqrt_nnan_nsz(float %a) #0 { 254; CHECK-LABEL: @fabs_sqrt_nnan_nsz( 255; CHECK-NEXT: [[SQRT:%.*]] = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 256; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) 257; CHECK-NEXT: ret float [[FABS]] 258; 259 %sqrt = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 260 %fabs = call float @llvm.fabs.f32(float %sqrt) 261 ret float %fabs 262} 263 264; The second fabs can be eliminated because the operand to sqrt cannot be -0. 265define float @fabs_sqrt_nnan_fabs(float %a) #0 { 266; CHECK-LABEL: @fabs_sqrt_nnan_fabs( 267; CHECK-NEXT: [[B:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) 268; CHECK-NEXT: [[SQRT:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[B]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 269; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]]) 270; CHECK-NEXT: ret float [[FABS]] 271; 272 %b = call float @llvm.fabs.f32(float %a) 273 %sqrt = call nnan float @llvm.experimental.constrained.sqrt.f32(float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 274 %fabs = call float @llvm.fabs.f32(float %sqrt) 275 ret float %fabs 276} 277 278; Y - (Y - X) --> X 279 280define float @fsub_fsub_common_op(float %x, float %y) #0 { 281; CHECK-LABEL: @fsub_fsub_common_op( 282; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 283; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 284; CHECK-NEXT: ret float [[R]] 285; 286 %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 287 %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 288 ret float %r 289} 290 291define <2 x float> @fsub_fsub_common_op_vec(<2 x float> %x, <2 x float> %y) #0 { 292; CHECK-LABEL: @fsub_fsub_common_op_vec( 293; CHECK-NEXT: [[S:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[Y:%.*]], <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 294; CHECK-NEXT: [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[Y]], <2 x float> [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 295; CHECK-NEXT: ret <2 x float> [[R]] 296; 297 %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %y, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 298 %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %y, <2 x float> %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 299 ret <2 x float> %r 300} 301 302; Negative test - fsub is not commutative. 303; Y - (X - Y) --> (Y - X) + Y (canonicalized) 304 305define float @fsub_fsub_wrong_common_op(float %x, float %y) #0 { 306; CHECK-LABEL: @fsub_fsub_wrong_common_op( 307; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 308; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 309; CHECK-NEXT: ret float [[R]] 310; 311 %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 312 %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 313 ret float %r 314} 315 316; Negative test - negated operand needed. 317; (Y - X) - Y --> -X 318 319define float @fsub_fsub_common_op_wrong_commute(float %x, float %y) #0 { 320; CHECK-LABEL: @fsub_fsub_common_op_wrong_commute( 321; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 322; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 323; CHECK-NEXT: ret float [[R]] 324; 325 %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 326 %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 327 ret float %r 328} 329 330; Negative test - fsub is not commutative. 331; (X - Y) - Y --> ? 332 333define float @fsub_fsub_wrong_common_op_wrong_commute(float %x, float %y) #0 { 334; CHECK-LABEL: @fsub_fsub_wrong_common_op_wrong_commute( 335; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 336; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 337; CHECK-NEXT: ret float [[R]] 338; 339 %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 340 %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 341 ret float %r 342} 343 344; (Y + X) - Y --> X 345 346define float @fadd_fsub_common_op(float %x, float %y) #0 { 347; CHECK-LABEL: @fadd_fsub_common_op( 348; CHECK-NEXT: [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 349; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[A]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 350; CHECK-NEXT: ret float [[R]] 351; 352 %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 353 %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %a, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 354 ret float %r 355} 356 357; (X + Y) - Y --> X 358 359define <2 x float> @fadd_fsub_common_op_commute_vec(<2 x float> %x, <2 x float> %y) #0 { 360; CHECK-LABEL: @fadd_fsub_common_op_commute_vec( 361; CHECK-NEXT: [[A:%.*]] = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 362; CHECK-NEXT: [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[A]], <2 x float> [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 363; CHECK-NEXT: ret <2 x float> [[R]] 364; 365 %a = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 366 %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %a, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 367 ret <2 x float> %r 368} 369 370; Negative test - negated operand needed. 371; Y - (Y + X) --> -X 372 373define float @fadd_fsub_common_op_wrong_commute(float %x, float %y) #0 { 374; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute( 375; CHECK-NEXT: [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 376; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 377; CHECK-NEXT: ret float [[R]] 378; 379 %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 380 %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 381 ret float %r 382} 383 384; Negative test - negated operand needed. 385; Y - (X + Y) --> -X 386 387define float @fadd_fsub_common_op_wrong_commute_commute(float %x, float %y) #0 { 388; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute_commute( 389; CHECK-NEXT: [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 390; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 391; CHECK-NEXT: ret float [[R]] 392; 393 %a = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 394 %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 395 ret float %r 396} 397 398; Y + (X - Y) --> X 399 400define <2 x float> @fsub_fadd_common_op_vec(<2 x float> %x, <2 x float> %y) #0 { 401; CHECK-LABEL: @fsub_fadd_common_op_vec( 402; CHECK-NEXT: [[S:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 403; CHECK-NEXT: [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[Y]], <2 x float> [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 404; CHECK-NEXT: ret <2 x float> [[R]] 405; 406 %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 407 %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %y, <2 x float> %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 408 ret <2 x float> %r 409} 410 411; (X - Y) + Y --> X 412 413define float @fsub_fadd_common_op_commute(float %x, float %y) #0 { 414; CHECK-LABEL: @fsub_fadd_common_op_commute( 415; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 416; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 417; CHECK-NEXT: ret float [[R]] 418; 419 %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 420 %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 421 ret float %r 422} 423 424; Negative test. 425; Y + (Y - X) --> ? 426 427define float @fsub_fadd_common_op_wrong_commute(float %x, float %y) #0 { 428; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute( 429; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 430; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 431; CHECK-NEXT: ret float [[R]] 432; 433 %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 434 %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 435 ret float %r 436} 437 438; Negative test. 439; (Y - X) + Y --> ? 440 441define float @fsub_fadd_common_op_wrong_commute_commute(float %x, float %y) #0 { 442; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute_commute( 443; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 444; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 445; CHECK-NEXT: ret float [[R]] 446; 447 %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 448 %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 449 ret float %r 450} 451 452; Originally PR46627 - https://bugs.llvm.org/show_bug.cgi?id=46627 453 454define float @maxnum_with_poszero_op(float %a) #0 { 455; CHECK-LABEL: @maxnum_with_poszero_op( 456; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 0.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]] 457; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) 458; CHECK-NEXT: ret float [[FABS]] 459; 460 %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 0.0, metadata !"fpexcept.ignore") #0 461 %fabs = call float @llvm.fabs.f32(float %max) 462 ret float %fabs 463} 464 465define float @maxnum_with_poszero_op_commute(float %a) #0 { 466; CHECK-LABEL: @maxnum_with_poszero_op_commute( 467; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 468; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float 0.000000e+00, float [[SQRT]], metadata !"fpexcept.ignore") #[[ATTR0]] 469; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) 470; CHECK-NEXT: ret float [[FABS]] 471; 472 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 473 %max = call float @llvm.experimental.constrained.maxnum.f32(float 0.0, float %sqrt, metadata !"fpexcept.ignore") #0 474 %fabs = call float @llvm.fabs.f32(float %max) 475 ret float %fabs 476} 477 478define float @maxnum_with_negzero_op(float %a) #0 { 479; CHECK-LABEL: @maxnum_with_negzero_op( 480; CHECK-NEXT: [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 481; CHECK-NEXT: [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]]) 482; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float -0.000000e+00, float [[FABSA]], metadata !"fpexcept.ignore") #[[ATTR0]] 483; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) 484; CHECK-NEXT: ret float [[FABS]] 485; 486 %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 487 %fabsa = call float @llvm.fabs.f32(float %nnan) 488 %max = call float @llvm.experimental.constrained.maxnum.f32(float -0.0, float %fabsa, metadata !"fpexcept.ignore") #0 489 %fabs = call float @llvm.fabs.f32(float %max) 490 ret float %fabs 491} 492 493define float @maxnum_with_negzero_op_commute(float %a) #0 { 494; CHECK-LABEL: @maxnum_with_negzero_op_commute( 495; CHECK-NEXT: [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] 496; CHECK-NEXT: [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]]) 497; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[FABSA]], float -0.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]] 498; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) 499; CHECK-NEXT: ret float [[FABS]] 500; 501 %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 502 %fabsa = call float @llvm.fabs.f32(float %nnan) 503 %max = call float @llvm.experimental.constrained.maxnum.f32(float %fabsa, float -0.0, metadata !"fpexcept.ignore") #0 504 %fabs = call float @llvm.fabs.f32(float %max) 505 ret float %fabs 506} 507 508; If an operand is strictly greater than 0.0, we know the sign of the result of maxnum. 509 510define float @maxnum_with_pos_one_op(float %a) #0 { 511; CHECK-LABEL: @maxnum_with_pos_one_op( 512; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 1.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]] 513; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]]) 514; CHECK-NEXT: ret float [[FABS]] 515; 516 %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 1.0, metadata !"fpexcept.ignore") #0 517 %fabs = call float @llvm.fabs.f32(float %max) 518 ret float %fabs 519} 520 521declare float @llvm.fabs.f32(float) 522declare <2 x float> @llvm.fabs.v2f32(<2 x float>) 523 524declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #0 525declare <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0 526 527declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0 528declare <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0 529 530declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) #0 531declare <4 x float> @llvm.experimental.constrained.fmul.v4f32(<4 x float>, <4 x float>, metadata, metadata) #0 532 533declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0 534 535declare float @llvm.experimental.constrained.maxnum.f32(float, float, metadata) #0 536declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) #0 537 538attributes #0 = { strictfp } 539