1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=instcombine %s | FileCheck %s 3 4@var = external global i32, align 4 5 6; fcmp olt fabs(x), smallest_normalized_number -> fcmp oeq x, 0.0 7; https://alive2.llvm.org/ce/z/fib8cf 8define void @denormal_input_preserve_sign_fcmp_olt_smallest_normalized(float %f32, double %f64, half %f16) #0 { 9; CHECK-LABEL: @denormal_input_preserve_sign_fcmp_olt_smallest_normalized( 10; CHECK-NEXT: [[CMPF32:%.*]] = fcmp oeq float [[F32:%.*]], 0.000000e+00 11; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 12; CHECK-NEXT: [[CMPF64:%.*]] = fcmp oeq double [[F64:%.*]], 0.000000e+00 13; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 14; CHECK-NEXT: [[CMPF16:%.*]] = fcmp oeq half [[F16:%.*]], 0xH0000 15; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 16; CHECK-NEXT: [[CMPF32_FLAGS:%.*]] = fcmp oeq float [[F32]], 0.000000e+00 17; CHECK-NEXT: store volatile i1 [[CMPF32_FLAGS]], ptr @var, align 1 18; CHECK-NEXT: ret void 19; 20 %f32.fabs = call float @llvm.fabs.f32(float %f32) 21 %cmpf32 = fcmp olt float %f32.fabs, 0x3810000000000000 22 store volatile i1 %cmpf32, ptr @var 23 24 %f64.fabs = call double @llvm.fabs.f64(double %f64) 25 %cmpf64 = fcmp olt double %f64.fabs, 0x10000000000000 26 store volatile i1 %cmpf64, ptr @var 27 28 %f16.fabs = call half @llvm.fabs.f16(half %f16) 29 %cmpf16 = fcmp olt half %f16.fabs, 0xH0400 30 store volatile i1 %cmpf16, ptr @var 31 32 %f32.fabs.flags = call nsz nnan float @llvm.fabs.f32(float %f32) 33 %cmpf32.flags = fcmp olt float %f32.fabs.flags, 0x3810000000000000 34 store volatile i1 %cmpf32.flags, ptr @var 35 36 ret void 37} 38 39; fcmp uge fabs(x), smallest_normalized_number -> fcmp une x, 0.0 40; https://alive2.llvm.org/ce/z/xmqBXx 41define void @denormal_input_preserve_sign_fcmp_uge_smallest_normalized(float %f32, double %f64, half %f16) #0 { 42; CHECK-LABEL: @denormal_input_preserve_sign_fcmp_uge_smallest_normalized( 43; CHECK-NEXT: [[CMPF32:%.*]] = fcmp une float [[F32:%.*]], 0.000000e+00 44; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 45; CHECK-NEXT: [[CMPF64:%.*]] = fcmp une double [[F64:%.*]], 0.000000e+00 46; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 47; CHECK-NEXT: [[CMPF16:%.*]] = fcmp une half [[F16:%.*]], 0xH0000 48; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 49; CHECK-NEXT: ret void 50; 51 %f32.fabs = call float @llvm.fabs.f32(float %f32) 52 %cmpf32 = fcmp uge float %f32.fabs, 0x3810000000000000 53 store volatile i1 %cmpf32, ptr @var 54 55 %f64.fabs = call double @llvm.fabs.f64(double %f64) 56 %cmpf64 = fcmp uge double %f64.fabs, 0x10000000000000 57 store volatile i1 %cmpf64, ptr @var 58 59 %f16.fabs = call half @llvm.fabs.f16(half %f16) 60 %cmpf16 = fcmp uge half %f16.fabs, 0xH0400 61 store volatile i1 %cmpf16, ptr @var 62 ret void 63} 64 65; fcmp oge fabs(x), smallest_normalized_number -> fcmp one x, 0.0 66; https://alive2.llvm.org/ce/z/ZucNzF 67define void @denormal_input_preserve_sign_fcmp_oge_smallest_normalized(float %f32, double %f64, half %f16) #0 { 68; CHECK-LABEL: @denormal_input_preserve_sign_fcmp_oge_smallest_normalized( 69; CHECK-NEXT: [[CMPF32:%.*]] = fcmp one float [[F32:%.*]], 0.000000e+00 70; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 71; CHECK-NEXT: [[CMPF64:%.*]] = fcmp one double [[F64:%.*]], 0.000000e+00 72; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 73; CHECK-NEXT: [[CMPF16:%.*]] = fcmp one half [[F16:%.*]], 0xH0000 74; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 75; CHECK-NEXT: ret void 76; 77 %f32.fabs = call float @llvm.fabs.f32(float %f32) 78 %cmpf32 = fcmp oge float %f32.fabs, 0x3810000000000000 79 store volatile i1 %cmpf32, ptr @var 80 81 %f64.fabs = call double @llvm.fabs.f64(double %f64) 82 %cmpf64 = fcmp oge double %f64.fabs, 0x10000000000000 83 store volatile i1 %cmpf64, ptr @var 84 85 %f16.fabs = call half @llvm.fabs.f16(half %f16) 86 %cmpf16 = fcmp oge half %f16.fabs, 0xH0400 87 store volatile i1 %cmpf16, ptr @var 88 ret void 89} 90 91; fcmp ult fabs(x), smallest_normalized_number -> fcmp ueq x, 0.0 92; https://alive2.llvm.org/ce/z/csAhZ2 93define void @denormal_input_preserve_sign_fcmp_ult_smallest_normalized(float %f32, double %f64, half %f16) #0 { 94; CHECK-LABEL: @denormal_input_preserve_sign_fcmp_ult_smallest_normalized( 95; CHECK-NEXT: [[CMPF32:%.*]] = fcmp ueq float [[F32:%.*]], 0.000000e+00 96; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 97; CHECK-NEXT: [[CMPF64:%.*]] = fcmp ueq double [[F64:%.*]], 0.000000e+00 98; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 99; CHECK-NEXT: [[CMPF16:%.*]] = fcmp ueq half [[F16:%.*]], 0xH0000 100; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 101; CHECK-NEXT: ret void 102; 103 %f32.fabs = call float @llvm.fabs.f32(float %f32) 104 %cmpf32 = fcmp ult float %f32.fabs, 0x3810000000000000 105 store volatile i1 %cmpf32, ptr @var 106 107 %f64.fabs = call double @llvm.fabs.f64(double %f64) 108 %cmpf64 = fcmp ult double %f64.fabs, 0x10000000000000 109 store volatile i1 %cmpf64, ptr @var 110 111 %f16.fabs = call half @llvm.fabs.f16(half %f16) 112 %cmpf16 = fcmp ult half %f16.fabs, 0xH0400 113 store volatile i1 %cmpf16, ptr @var 114 ret void 115} 116 117define void @denormal_input_preserve_sign_vector_fcmp_olt_smallest_normalized(<2 x float> %f32, <2 x double> %f64, <2 x half> %f16) #0 { 118; CHECK-LABEL: @denormal_input_preserve_sign_vector_fcmp_olt_smallest_normalized( 119; CHECK-NEXT: [[CMPF32:%.*]] = fcmp oeq <2 x float> [[F32:%.*]], zeroinitializer 120; CHECK-NEXT: store volatile <2 x i1> [[CMPF32]], ptr @var, align 1 121; CHECK-NEXT: [[CMPF64:%.*]] = fcmp oeq <2 x double> [[F64:%.*]], zeroinitializer 122; CHECK-NEXT: store volatile <2 x i1> [[CMPF64]], ptr @var, align 1 123; CHECK-NEXT: [[CMPF16:%.*]] = fcmp oeq <2 x half> [[F16:%.*]], zeroinitializer 124; CHECK-NEXT: store volatile <2 x i1> [[CMPF16]], ptr @var, align 1 125; CHECK-NEXT: ret void 126; 127 %f32.fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %f32) 128 %cmpf32 = fcmp olt <2 x float> %f32.fabs, <float 0x3810000000000000, float 0x3810000000000000> 129 store volatile <2 x i1> %cmpf32, ptr @var 130 131 %f64.fabs = call <2 x double> @llvm.fabs.v2f64(<2 x double> %f64) 132 %cmpf64 = fcmp olt <2 x double> %f64.fabs, <double 0x10000000000000, double 0x10000000000000> 133 store volatile <2 x i1> %cmpf64, ptr @var 134 135 %f16.fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %f16) 136 %cmpf16 = fcmp olt <2 x half> %f16.fabs, <half 0xH0400, half 0xH0400> 137 store volatile <2 x i1> %cmpf16, ptr @var 138 ret void 139} 140 141define void @denormal_input_preserve_sign_vector_fcmp_uge_smallest_normalized(<2 x float> %f32, <2 x double> %f64, <2 x half> %f16) #0 { 142; CHECK-LABEL: @denormal_input_preserve_sign_vector_fcmp_uge_smallest_normalized( 143; CHECK-NEXT: [[CMPF32:%.*]] = fcmp une <2 x float> [[F32:%.*]], zeroinitializer 144; CHECK-NEXT: store volatile <2 x i1> [[CMPF32]], ptr @var, align 1 145; CHECK-NEXT: [[CMPF64:%.*]] = fcmp une <2 x double> [[F64:%.*]], zeroinitializer 146; CHECK-NEXT: store volatile <2 x i1> [[CMPF64]], ptr @var, align 1 147; CHECK-NEXT: [[CMPF16:%.*]] = fcmp une <2 x half> [[F16:%.*]], zeroinitializer 148; CHECK-NEXT: store volatile <2 x i1> [[CMPF16]], ptr @var, align 1 149; CHECK-NEXT: ret void 150; 151 %f32.fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %f32) 152 %cmpf32 = fcmp uge <2 x float> %f32.fabs, <float 0x3810000000000000, float 0x3810000000000000> 153 store volatile <2 x i1> %cmpf32, ptr @var 154 155 %f64.fabs = call <2 x double> @llvm.fabs.v2f64(<2 x double> %f64) 156 %cmpf64 = fcmp uge <2 x double> %f64.fabs, <double 0x10000000000000, double 0x10000000000000> 157 store volatile <2 x i1> %cmpf64, ptr @var 158 159 %f16.fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %f16) 160 %cmpf16 = fcmp uge <2 x half> %f16.fabs, <half 0xH0400, half 0xH0400> 161 store volatile <2 x i1> %cmpf16, ptr @var 162 ret void 163} 164 165define void @denormal_input_preserve_sign_vector_fcmp_oge_smallest_normalized(<2 x float> %f32, <2 x double> %f64, <2 x half> %f16) #0 { 166; CHECK-LABEL: @denormal_input_preserve_sign_vector_fcmp_oge_smallest_normalized( 167; CHECK-NEXT: [[CMPF32:%.*]] = fcmp one <2 x float> [[F32:%.*]], zeroinitializer 168; CHECK-NEXT: store volatile <2 x i1> [[CMPF32]], ptr @var, align 1 169; CHECK-NEXT: [[CMPF64:%.*]] = fcmp one <2 x double> [[F64:%.*]], zeroinitializer 170; CHECK-NEXT: store volatile <2 x i1> [[CMPF64]], ptr @var, align 1 171; CHECK-NEXT: [[CMPF16:%.*]] = fcmp one <2 x half> [[F16:%.*]], zeroinitializer 172; CHECK-NEXT: store volatile <2 x i1> [[CMPF16]], ptr @var, align 1 173; CHECK-NEXT: ret void 174; 175 %f32.fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %f32) 176 %cmpf32 = fcmp oge <2 x float> %f32.fabs, <float 0x3810000000000000, float 0x3810000000000000> 177 store volatile <2 x i1> %cmpf32, ptr @var 178 179 %f64.fabs = call <2 x double> @llvm.fabs.v2f64(<2 x double> %f64) 180 %cmpf64 = fcmp oge <2 x double> %f64.fabs, <double 0x10000000000000, double 0x10000000000000> 181 store volatile <2 x i1> %cmpf64, ptr @var 182 183 %f16.fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %f16) 184 %cmpf16 = fcmp oge <2 x half> %f16.fabs, <half 0xH0400, half 0xH0400> 185 store volatile <2 x i1> %cmpf16, ptr @var 186 ret void 187} 188 189define void @denormal_input_preserve_sign_vector_fcmp_ult_smallest_normalized(<2 x float> %f32, <2 x double> %f64, <2 x half> %f16) #0 { 190; CHECK-LABEL: @denormal_input_preserve_sign_vector_fcmp_ult_smallest_normalized( 191; CHECK-NEXT: [[CMPF32:%.*]] = fcmp ueq <2 x float> [[F32:%.*]], zeroinitializer 192; CHECK-NEXT: store volatile <2 x i1> [[CMPF32]], ptr @var, align 1 193; CHECK-NEXT: [[CMPF64:%.*]] = fcmp ueq <2 x double> [[F64:%.*]], zeroinitializer 194; CHECK-NEXT: store volatile <2 x i1> [[CMPF64]], ptr @var, align 1 195; CHECK-NEXT: [[CMPF16:%.*]] = fcmp ueq <2 x half> [[F16:%.*]], zeroinitializer 196; CHECK-NEXT: store volatile <2 x i1> [[CMPF16]], ptr @var, align 1 197; CHECK-NEXT: ret void 198; 199 %f32.fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %f32) 200 %cmpf32 = fcmp ult <2 x float> %f32.fabs, <float 0x3810000000000000, float 0x3810000000000000> 201 store volatile <2 x i1> %cmpf32, ptr @var 202 203 %f64.fabs = call <2 x double> @llvm.fabs.v2f64(<2 x double> %f64) 204 %cmpf64 = fcmp ult <2 x double> %f64.fabs, <double 0x10000000000000, double 0x10000000000000> 205 store volatile <2 x i1> %cmpf64, ptr @var 206 207 %f16.fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %f16) 208 %cmpf16 = fcmp ult <2 x half> %f16.fabs, <half 0xH0400, half 0xH0400> 209 store volatile <2 x i1> %cmpf16, ptr @var 210 ret void 211} 212 213; fcmp olt fabs(x), smallest_normalized_number -> fcmp oeq x, 0.0 214; https://alive2.llvm.org/ce/z/mpduXS 215define void @denormal_input_positive_zero_fcmp_olt_smallest_normalized(float %f32, double %f64, half %f16) #1 { 216; CHECK-LABEL: @denormal_input_positive_zero_fcmp_olt_smallest_normalized( 217; CHECK-NEXT: [[CMPF32:%.*]] = fcmp oeq float [[F32:%.*]], 0.000000e+00 218; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 219; CHECK-NEXT: [[CMPF64:%.*]] = fcmp oeq double [[F64:%.*]], 0.000000e+00 220; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 221; CHECK-NEXT: [[CMPF16:%.*]] = fcmp oeq half [[F16:%.*]], 0xH0000 222; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 223; CHECK-NEXT: ret void 224; 225 %f32.fabs = call float @llvm.fabs.f32(float %f32) 226 %cmpf32 = fcmp olt float %f32.fabs, 0x3810000000000000 227 store volatile i1 %cmpf32, ptr @var 228 229 %f64.fabs = call double @llvm.fabs.f64(double %f64) 230 %cmpf64 = fcmp olt double %f64.fabs, 0x10000000000000 231 store volatile i1 %cmpf64, ptr @var 232 233 %f16.fabs = call half @llvm.fabs.f16(half %f16) 234 %cmpf16 = fcmp olt half %f16.fabs, 0xH0400 235 store volatile i1 %cmpf16, ptr @var 236 ret void 237} 238 239; Should not fold with IEEE inputs. 240define void @denormal_input_ieee(float %f32, double %f64, half %f16) #2 { 241; CHECK-LABEL: @denormal_input_ieee( 242; CHECK-NEXT: [[F32_FABS:%.*]] = call float @llvm.fabs.f32(float [[F32:%.*]]) 243; CHECK-NEXT: [[CMPF32:%.*]] = fcmp olt float [[F32_FABS]], 0x3810000000000000 244; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 245; CHECK-NEXT: [[F64_FABS:%.*]] = call double @llvm.fabs.f64(double [[F64:%.*]]) 246; CHECK-NEXT: [[CMPF64:%.*]] = fcmp olt double [[F64_FABS]], 0x10000000000000 247; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 248; CHECK-NEXT: [[F16_FABS:%.*]] = call half @llvm.fabs.f16(half [[F16:%.*]]) 249; CHECK-NEXT: [[CMPF16:%.*]] = fcmp olt half [[F16_FABS]], 0xH0400 250; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 251; CHECK-NEXT: ret void 252; 253 %f32.fabs = call float @llvm.fabs.f32(float %f32) 254 %cmpf32 = fcmp olt float %f32.fabs, 0x3810000000000000 255 store volatile i1 %cmpf32, ptr @var 256 257 %f64.fabs = call double @llvm.fabs.f64(double %f64) 258 %cmpf64 = fcmp olt double %f64.fabs, 0x10000000000000 259 store volatile i1 %cmpf64, ptr @var 260 261 %f16.fabs = call half @llvm.fabs.f16(half %f16) 262 %cmpf16 = fcmp olt half %f16.fabs, 0xH0400 263 store volatile i1 %cmpf16, ptr @var 264 ret void 265} 266 267; Only f32 case should fold. 268define void @denormal_input_preserve_sign_f32_only(float %f32, double %f64, half %f16) #3 { 269; CHECK-LABEL: @denormal_input_preserve_sign_f32_only( 270; CHECK-NEXT: [[CMPF32:%.*]] = fcmp oeq float [[F32:%.*]], 0.000000e+00 271; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 272; CHECK-NEXT: [[F64_FABS:%.*]] = call double @llvm.fabs.f64(double [[F64:%.*]]) 273; CHECK-NEXT: [[CMPF64:%.*]] = fcmp olt double [[F64_FABS]], 0x10000000000000 274; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 275; CHECK-NEXT: [[F16_FABS:%.*]] = call half @llvm.fabs.f16(half [[F16:%.*]]) 276; CHECK-NEXT: [[CMPF16:%.*]] = fcmp olt half [[F16_FABS]], 0xH0400 277; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 278; CHECK-NEXT: ret void 279; 280 %f32.fabs = call float @llvm.fabs.f32(float %f32) 281 %cmpf32 = fcmp olt float %f32.fabs, 0x3810000000000000 282 store volatile i1 %cmpf32, ptr @var 283 284 %f64.fabs = call double @llvm.fabs.f64(double %f64) 285 %cmpf64 = fcmp olt double %f64.fabs, 0x10000000000000 286 store volatile i1 %cmpf64, ptr @var 287 288 %f16.fabs = call half @llvm.fabs.f16(half %f16) 289 %cmpf16 = fcmp olt half %f16.fabs, 0xH0400 290 store volatile i1 %cmpf16, ptr @var 291 ret void 292} 293 294define void @wrong_fcmp_type_ole(float %f32, double %f64, half %f16) #0 { 295; CHECK-LABEL: @wrong_fcmp_type_ole( 296; CHECK-NEXT: [[F32_FABS:%.*]] = call float @llvm.fabs.f32(float [[F32:%.*]]) 297; CHECK-NEXT: [[CMPF32:%.*]] = fcmp ole float [[F32_FABS]], 0x3810000000000000 298; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 299; CHECK-NEXT: [[F64_FABS:%.*]] = call double @llvm.fabs.f64(double [[F64:%.*]]) 300; CHECK-NEXT: [[CMPF64:%.*]] = fcmp ole double [[F64_FABS]], 0x10000000000000 301; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 302; CHECK-NEXT: [[F16_FABS:%.*]] = call half @llvm.fabs.f16(half [[F16:%.*]]) 303; CHECK-NEXT: [[CMPF16:%.*]] = fcmp ole half [[F16_FABS]], 0xH0400 304; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 305; CHECK-NEXT: ret void 306; 307 %f32.fabs = call float @llvm.fabs.f32(float %f32) 308 %cmpf32 = fcmp ole float %f32.fabs, 0x3810000000000000 309 store volatile i1 %cmpf32, ptr @var 310 311 %f64.fabs = call double @llvm.fabs.f64(double %f64) 312 %cmpf64 = fcmp ole double %f64.fabs, 0x10000000000000 313 store volatile i1 %cmpf64, ptr @var 314 315 %f16.fabs = call half @llvm.fabs.f16(half %f16) 316 %cmpf16 = fcmp ole half %f16.fabs, 0xH0400 317 store volatile i1 %cmpf16, ptr @var 318 ret void 319} 320 321define void @missing_fabs(float %f32, double %f64, half %f16) #0 { 322; CHECK-LABEL: @missing_fabs( 323; CHECK-NEXT: [[CMPF32:%.*]] = fcmp olt float [[F32:%.*]], 0x3810000000000000 324; CHECK-NEXT: store volatile i1 [[CMPF32]], ptr @var, align 1 325; CHECK-NEXT: [[CMPF64:%.*]] = fcmp olt double [[F64:%.*]], 0x10000000000000 326; CHECK-NEXT: store volatile i1 [[CMPF64]], ptr @var, align 1 327; CHECK-NEXT: [[CMPF16:%.*]] = fcmp olt half [[F16:%.*]], 0xH0400 328; CHECK-NEXT: store volatile i1 [[CMPF16]], ptr @var, align 1 329; CHECK-NEXT: ret void 330; 331 %cmpf32 = fcmp olt float %f32, 0x3810000000000000 332 store volatile i1 %cmpf32, ptr @var 333 334 %cmpf64 = fcmp olt double %f64, 0x10000000000000 335 store volatile i1 %cmpf64, ptr @var 336 337 %cmpf16 = fcmp olt half %f16, 0xH0400 338 store volatile i1 %cmpf16, ptr @var 339 ret void 340} 341 342declare float @llvm.fabs.f32(float) 343declare <2 x float> @llvm.fabs.v2f32(<2 x float>) 344 345declare half @llvm.fabs.f16(half) 346declare <2 x half> @llvm.fabs.v2f16(<2 x half>) 347 348declare double @llvm.fabs.f64(double) 349declare <2 x double> @llvm.fabs.v2f64(<2 x double>) 350 351attributes #0 = { "denormal-fp-math"="ieee,preserve-sign" } 352attributes #1 = { "denormal-fp-math"="ieee,positive-zero" } 353attributes #2 = { "denormal-fp-math"="ieee,ieee" } 354attributes #3 = { "denormal-fp-math-f32"="ieee,preserve-sign" } 355