1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -instcombine < %s | FileCheck %s 3 4declare float @llvm.maximum.f32(float, float) 5declare <2 x float> @llvm.maximum.v2f32(<2 x float>, <2 x float>) 6declare <4 x float> @llvm.maximum.v4f32(<4 x float>, <4 x float>) 7 8declare double @llvm.maximum.f64(double, double) 9declare <2 x double> @llvm.maximum.v2f64(<2 x double>, <2 x double>) 10 11define float @constant_fold_maximum_f32() { 12; CHECK-LABEL: @constant_fold_maximum_f32( 13; CHECK-NEXT: ret float 2.000000e+00 14; 15 %x = call float @llvm.maximum.f32(float 1.0, float 2.0) 16 ret float %x 17} 18 19define float @constant_fold_maximum_f32_inv() { 20; CHECK-LABEL: @constant_fold_maximum_f32_inv( 21; CHECK-NEXT: ret float 2.000000e+00 22; 23 %x = call float @llvm.maximum.f32(float 2.0, float 1.0) 24 ret float %x 25} 26 27define float @constant_fold_maximum_f32_nan0() { 28; CHECK-LABEL: @constant_fold_maximum_f32_nan0( 29; CHECK-NEXT: ret float 0x7FF8000000000000 30; 31 %x = call float @llvm.maximum.f32(float 0x7FF8000000000000, float 2.0) 32 ret float %x 33} 34 35define float @constant_fold_maximum_f32_nan1() { 36; CHECK-LABEL: @constant_fold_maximum_f32_nan1( 37; CHECK-NEXT: ret float 0x7FF8000000000000 38; 39 %x = call float @llvm.maximum.f32(float 2.0, float 0x7FF8000000000000) 40 ret float %x 41} 42 43define float @constant_fold_maximum_f32_nan_nan() { 44; CHECK-LABEL: @constant_fold_maximum_f32_nan_nan( 45; CHECK-NEXT: ret float 0x7FF8000000000000 46; 47 %x = call float @llvm.maximum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000) 48 ret float %x 49} 50 51define float @constant_fold_maximum_f32_p0_p0() { 52; CHECK-LABEL: @constant_fold_maximum_f32_p0_p0( 53; CHECK-NEXT: ret float 0.000000e+00 54; 55 %x = call float @llvm.maximum.f32(float 0.0, float 0.0) 56 ret float %x 57} 58 59define float @constant_fold_maximum_f32_p0_n0() { 60; CHECK-LABEL: @constant_fold_maximum_f32_p0_n0( 61; CHECK-NEXT: ret float 0.000000e+00 62; 63 %x = call float @llvm.maximum.f32(float 0.0, float -0.0) 64 ret float %x 65} 66 67define float @constant_fold_maximum_f32_n0_p0() { 68; CHECK-LABEL: @constant_fold_maximum_f32_n0_p0( 69; CHECK-NEXT: ret float 0.000000e+00 70; 71 %x = call float @llvm.maximum.f32(float -0.0, float 0.0) 72 ret float %x 73} 74 75define float @constant_fold_maximum_f32_n0_n0() { 76; CHECK-LABEL: @constant_fold_maximum_f32_n0_n0( 77; CHECK-NEXT: ret float -0.000000e+00 78; 79 %x = call float @llvm.maximum.f32(float -0.0, float -0.0) 80 ret float %x 81} 82 83define <4 x float> @constant_fold_maximum_v4f32() { 84; CHECK-LABEL: @constant_fold_maximum_v4f32( 85; CHECK-NEXT: ret <4 x float> <float 2.000000e+00, float 8.000000e+00, float 1.000000e+01, float 9.000000e+00> 86; 87 %x = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.0, float 8.0, float 3.0, float 9.0>, <4 x float> <float 2.0, float 2.0, float 10.0, float 5.0>) 88 ret <4 x float> %x 89} 90 91define double @constant_fold_maximum_f64() { 92; CHECK-LABEL: @constant_fold_maximum_f64( 93; CHECK-NEXT: ret double 2.000000e+00 94; 95 %x = call double @llvm.maximum.f64(double 1.0, double 2.0) 96 ret double %x 97} 98 99define double @constant_fold_maximum_f64_nan0() { 100; CHECK-LABEL: @constant_fold_maximum_f64_nan0( 101; CHECK-NEXT: ret double 0x7FF8000000000000 102; 103 %x = call double @llvm.maximum.f64(double 0x7FF8000000000000, double 2.0) 104 ret double %x 105} 106 107define double @constant_fold_maximum_f64_nan1() { 108; CHECK-LABEL: @constant_fold_maximum_f64_nan1( 109; CHECK-NEXT: ret double 0x7FF8000000000000 110; 111 %x = call double @llvm.maximum.f64(double 2.0, double 0x7FF8000000000000) 112 ret double %x 113} 114 115define double @constant_fold_maximum_f64_nan_nan() { 116; CHECK-LABEL: @constant_fold_maximum_f64_nan_nan( 117; CHECK-NEXT: ret double 0x7FF8000000000000 118; 119 %x = call double @llvm.maximum.f64(double 0x7FF8000000000000, double 0x7FF8000000000000) 120 ret double %x 121} 122 123define float @canonicalize_constant_maximum_f32(float %x) { 124; CHECK-LABEL: @canonicalize_constant_maximum_f32( 125; CHECK-NEXT: [[Y:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00) 126; CHECK-NEXT: ret float [[Y]] 127; 128 %y = call float @llvm.maximum.f32(float 1.0, float %x) 129 ret float %y 130} 131 132define float @maximum_f32_nan_val(float %x) { 133; CHECK-LABEL: @maximum_f32_nan_val( 134; CHECK-NEXT: ret float 0x7FF8000000000000 135; 136 %y = call float @llvm.maximum.f32(float 0x7FF8000000000000, float %x) 137 ret float %y 138} 139 140define float @maximum_f32_val_nan(float %x) { 141; CHECK-LABEL: @maximum_f32_val_nan( 142; CHECK-NEXT: ret float 0x7FF8000000000000 143; 144 %y = call float @llvm.maximum.f32(float %x, float 0x7FF8000000000000) 145 ret float %y 146} 147 148define float @maximum_f32_1_maximum_val_p0(float %x) { 149; CHECK-LABEL: @maximum_f32_1_maximum_val_p0( 150; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00) 151; CHECK-NEXT: ret float [[TMP1]] 152; 153 %y = call float @llvm.maximum.f32(float %x, float 0.0) 154 %z = call float @llvm.maximum.f32(float %y, float 1.0) 155 ret float %z 156} 157 158define float @maximum_f32_1_maximum_p0_val_fast(float %x) { 159; CHECK-LABEL: @maximum_f32_1_maximum_p0_val_fast( 160; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00) 161; CHECK-NEXT: ret float [[TMP1]] 162; 163 %y = call float @llvm.maximum.f32(float 0.0, float %x) 164 %z = call fast float @llvm.maximum.f32(float %y, float 1.0) 165 ret float %z 166} 167 168define float @maximum_f32_1_maximum_p0_val_fmf1(float %x) { 169; CHECK-LABEL: @maximum_f32_1_maximum_p0_val_fmf1( 170; CHECK-NEXT: [[TMP1:%.*]] = call nnan arcp float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00) 171; CHECK-NEXT: ret float [[TMP1]] 172; 173 %y = call arcp nnan float @llvm.maximum.f32(float 0.0, float %x) 174 %z = call arcp nnan ninf float @llvm.maximum.f32(float %y, float 1.0) 175 ret float %z 176} 177 178define float @maximum_f32_1_maximum_p0_val_fmf2(float %x) { 179; CHECK-LABEL: @maximum_f32_1_maximum_p0_val_fmf2( 180; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00) 181; CHECK-NEXT: ret float [[TMP1]] 182; 183 %y = call arcp nnan ninf float @llvm.maximum.f32(float 0.0, float %x) 184 %z = call nnan float @llvm.maximum.f32(float %y, float 1.0) 185 ret float %z 186} 187 188define float @maximum_f32_1_maximum_p0_val_fmf3(float %x) { 189; CHECK-LABEL: @maximum_f32_1_maximum_p0_val_fmf3( 190; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00) 191; CHECK-NEXT: ret float [[TMP1]] 192; 193 %y = call nnan ninf float @llvm.maximum.f32(float 0.0, float %x) 194 %z = call arcp nnan ninf float @llvm.maximum.f32(float %y, float 1.0) 195 ret float %z 196} 197 198define float @maximum_f32_p0_maximum_val_n0(float %x) { 199; CHECK-LABEL: @maximum_f32_p0_maximum_val_n0( 200; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float 0.000000e+00) 201; CHECK-NEXT: ret float [[TMP1]] 202; 203 %y = call float @llvm.maximum.f32(float %x, float -0.0) 204 %z = call float @llvm.maximum.f32(float %y, float 0.0) 205 ret float %z 206} 207 208define float @maximum_f32_1_maximum_p0_val(float %x) { 209; CHECK-LABEL: @maximum_f32_1_maximum_p0_val( 210; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float 1.000000e+00) 211; CHECK-NEXT: ret float [[TMP1]] 212; 213 %y = call float @llvm.maximum.f32(float 0.0, float %x) 214 %z = call float @llvm.maximum.f32(float %y, float 1.0) 215 ret float %z 216} 217 218define <2 x float> @maximum_f32_1_maximum_val_p0_val_v2f32(<2 x float> %x) { 219; CHECK-LABEL: @maximum_f32_1_maximum_val_p0_val_v2f32( 220; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.maximum.v2f32(<2 x float> [[X:%.*]], <2 x float> <float 1.000000e+00, float 1.000000e+00>) 221; CHECK-NEXT: ret <2 x float> [[TMP1]] 222; 223 %y = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> zeroinitializer) 224 %z = call <2 x float> @llvm.maximum.v2f32(<2 x float> %y, <2 x float><float 1.0, float 1.0>) 225 ret <2 x float> %z 226} 227 228define float @maximum4(float %x, float %y, float %z, float %w) { 229; CHECK-LABEL: @maximum4( 230; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) 231; CHECK-NEXT: [[B:%.*]] = call float @llvm.maximum.f32(float [[Z:%.*]], float [[W:%.*]]) 232; CHECK-NEXT: [[C:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) 233; CHECK-NEXT: ret float [[C]] 234; 235 %a = call float @llvm.maximum.f32(float %x, float %y) 236 %b = call float @llvm.maximum.f32(float %z, float %w) 237 %c = call float @llvm.maximum.f32(float %a, float %b) 238 ret float %c 239} 240 241; PR37404 - https://bugs.llvm.org/show_bug.cgi?id=37404 242 243define <2 x float> @neg_neg(<2 x float> %x, <2 x float> %y) { 244; CHECK-LABEL: @neg_neg( 245; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]]) 246; CHECK-NEXT: [[R:%.*]] = fneg <2 x float> [[TMP1]] 247; CHECK-NEXT: ret <2 x float> [[R]] 248; 249 %negx = fsub <2 x float> <float -0.0, float -0.0>, %x 250 %negy = fsub <2 x float> <float -0.0, float -0.0>, %y 251 %r = call <2 x float> @llvm.maximum.v2f32(<2 x float> %negx, <2 x float> %negy) 252 ret <2 x float> %r 253} 254 255define <2 x float> @unary_neg_neg(<2 x float> %x, <2 x float> %y) { 256; CHECK-LABEL: @unary_neg_neg( 257; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]]) 258; CHECK-NEXT: [[R:%.*]] = fneg <2 x float> [[TMP1]] 259; CHECK-NEXT: ret <2 x float> [[R]] 260; 261 %negx = fneg <2 x float> %x 262 %negy = fneg <2 x float> %y 263 %r = call <2 x float> @llvm.maximum.v2f32(<2 x float> %negx, <2 x float> %negy) 264 ret <2 x float> %r 265} 266 267; FMF is not required, but it should be propagated from the intrinsic (not the fnegs). 268 269define float @neg_neg_vec_fmf(float %x, float %y) { 270; CHECK-LABEL: @neg_neg_vec_fmf( 271; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) 272; CHECK-NEXT: [[R:%.*]] = fneg fast float [[TMP1]] 273; CHECK-NEXT: ret float [[R]] 274; 275 %negx = fsub arcp float -0.0, %x 276 %negy = fsub afn float -0.0, %y 277 %r = call fast float @llvm.maximum.f32(float %negx, float %negy) 278 ret float %r 279} 280 281define float @unary_neg_neg_vec_fmf(float %x, float %y) { 282; CHECK-LABEL: @unary_neg_neg_vec_fmf( 283; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) 284; CHECK-NEXT: [[R:%.*]] = fneg fast float [[TMP1]] 285; CHECK-NEXT: ret float [[R]] 286; 287 %negx = fneg arcp float %x 288 %negy = fneg afn float %y 289 %r = call fast float @llvm.maximum.f32(float %negx, float %negy) 290 ret float %r 291} 292 293; 1 extra use of an intermediate value should still allow the fold, 294; but 2 would require more instructions than we started with. 295 296declare void @use(float) 297define float @neg_neg_extra_use_x(float %x, float %y) { 298; CHECK-LABEL: @neg_neg_extra_use_x( 299; CHECK-NEXT: [[NEGX:%.*]] = fneg float [[X:%.*]] 300; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.minimum.f32(float [[X]], float [[Y:%.*]]) 301; CHECK-NEXT: [[R:%.*]] = fneg float [[TMP1]] 302; CHECK-NEXT: call void @use(float [[NEGX]]) 303; CHECK-NEXT: ret float [[R]] 304; 305 %negx = fsub float -0.0, %x 306 %negy = fsub float -0.0, %y 307 %r = call float @llvm.maximum.f32(float %negx, float %negy) 308 call void @use(float %negx) 309 ret float %r 310} 311 312define float @unary_neg_neg_extra_use_x(float %x, float %y) { 313; CHECK-LABEL: @unary_neg_neg_extra_use_x( 314; CHECK-NEXT: [[NEGX:%.*]] = fneg float [[X:%.*]] 315; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.minimum.f32(float [[X]], float [[Y:%.*]]) 316; CHECK-NEXT: [[R:%.*]] = fneg float [[TMP1]] 317; CHECK-NEXT: call void @use(float [[NEGX]]) 318; CHECK-NEXT: ret float [[R]] 319; 320 %negx = fneg float %x 321 %negy = fneg float %y 322 %r = call float @llvm.maximum.f32(float %negx, float %negy) 323 call void @use(float %negx) 324 ret float %r 325} 326 327define float @neg_neg_extra_use_y(float %x, float %y) { 328; CHECK-LABEL: @neg_neg_extra_use_y( 329; CHECK-NEXT: [[NEGY:%.*]] = fneg float [[Y:%.*]] 330; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y]]) 331; CHECK-NEXT: [[R:%.*]] = fneg float [[TMP1]] 332; CHECK-NEXT: call void @use(float [[NEGY]]) 333; CHECK-NEXT: ret float [[R]] 334; 335 %negx = fsub float -0.0, %x 336 %negy = fsub float -0.0, %y 337 %r = call float @llvm.maximum.f32(float %negx, float %negy) 338 call void @use(float %negy) 339 ret float %r 340} 341 342define float @unary_neg_neg_extra_use_y(float %x, float %y) { 343; CHECK-LABEL: @unary_neg_neg_extra_use_y( 344; CHECK-NEXT: [[NEGY:%.*]] = fneg float [[Y:%.*]] 345; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y]]) 346; CHECK-NEXT: [[R:%.*]] = fneg float [[TMP1]] 347; CHECK-NEXT: call void @use(float [[NEGY]]) 348; CHECK-NEXT: ret float [[R]] 349; 350 %negx = fneg float %x 351 %negy = fneg float %y 352 %r = call float @llvm.maximum.f32(float %negx, float %negy) 353 call void @use(float %negy) 354 ret float %r 355} 356 357define float @neg_neg_extra_use_x_and_y(float %x, float %y) { 358; CHECK-LABEL: @neg_neg_extra_use_x_and_y( 359; CHECK-NEXT: [[NEGX:%.*]] = fneg float [[X:%.*]] 360; CHECK-NEXT: [[NEGY:%.*]] = fneg float [[Y:%.*]] 361; CHECK-NEXT: [[R:%.*]] = call float @llvm.maximum.f32(float [[NEGX]], float [[NEGY]]) 362; CHECK-NEXT: call void @use(float [[NEGX]]) 363; CHECK-NEXT: call void @use(float [[NEGY]]) 364; CHECK-NEXT: ret float [[R]] 365; 366 %negx = fsub float -0.0, %x 367 %negy = fsub float -0.0, %y 368 %r = call float @llvm.maximum.f32(float %negx, float %negy) 369 call void @use(float %negx) 370 call void @use(float %negy) 371 ret float %r 372} 373 374define float @unary_neg_neg_extra_use_x_and_y(float %x, float %y) { 375; CHECK-LABEL: @unary_neg_neg_extra_use_x_and_y( 376; CHECK-NEXT: [[NEGX:%.*]] = fneg float [[X:%.*]] 377; CHECK-NEXT: [[NEGY:%.*]] = fneg float [[Y:%.*]] 378; CHECK-NEXT: [[R:%.*]] = call float @llvm.maximum.f32(float [[NEGX]], float [[NEGY]]) 379; CHECK-NEXT: call void @use(float [[NEGX]]) 380; CHECK-NEXT: call void @use(float [[NEGY]]) 381; CHECK-NEXT: ret float [[R]] 382; 383 %negx = fneg float %x 384 %negy = fneg float %y 385 %r = call float @llvm.maximum.f32(float %negx, float %negy) 386 call void @use(float %negx) 387 call void @use(float %negy) 388 ret float %r 389} 390 391define float @reduce_precision(float %x, float %y) { 392; CHECK-LABEL: @reduce_precision( 393; CHECK-NEXT: [[MAXIMUM:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) 394; CHECK-NEXT: ret float [[MAXIMUM]] 395; 396 %x.ext = fpext float %x to double 397 %y.ext = fpext float %y to double 398 %maximum = call double @llvm.maximum.f64(double %x.ext, double %y.ext) 399 %trunc = fptrunc double %maximum to float 400 ret float %trunc 401} 402 403define float @reduce_precision_fmf(float %x, float %y) { 404; CHECK-LABEL: @reduce_precision_fmf( 405; CHECK-NEXT: [[MAXIMUM:%.*]] = call nnan float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) 406; CHECK-NEXT: ret float [[MAXIMUM]] 407; 408 %x.ext = fpext float %x to double 409 %y.ext = fpext float %y to double 410 %maximum = call nnan double @llvm.maximum.f64(double %x.ext, double %y.ext) 411 %trunc = fptrunc double %maximum to float 412 ret float %trunc 413} 414 415define float @negated_op(float %x) { 416; CHECK-LABEL: @negated_op( 417; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]]) 418; CHECK-NEXT: ret float [[TMP1]] 419; 420 %negx = fneg float %x 421 %r = call float @llvm.maximum.f32(float %x, float %negx) 422 ret float %r 423} 424 425define <2 x double> @negated_op_fmf_commute_vec(<2 x double> %x) { 426; CHECK-LABEL: @negated_op_fmf_commute_vec( 427; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]]) 428; CHECK-NEXT: ret <2 x double> [[TMP1]] 429; 430 %negx = fneg <2 x double> %x 431 %r = call nsz nnan ninf <2 x double> @llvm.maximum.v2f64(<2 x double> %negx, <2 x double> %x) 432 ret <2 x double> %r 433} 434 435define float @negated_op_extra_use(float %x) { 436; CHECK-LABEL: @negated_op_extra_use( 437; CHECK-NEXT: [[NEGX:%.*]] = fneg float [[X:%.*]] 438; CHECK-NEXT: call void @use(float [[NEGX]]) 439; CHECK-NEXT: [[R:%.*]] = call float @llvm.maximum.f32(float [[NEGX]], float [[X]]) 440; CHECK-NEXT: ret float [[R]] 441; 442 %negx = fneg float %x 443 call void @use(float %negx) 444 %r = call float @llvm.maximum.f32(float %negx, float %x) 445 ret float %r 446} 447