1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -instcombine < %s | FileCheck %s 3 4declare float @llvm.minimum.f32(float, float) 5declare <2 x float> @llvm.minimum.v2f32(<2 x float>, <2 x float>) 6declare <4 x float> @llvm.minimum.v4f32(<4 x float>, <4 x float>) 7 8declare double @llvm.minimum.f64(double, double) 9declare <2 x double> @llvm.minimum.v2f64(<2 x double>, <2 x double>) 10 11declare float @llvm.maximum.f32(float, float) 12 13define float @constant_fold_minimum_f32() { 14; CHECK-LABEL: @constant_fold_minimum_f32( 15; CHECK-NEXT: ret float 1.000000e+00 16; 17 %x = call float @llvm.minimum.f32(float 1.0, float 2.0) 18 ret float %x 19} 20 21define float @constant_fold_minimum_f32_inv() { 22; CHECK-LABEL: @constant_fold_minimum_f32_inv( 23; CHECK-NEXT: ret float 1.000000e+00 24; 25 %x = call float @llvm.minimum.f32(float 2.0, float 1.0) 26 ret float %x 27} 28 29define float @constant_fold_minimum_f32_nan0() { 30; CHECK-LABEL: @constant_fold_minimum_f32_nan0( 31; CHECK-NEXT: ret float 0x7FF8000000000000 32; 33 %x = call float @llvm.minimum.f32(float 0x7FF8000000000000, float 2.0) 34 ret float %x 35} 36 37define float @constant_fold_minimum_f32_nan1() { 38; CHECK-LABEL: @constant_fold_minimum_f32_nan1( 39; CHECK-NEXT: ret float 0x7FF8000000000000 40; 41 %x = call float @llvm.minimum.f32(float 2.0, float 0x7FF8000000000000) 42 ret float %x 43} 44 45define float @constant_fold_minimum_f32_nan_nan() { 46; CHECK-LABEL: @constant_fold_minimum_f32_nan_nan( 47; CHECK-NEXT: ret float 0x7FF8000000000000 48; 49 %x = call float @llvm.minimum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000) 50 ret float %x 51} 52 53define float @constant_fold_minimum_f32_p0_p0() { 54; CHECK-LABEL: @constant_fold_minimum_f32_p0_p0( 55; CHECK-NEXT: ret float 0.000000e+00 56; 57 %x = call float @llvm.minimum.f32(float 0.0, float 0.0) 58 ret float %x 59} 60 61define float @constant_fold_minimum_f32_p0_n0() { 62; CHECK-LABEL: @constant_fold_minimum_f32_p0_n0( 63; CHECK-NEXT: ret float -0.000000e+00 64; 65 %x = call float @llvm.minimum.f32(float 0.0, float -0.0) 66 ret float %x 67} 68 69define float @constant_fold_minimum_f32_n0_p0() { 70; CHECK-LABEL: @constant_fold_minimum_f32_n0_p0( 71; CHECK-NEXT: ret float -0.000000e+00 72; 73 %x = call float @llvm.minimum.f32(float -0.0, float 0.0) 74 ret float %x 75} 76 77define float @constant_fold_minimum_f32_n0_n0() { 78; CHECK-LABEL: @constant_fold_minimum_f32_n0_n0( 79; CHECK-NEXT: ret float -0.000000e+00 80; 81 %x = call float @llvm.minimum.f32(float -0.0, float -0.0) 82 ret float %x 83} 84 85define <4 x float> @constant_fold_minimum_v4f32() { 86; CHECK-LABEL: @constant_fold_minimum_v4f32( 87; CHECK-NEXT: ret <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 5.000000e+00> 88; 89 %x = call <4 x float> @llvm.minimum.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>) 90 ret <4 x float> %x 91} 92 93define double @constant_fold_minimum_f64() { 94; CHECK-LABEL: @constant_fold_minimum_f64( 95; CHECK-NEXT: ret double 1.000000e+00 96; 97 %x = call double @llvm.minimum.f64(double 1.0, double 2.0) 98 ret double %x 99} 100 101define double @constant_fold_minimum_f64_nan0() { 102; CHECK-LABEL: @constant_fold_minimum_f64_nan0( 103; CHECK-NEXT: ret double 0x7FF8000000000000 104; 105 %x = call double @llvm.minimum.f64(double 0x7FF8000000000000, double 2.0) 106 ret double %x 107} 108 109define double @constant_fold_minimum_f64_nan1() { 110; CHECK-LABEL: @constant_fold_minimum_f64_nan1( 111; CHECK-NEXT: ret double 0x7FF8000000000000 112; 113 %x = call double @llvm.minimum.f64(double 2.0, double 0x7FF8000000000000) 114 ret double %x 115} 116 117define double @constant_fold_minimum_f64_nan_nan() { 118; CHECK-LABEL: @constant_fold_minimum_f64_nan_nan( 119; CHECK-NEXT: ret double 0x7FF8000000000000 120; 121 %x = call double @llvm.minimum.f64(double 0x7FF8000000000000, double 0x7FF8000000000000) 122 ret double %x 123} 124 125define float @canonicalize_constant_minimum_f32(float %x) { 126; CHECK-LABEL: @canonicalize_constant_minimum_f32( 127; CHECK-NEXT: [[Y:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float 1.000000e+00) 128; CHECK-NEXT: ret float [[Y]] 129; 130 %y = call float @llvm.minimum.f32(float 1.0, float %x) 131 ret float %y 132} 133 134define float @minimum_f32_nan_val(float %x) { 135; CHECK-LABEL: @minimum_f32_nan_val( 136; CHECK-NEXT: ret float 0x7FF8000000000000 137; 138 %y = call float @llvm.minimum.f32(float 0x7FF8000000000000, float %x) 139 ret float %y 140} 141 142define float @minimum_f32_val_nan(float %x) { 143; CHECK-LABEL: @minimum_f32_val_nan( 144; CHECK-NEXT: ret float 0x7FF8000000000000 145; 146 %y = call float @llvm.minimum.f32(float %x, float 0x7FF8000000000000) 147 ret float %y 148} 149 150define float @minimum_f32_1_minimum_val_p0(float %x) { 151; CHECK-LABEL: @minimum_f32_1_minimum_val_p0( 152; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minimum.f32(float %x, float 0.000000e+00) 153; CHECK-NEXT: ret float [[RES]] 154 %y = call float @llvm.minimum.f32(float %x, float 0.0) 155 %z = call float @llvm.minimum.f32(float %y, float 1.0) 156 ret float %z 157} 158 159define float @minimum_f32_1_minimum_p0_val_fast(float %x) { 160; CHECK-LABEL: @minimum_f32_1_minimum_p0_val_fast( 161; CHECK-NEXT: [[RES:%.*]] = call fast float @llvm.minimum.f32(float %x, float 0.000000e+00) 162; CHECK-NEXT: ret float [[RES]] 163 %y = call float @llvm.minimum.f32(float 0.0, float %x) 164 %z = call fast float @llvm.minimum.f32(float %y, float 1.0) 165 ret float %z 166} 167 168define float @minimum_f32_1_minimum_p0_val_nnan_ninf(float %x) { 169; CHECK-LABEL: @minimum_f32_1_minimum_p0_val_nnan_ninf( 170; CHECK-NEXT: [[RES:%.*]] = call nnan ninf float @llvm.minimum.f32(float %x, float 0.000000e+00) 171; CHECK-NEXT: ret float [[RES]] 172 %y = call float @llvm.minimum.f32(float 0.0, float %x) 173 %z = call nnan ninf float @llvm.minimum.f32(float %y, float 1.0) 174 ret float %z 175} 176 177define float @minimum_f32_p0_minimum_val_n0(float %x) { 178; CHECK-LABEL: @minimum_f32_p0_minimum_val_n0( 179; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minimum.f32(float %x, float -0.000000e+00) 180; CHECK-NEXT: ret float [[RES]] 181 %y = call float @llvm.minimum.f32(float %x, float -0.0) 182 %z = call float @llvm.minimum.f32(float %y, float 0.0) 183 ret float %z 184} 185 186define float @minimum_f32_1_minimum_p0_val(float %x) { 187; CHECK-LABEL: @minimum_f32_1_minimum_p0_val( 188; CHECK-NEXT: [[RES:%.*]] = call float @llvm.minimum.f32(float %x, float 0.000000e+00) 189; CHECK-NEXT: ret float [[RES]] 190 %y = call float @llvm.minimum.f32(float 0.0, float %x) 191 %z = call float @llvm.minimum.f32(float %y, float 1.0) 192 ret float %z 193} 194 195define <2 x float> @minimum_f32_1_minimum_val_p0_val_v2f32(<2 x float> %x) { 196; CHECK-LABEL: @minimum_f32_1_minimum_val_p0_val_v2f32( 197; CHECK-NEXT: [[RES:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> zeroinitializer) 198; CHECK-NEXT: ret <2 x float> [[RES]] 199 %y = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> zeroinitializer) 200 %z = call <2 x float> @llvm.minimum.v2f32(<2 x float> %y, <2 x float><float 1.0, float 1.0>) 201 ret <2 x float> %z 202} 203 204define float @minimum4(float %x, float %y, float %z, float %w) { 205; CHECK-LABEL: @minimum4( 206; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) 207; CHECK-NEXT: [[B:%.*]] = call float @llvm.minimum.f32(float [[Z:%.*]], float [[W:%.*]]) 208; CHECK-NEXT: [[C:%.*]] = call float @llvm.minimum.f32(float [[A]], float [[B]]) 209; CHECK-NEXT: ret float [[C]] 210; 211 %a = call float @llvm.minimum.f32(float %x, float %y) 212 %b = call float @llvm.minimum.f32(float %z, float %w) 213 %c = call float @llvm.minimum.f32(float %a, float %b) 214 ret float %c 215} 216 217define float @minimum_x_maximum_x_y(float %x, float %y) { 218; CHECK-LABEL: @minimum_x_maximum_x_y( 219; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximum.f32(float [[X:%.*]], float [[Y:%.*]]) 220; CHECK-NEXT: [[B:%.*]] = call float @llvm.minimum.f32(float [[X]], float [[A]]) 221; CHECK-NEXT: ret float [[B]] 222; 223 %a = call float @llvm.maximum.f32(float %x, float %y) 224 %b = call float @llvm.minimum.f32(float %x, float %a) 225 ret float %b 226} 227 228define float @maximum_x_minimum_x_y(float %x, float %y) { 229; CHECK-LABEL: @maximum_x_minimum_x_y( 230; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimum.f32(float [[X:%.*]], float [[Y:%.*]]) 231; CHECK-NEXT: [[B:%.*]] = call float @llvm.maximum.f32(float [[X]], float [[A]]) 232; CHECK-NEXT: ret float [[B]] 233; 234 %a = call float @llvm.minimum.f32(float %x, float %y) 235 %b = call float @llvm.maximum.f32(float %x, float %a) 236 ret float %b 237} 238 239; PR37405 - https://bugs.llvm.org/show_bug.cgi?id=37405 240 241define double @neg_neg(double %x, double %y) { 242; CHECK-LABEL: @neg_neg( 243; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X:%.*]], double [[Y:%.*]]) 244; CHECK-NEXT: [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]] 245; CHECK-NEXT: ret double [[R]] 246; 247 %negx = fsub double -0.0, %x 248 %negy = fsub double -0.0, %y 249 %r = call double @llvm.minimum.f64(double %negx, double %negy) 250 ret double %r 251} 252 253define double @unary_neg_neg(double %x, double %y) { 254; CHECK-LABEL: @unary_neg_neg( 255; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X:%.*]], double [[Y:%.*]]) 256; CHECK-NEXT: [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]] 257; CHECK-NEXT: ret double [[R]] 258; 259 %negx = fneg double %x 260 %negy = fneg double %y 261 %r = call double @llvm.minimum.f64(double %negx, double %negy) 262 ret double %r 263} 264 265; FMF is not required, but it should be propagated from the intrinsic (not the fnegs). 266; Also, make sure this works with vectors. 267 268define <2 x double> @neg_neg_vec_fmf(<2 x double> %x, <2 x double> %y) { 269; CHECK-LABEL: @neg_neg_vec_fmf( 270; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf <2 x double> @llvm.maximum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]]) 271; CHECK-NEXT: [[R:%.*]] = fsub nnan ninf <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[TMP1]] 272; CHECK-NEXT: ret <2 x double> [[R]] 273; 274 %negx = fsub reassoc <2 x double> <double -0.0, double -0.0>, %x 275 %negy = fsub fast <2 x double> <double -0.0, double -0.0>, %y 276 %r = call nnan ninf <2 x double> @llvm.minimum.v2f64(<2 x double> %negx, <2 x double> %negy) 277 ret <2 x double> %r 278} 279 280define <2 x double> @unary_neg_neg_vec_fmf(<2 x double> %x, <2 x double> %y) { 281; CHECK-LABEL: @unary_neg_neg_vec_fmf( 282; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf <2 x double> @llvm.maximum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]]) 283; CHECK-NEXT: [[R:%.*]] = fsub nnan ninf <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[TMP1]] 284; CHECK-NEXT: ret <2 x double> [[R]] 285; 286 %negx = fneg reassoc <2 x double> %x 287 %negy = fneg fast <2 x double> %y 288 %r = call nnan ninf <2 x double> @llvm.minimum.v2f64(<2 x double> %negx, <2 x double> %negy) 289 ret <2 x double> %r 290} 291 292; 1 extra use of an intermediate value should still allow the fold, 293; but 2 would require more instructions than we started with. 294 295declare void @use(double) 296define double @neg_neg_extra_use_x(double %x, double %y) { 297; CHECK-LABEL: @neg_neg_extra_use_x( 298; CHECK-NEXT: [[NEGX:%.*]] = fsub double -0.000000e+00, [[X:%.*]] 299; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X]], double [[Y:%.*]]) 300; CHECK-NEXT: [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]] 301; CHECK-NEXT: call void @use(double [[NEGX]]) 302; CHECK-NEXT: ret double [[R]] 303; 304 %negx = fsub double -0.0, %x 305 %negy = fsub double -0.0, %y 306 %r = call double @llvm.minimum.f64(double %negx, double %negy) 307 call void @use(double %negx) 308 ret double %r 309} 310 311define double @unary_neg_neg_extra_use_x(double %x, double %y) { 312; CHECK-LABEL: @unary_neg_neg_extra_use_x( 313; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X:%.*]] 314; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X]], double [[Y:%.*]]) 315; CHECK-NEXT: [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]] 316; CHECK-NEXT: call void @use(double [[NEGX]]) 317; CHECK-NEXT: ret double [[R]] 318; 319 %negx = fneg double %x 320 %negy = fneg double %y 321 %r = call double @llvm.minimum.f64(double %negx, double %negy) 322 call void @use(double %negx) 323 ret double %r 324} 325 326define double @neg_neg_extra_use_y(double %x, double %y) { 327; CHECK-LABEL: @neg_neg_extra_use_y( 328; CHECK-NEXT: [[NEGY:%.*]] = fsub double -0.000000e+00, [[Y:%.*]] 329; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X:%.*]], double [[Y]]) 330; CHECK-NEXT: [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]] 331; CHECK-NEXT: call void @use(double [[NEGY]]) 332; CHECK-NEXT: ret double [[R]] 333; 334 %negx = fsub double -0.0, %x 335 %negy = fsub double -0.0, %y 336 %r = call double @llvm.minimum.f64(double %negx, double %negy) 337 call void @use(double %negy) 338 ret double %r 339} 340 341define double @unary_neg_neg_extra_use_y(double %x, double %y) { 342; CHECK-LABEL: @unary_neg_neg_extra_use_y( 343; CHECK-NEXT: [[NEGY:%.*]] = fneg double [[Y:%.*]] 344; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.maximum.f64(double [[X:%.*]], double [[Y]]) 345; CHECK-NEXT: [[R:%.*]] = fsub double -0.000000e+00, [[TMP1]] 346; CHECK-NEXT: call void @use(double [[NEGY]]) 347; CHECK-NEXT: ret double [[R]] 348; 349 %negx = fneg double %x 350 %negy = fneg double %y 351 %r = call double @llvm.minimum.f64(double %negx, double %negy) 352 call void @use(double %negy) 353 ret double %r 354} 355 356define double @neg_neg_extra_use_x_and_y(double %x, double %y) { 357; CHECK-LABEL: @neg_neg_extra_use_x_and_y( 358; CHECK-NEXT: [[NEGX:%.*]] = fsub double -0.000000e+00, [[X:%.*]] 359; CHECK-NEXT: [[NEGY:%.*]] = fsub double -0.000000e+00, [[Y:%.*]] 360; CHECK-NEXT: [[R:%.*]] = call double @llvm.minimum.f64(double [[NEGX]], double [[NEGY]]) 361; CHECK-NEXT: call void @use(double [[NEGX]]) 362; CHECK-NEXT: call void @use(double [[NEGY]]) 363; CHECK-NEXT: ret double [[R]] 364; 365 %negx = fsub double -0.0, %x 366 %negy = fsub double -0.0, %y 367 %r = call double @llvm.minimum.f64(double %negx, double %negy) 368 call void @use(double %negx) 369 call void @use(double %negy) 370 ret double %r 371} 372 373define double @unary_neg_neg_extra_use_x_and_y(double %x, double %y) { 374; CHECK-LABEL: @unary_neg_neg_extra_use_x_and_y( 375; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X:%.*]] 376; CHECK-NEXT: [[NEGY:%.*]] = fneg double [[Y:%.*]] 377; CHECK-NEXT: [[R:%.*]] = call double @llvm.minimum.f64(double [[NEGX]], double [[NEGY]]) 378; CHECK-NEXT: call void @use(double [[NEGX]]) 379; CHECK-NEXT: call void @use(double [[NEGY]]) 380; CHECK-NEXT: ret double [[R]] 381; 382 %negx = fneg double %x 383 %negy = fneg double %y 384 %r = call double @llvm.minimum.f64(double %negx, double %negy) 385 call void @use(double %negx) 386 call void @use(double %negy) 387 ret double %r 388} 389