301 changes: 301 additions & 0 deletions llvm/test/Transforms/InstCombine/fneg-as-int.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -S -passes=instcombine %s | FileCheck %s

define float @fneg_as_int_f32_castback_noimplicitfloat(float %val) noimplicitfloat {
; CHECK-LABEL: define float @fneg_as_int_f32_castback_noimplicitfloat
; CHECK-SAME: (float [[VAL:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[BITCAST]], -2147483648
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[XOR]] to float
; CHECK-NEXT: ret float [[FNEG]]
;
%bitcast = bitcast float %val to i32
%xor = xor i32 %bitcast, -2147483648
%fneg = bitcast i32 %xor to float
ret float %fneg
}

define <2 x i32> @fneg_as_int_v2f32_noimplicitfloat(<2 x float> %x) noimplicitfloat {
; CHECK-LABEL: define <2 x i32> @fneg_as_int_v2f32_noimplicitfloat
; CHECK-SAME: (<2 x float> [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x float> [[X]] to <2 x i32>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[BC]], <i32 -2147483648, i32 -2147483648>
; CHECK-NEXT: ret <2 x i32> [[XOR]]
;
%bc = bitcast <2 x float> %x to <2 x i32>
%xor = xor <2 x i32> %bc, <i32 -2147483648, i32 -2147483648>
ret <2 x i32> %xor
}

define float @fneg_as_int_f32_castback(float %val) {
; CHECK-LABEL: define float @fneg_as_int_f32_castback
; CHECK-SAME: (float [[VAL:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[VAL]]
; CHECK-NEXT: ret float [[TMP1]]
;
%bitcast = bitcast float %val to i32
%xor = xor i32 %bitcast, -2147483648
%fneg = bitcast i32 %xor to float
ret float %fneg
}

define float @not_fneg_as_int_f32_castback_wrongconst(float %val) {
; CHECK-LABEL: define float @not_fneg_as_int_f32_castback_wrongconst
; CHECK-SAME: (float [[VAL:%.*]]) {
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[BITCAST]], -2147483647
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[XOR]] to float
; CHECK-NEXT: ret float [[FNEG]]
;
%bitcast = bitcast float %val to i32
%xor = xor i32 %bitcast, -2147483647
%fneg = bitcast i32 %xor to float
ret float %fneg
}

define float @fneg_as_int_f32_castback_multi_use(float %val, ptr %ptr) {
; CHECK-LABEL: define float @fneg_as_int_f32_castback_multi_use
; CHECK-SAME: (float [[VAL:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[VAL]]
; CHECK-NEXT: store float [[TMP1]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[TMP1]]
;
%bitcast = bitcast float %val to i32
%xor = xor i32 %bitcast, -2147483648
store i32 %xor, ptr %ptr
%fneg = bitcast i32 %xor to float
ret float %fneg
}

define i64 @fneg_as_int_f64(double %x) {
; CHECK-LABEL: define i64 @fneg_as_int_f64
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg double [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast double [[TMP1]] to i64
; CHECK-NEXT: ret i64 [[XOR]]
;
%bc = bitcast double %x to i64
%xor = xor i64 %bc, -9223372036854775808
ret i64 %xor
}

define <2 x i64> @fneg_as_int_v2f64(<2 x double> %x) {
; CHECK-LABEL: define <2 x i64> @fneg_as_int_v2f64
; CHECK-SAME: (<2 x double> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x double> [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x double> [[TMP1]] to <2 x i64>
; CHECK-NEXT: ret <2 x i64> [[XOR]]
;
%bc = bitcast <2 x double> %x to <2 x i64>
%xor = xor <2 x i64> %bc, <i64 -9223372036854775808, i64 -9223372036854775808>
ret <2 x i64> %xor
}

define i64 @fneg_as_int_f64_swap(double %x) {
; CHECK-LABEL: define i64 @fneg_as_int_f64_swap
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg double [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast double [[TMP1]] to i64
; CHECK-NEXT: ret i64 [[XOR]]
;
%bc = bitcast double %x to i64
%xor = xor i64 -9223372036854775808, %bc
ret i64 %xor
}

define i32 @fneg_as_int_f32(float %x) {
; CHECK-LABEL: define i32 @fneg_as_int_f32
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast float [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[XOR]]
;
%bc = bitcast float %x to i32
%xor = xor i32 %bc, -2147483648
ret i32 %xor
}

define <2 x i32> @fneg_as_int_v2f32(<2 x float> %x) {
; CHECK-LABEL: define <2 x i32> @fneg_as_int_v2f32
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x float> [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x float> [[TMP1]] to <2 x i32>
; CHECK-NEXT: ret <2 x i32> [[XOR]]
;
%bc = bitcast <2 x float> %x to <2 x i32>
%xor = xor <2 x i32> %bc, <i32 -2147483648, i32 -2147483648>
ret <2 x i32> %xor
}

define <2 x i32> @not_fneg_as_int_v2f32_nonsplat(<2 x float> %x) {
; CHECK-LABEL: define <2 x i32> @not_fneg_as_int_v2f32_nonsplat
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x float> [[X]] to <2 x i32>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[BC]], <i32 -2147483648, i32 -2147483647>
; CHECK-NEXT: ret <2 x i32> [[XOR]]
;
%bc = bitcast <2 x float> %x to <2 x i32>
%xor = xor <2 x i32> %bc, <i32 -2147483648, i32 -2147483647>
ret <2 x i32> %xor
}

define <3 x i32> @fneg_as_int_v3f32_undef(<3 x float> %x) {
; CHECK-LABEL: define <3 x i32> @fneg_as_int_v3f32_undef
; CHECK-SAME: (<3 x float> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg <3 x float> [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast <3 x float> [[TMP1]] to <3 x i32>
; CHECK-NEXT: ret <3 x i32> [[XOR]]
;
%bc = bitcast <3 x float> %x to <3 x i32>
%xor = xor <3 x i32> %bc, <i32 -2147483648, i32 undef, i32 -2147483648>
ret <3 x i32> %xor
}

; Make sure that only a bitcast is transformed.
define i64 @fneg_as_int_f64_not_bitcast(double %x) {
; CHECK-LABEL: define i64 @fneg_as_int_f64_not_bitcast
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = fptoui double [[X]] to i64
; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[BC]], -9223372036854775808
; CHECK-NEXT: ret i64 [[XOR]]
;
%bc = fptoui double %x to i64
%xor = xor i64 %bc, -9223372036854775808
ret i64 %xor
}

define float @not_fneg_as_int_f32_bitcast_from_v2f16(<2 x half> %val) {
; CHECK-LABEL: define float @not_fneg_as_int_f32_bitcast_from_v2f16
; CHECK-SAME: (<2 x half> [[VAL:%.*]]) {
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast <2 x half> [[VAL]] to i32
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[BITCAST]], -2147483648
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[XOR]] to float
; CHECK-NEXT: ret float [[FNEG]]
;
%bitcast = bitcast <2 x half> %val to i32
%xor = xor i32 %bitcast, -2147483648
%fneg = bitcast i32 %xor to float
ret float %fneg
}

define float @not_fneg_as_int_f32_bitcast_from_v2i16(<2 x i16> %val) {
; CHECK-LABEL: define float @not_fneg_as_int_f32_bitcast_from_v2i16
; CHECK-SAME: (<2 x i16> [[VAL:%.*]]) {
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast <2 x i16> [[VAL]] to i32
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[BITCAST]], -2147483648
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[XOR]] to float
; CHECK-NEXT: ret float [[FNEG]]
;
%bitcast = bitcast <2 x i16> %val to i32
%xor = xor i32 %bitcast, -2147483648
%fneg = bitcast i32 %xor to float
ret float %fneg
}

define i128 @fneg_as_int_fp128_f64_mask(fp128 %x) {
; CHECK-LABEL: define i128 @fneg_as_int_fp128_f64_mask
; CHECK-SAME: (fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast fp128 [[X]] to i128
; CHECK-NEXT: [[XOR:%.*]] = xor i128 [[BC]], -9223372036854775808
; CHECK-NEXT: ret i128 [[XOR]]
;
%bc = bitcast fp128 %x to i128
%xor = xor i128 %bc, -9223372036854775808
ret i128 %xor
}

define i128 @fneg_as_int_fp128_f128_mask(fp128 %x) {
; CHECK-LABEL: define i128 @fneg_as_int_fp128_f128_mask
; CHECK-SAME: (fp128 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg fp128 [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast fp128 [[TMP1]] to i128
; CHECK-NEXT: ret i128 [[XOR]]
;
%bc = bitcast fp128 %x to i128
%xor = xor i128 %bc, -170141183460469231731687303715884105728
ret i128 %xor
}

define i16 @fneg_as_int_f16(half %x) {
; CHECK-LABEL: define i16 @fneg_as_int_f16
; CHECK-SAME: (half [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg half [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast half [[TMP1]] to i16
; CHECK-NEXT: ret i16 [[XOR]]
;
%bc = bitcast half %x to i16
%xor = xor i16 %bc, -32768
ret i16 %xor
}

define <2 x i16> @fneg_as_int_v2f16(<2 x half> %x) {
; CHECK-LABEL: define <2 x i16> @fneg_as_int_v2f16
; CHECK-SAME: (<2 x half> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x half> [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x half> [[TMP1]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[XOR]]
;
%bc = bitcast <2 x half> %x to <2 x i16>
%xor = xor <2 x i16> %bc, <i16 -32768, i16 -32768>
ret <2 x i16> %xor
}

define i16 @fneg_as_int_bf16(bfloat %x) {
; CHECK-LABEL: define i16 @fneg_as_int_bf16
; CHECK-SAME: (bfloat [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg bfloat [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast bfloat [[TMP1]] to i16
; CHECK-NEXT: ret i16 [[XOR]]
;
%bc = bitcast bfloat %x to i16
%xor = xor i16 %bc, -32768
ret i16 %xor
}

define <2 x i16> @fneg_as_int_v2bf16(<2 x bfloat> %x) {
; CHECK-LABEL: define <2 x i16> @fneg_as_int_v2bf16
; CHECK-SAME: (<2 x bfloat> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x bfloat> [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x bfloat> [[TMP1]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[XOR]]
;
%bc = bitcast <2 x bfloat> %x to <2 x i16>
%xor = xor <2 x i16> %bc, <i16 -32768, i16 -32768>
ret <2 x i16> %xor
}

define i80 @fneg_as_int_x86_fp80_f64_mask(x86_fp80 %x) {
; CHECK-LABEL: define i80 @fneg_as_int_x86_fp80_f64_mask
; CHECK-SAME: (x86_fp80 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = fneg x86_fp80 [[X]]
; CHECK-NEXT: [[XOR:%.*]] = bitcast x86_fp80 [[TMP1]] to i80
; CHECK-NEXT: ret i80 [[XOR]]
;
%bc = bitcast x86_fp80 %x to i80
%xor = xor i80 %bc, -604462909807314587353088
ret i80 %xor
}

define i128 @fneg_as_int_ppc_fp128_f64_mask(ppc_fp128 %x) {
; CHECK-LABEL: define i128 @fneg_as_int_ppc_fp128_f64_mask
; CHECK-SAME: (ppc_fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast ppc_fp128 [[X]] to i128
; CHECK-NEXT: [[XOR:%.*]] = xor i128 [[BC]], -9223372036854775808
; CHECK-NEXT: ret i128 [[XOR]]
;
%bc = bitcast ppc_fp128 %x to i128
%xor = xor i128 %bc, -9223372036854775808
ret i128 %xor
}

define i128 @fneg_as_int_ppc_fp128_f128_mask(ppc_fp128 %x) {
; CHECK-LABEL: define i128 @fneg_as_int_ppc_fp128_f128_mask
; CHECK-SAME: (ppc_fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast ppc_fp128 [[X]] to i128
; CHECK-NEXT: [[XOR:%.*]] = xor i128 [[BC]], -170141183460469231731687303715884105728
; CHECK-NEXT: ret i128 [[XOR]]
;
%bc = bitcast ppc_fp128 %x to i128
%xor = xor i128 %bc, -170141183460469231731687303715884105728
ret i128 %xor
}
327 changes: 327 additions & 0 deletions llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -S -passes=instcombine %s | FileCheck %s

define i32 @fneg_fabs_as_int_f32_noimplicitfloat(float %x) noimplicitfloat {
; CHECK-LABEL: define i32 @fneg_fabs_as_int_f32_noimplicitfloat
; CHECK-SAME: (float [[X:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[BC:%.*]] = bitcast float [[X]] to i32
; CHECK-NEXT: [[OR:%.*]] = or i32 [[BC]], -2147483648
; CHECK-NEXT: ret i32 [[OR]]
;
%bc = bitcast float %x to i32
%or = or i32 %bc, -2147483648
ret i32 %or
}

define <2 x i32> @fneg_fabs_as_int_v2f32_noimplicitfloat(<2 x float> %x) noimplicitfloat {
; CHECK-LABEL: define <2 x i32> @fneg_fabs_as_int_v2f32_noimplicitfloat
; CHECK-SAME: (<2 x float> [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x float> [[X]] to <2 x i32>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[BC]], <i32 -2147483648, i32 -2147483648>
; CHECK-NEXT: ret <2 x i32> [[OR]]
;
%bc = bitcast <2 x float> %x to <2 x i32>
%or = or <2 x i32> %bc, <i32 -2147483648, i32 -2147483648>
ret <2 x i32> %or
}

define float @fneg_fabs_fabs_as_int_f32_and_or(float %val) {
; CHECK-LABEL: define float @fneg_fabs_fabs_as_int_f32_and_or
; CHECK-SAME: (float [[VAL:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[TMP2]]
;
%bitcast = bitcast float %val to i32
%and = and i32 %bitcast, 2147483647
%or = or i32 %and, -2147483648
%fneg.fabs = bitcast i32 %or to float
ret float %fneg.fabs
}

define float @fneg_fabs_as_int_f32_castback(float %val) {
; CHECK-LABEL: define float @fneg_fabs_as_int_f32_castback
; CHECK-SAME: (float [[VAL:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[TMP2]]
;
%bitcast = bitcast float %val to i32
%or = or i32 %bitcast, -2147483648
%fneg = bitcast i32 %or to float
ret float %fneg
}

define float @not_fneg_fabs_as_int_f32_castback_wrongconst(float %val) {
; CHECK-LABEL: define float @not_fneg_fabs_as_int_f32_castback_wrongconst
; CHECK-SAME: (float [[VAL:%.*]]) {
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
; CHECK-NEXT: [[OR:%.*]] = or i32 [[BITCAST]], -2147483647
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[OR]] to float
; CHECK-NEXT: ret float [[FNEG]]
;
%bitcast = bitcast float %val to i32
%or = or i32 %bitcast, -2147483647
%fneg = bitcast i32 %or to float
ret float %fneg
}

define float @fneg_fabs_as_int_f32_castback_multi_use(float %val, ptr %ptr) {
; CHECK-LABEL: define float @fneg_fabs_as_int_f32_castback_multi_use
; CHECK-SAME: (float [[VAL:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: store float [[TMP2]], ptr [[PTR]], align 4
; CHECK-NEXT: ret float [[TMP2]]
;
%bitcast = bitcast float %val to i32
%or = or i32 %bitcast, -2147483648
store i32 %or, ptr %ptr
%fneg = bitcast i32 %or to float
ret float %fneg
}

define i64 @fneg_fabs_as_int_f64(double %x) {
; CHECK-LABEL: define i64 @fneg_fabs_as_int_f64
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg double [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast double [[TMP2]] to i64
; CHECK-NEXT: ret i64 [[OR]]
;
%bc = bitcast double %x to i64
%or = or i64 %bc, -9223372036854775808
ret i64 %or
}

define <2 x i64> @fneg_fabs_as_int_v2f64(<2 x double> %x) {
; CHECK-LABEL: define <2 x i64> @fneg_fabs_as_int_v2f64
; CHECK-SAME: (<2 x double> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x double> @llvm.fabs.v2f64(<2 x double> [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg <2 x double> [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast <2 x double> [[TMP2]] to <2 x i64>
; CHECK-NEXT: ret <2 x i64> [[OR]]
;
%bc = bitcast <2 x double> %x to <2 x i64>
%or = or <2 x i64> %bc, <i64 -9223372036854775808, i64 -9223372036854775808>
ret <2 x i64> %or
}

define i64 @fneg_fabs_as_int_f64_swap(double %x) {
; CHECK-LABEL: define i64 @fneg_fabs_as_int_f64_swap
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg double [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast double [[TMP2]] to i64
; CHECK-NEXT: ret i64 [[OR]]
;
%bc = bitcast double %x to i64
%or = or i64 -9223372036854775808, %bc
ret i64 %or
}

define i32 @fneg_fabs_as_int_f32(float %x) {
; CHECK-LABEL: define i32 @fneg_fabs_as_int_f32
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast float [[TMP2]] to i32
; CHECK-NEXT: ret i32 [[OR]]
;
%bc = bitcast float %x to i32
%or = or i32 %bc, -2147483648
ret i32 %or
}

define <2 x i32> @fneg_fabs_as_int_v2f32(<2 x float> %x) {
; CHECK-LABEL: define <2 x i32> @fneg_fabs_as_int_v2f32
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg <2 x float> [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast <2 x float> [[TMP2]] to <2 x i32>
; CHECK-NEXT: ret <2 x i32> [[OR]]
;
%bc = bitcast <2 x float> %x to <2 x i32>
%or = or <2 x i32> %bc, <i32 -2147483648, i32 -2147483648>
ret <2 x i32> %or
}

define <2 x i32> @not_fneg_fabs_as_int_v2f32_nonsplat(<2 x float> %x) {
; CHECK-LABEL: define <2 x i32> @not_fneg_fabs_as_int_v2f32_nonsplat
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x float> [[X]] to <2 x i32>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[BC]], <i32 -2147483648, i32 -2147483647>
; CHECK-NEXT: ret <2 x i32> [[OR]]
;
%bc = bitcast <2 x float> %x to <2 x i32>
%or = or <2 x i32> %bc, <i32 -2147483648, i32 -2147483647>
ret <2 x i32> %or
}

define <3 x i32> @fneg_fabs_as_int_v3f32_undef(<3 x float> %x) {
; CHECK-LABEL: define <3 x i32> @fneg_fabs_as_int_v3f32_undef
; CHECK-SAME: (<3 x float> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x float> @llvm.fabs.v3f32(<3 x float> [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg <3 x float> [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast <3 x float> [[TMP2]] to <3 x i32>
; CHECK-NEXT: ret <3 x i32> [[OR]]
;
%bc = bitcast <3 x float> %x to <3 x i32>
%or = or <3 x i32> %bc, <i32 -2147483648, i32 undef, i32 -2147483648>
ret <3 x i32> %or
}

; Make sure that only a bitcast is transformed.
define i64 @fneg_fabs_as_int_f64_not_bitcast(double %x) {
; CHECK-LABEL: define i64 @fneg_fabs_as_int_f64_not_bitcast
; CHECK-SAME: (double [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = fptoui double [[X]] to i64
; CHECK-NEXT: [[OR:%.*]] = or i64 [[BC]], -9223372036854775808
; CHECK-NEXT: ret i64 [[OR]]
;
%bc = fptoui double %x to i64
%or = or i64 %bc, -9223372036854775808
ret i64 %or
}

define float @not_fneg_fabs_as_int_f32_bitcast_from_v2f16(<2 x half> %val) {
; CHECK-LABEL: define float @not_fneg_fabs_as_int_f32_bitcast_from_v2f16
; CHECK-SAME: (<2 x half> [[VAL:%.*]]) {
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast <2 x half> [[VAL]] to i32
; CHECK-NEXT: [[OR:%.*]] = or i32 [[BITCAST]], -2147483648
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[OR]] to float
; CHECK-NEXT: ret float [[FNEG]]
;
%bitcast = bitcast <2 x half> %val to i32
%or = or i32 %bitcast, -2147483648
%fneg = bitcast i32 %or to float
ret float %fneg
}

define float @not_fneg_fabs_as_int_f32_bitcast_from_v2i16(<2 x i16> %val) {
; CHECK-LABEL: define float @not_fneg_fabs_as_int_f32_bitcast_from_v2i16
; CHECK-SAME: (<2 x i16> [[VAL:%.*]]) {
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast <2 x i16> [[VAL]] to i32
; CHECK-NEXT: [[OR:%.*]] = or i32 [[BITCAST]], -2147483648
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[OR]] to float
; CHECK-NEXT: ret float [[FNEG]]
;
%bitcast = bitcast <2 x i16> %val to i32
%or = or i32 %bitcast, -2147483648
%fneg = bitcast i32 %or to float
ret float %fneg
}

define i128 @fneg_fabs_as_int_fp128_f64_mask(fp128 %x) {
; CHECK-LABEL: define i128 @fneg_fabs_as_int_fp128_f64_mask
; CHECK-SAME: (fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast fp128 [[X]] to i128
; CHECK-NEXT: [[OR:%.*]] = or i128 [[BC]], -9223372036854775808
; CHECK-NEXT: ret i128 [[OR]]
;
%bc = bitcast fp128 %x to i128
%or = or i128 %bc, -9223372036854775808
ret i128 %or
}

define i128 @fneg_fabs_as_int_fp128_f128_mask(fp128 %x) {
; CHECK-LABEL: define i128 @fneg_fabs_as_int_fp128_f128_mask
; CHECK-SAME: (fp128 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg fp128 [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast fp128 [[TMP2]] to i128
; CHECK-NEXT: ret i128 [[OR]]
;
%bc = bitcast fp128 %x to i128
%or = or i128 %bc, -170141183460469231731687303715884105728
ret i128 %or
}

define i16 @fneg_fabs_as_int_f16(half %x) {
; CHECK-LABEL: define i16 @fneg_fabs_as_int_f16
; CHECK-SAME: (half [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg half [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast half [[TMP2]] to i16
; CHECK-NEXT: ret i16 [[OR]]
;
%bc = bitcast half %x to i16
%or = or i16 %bc, -32768
ret i16 %or
}

define <2 x i16> @fneg_fabs_as_int_v2f16(<2 x half> %x) {
; CHECK-LABEL: define <2 x i16> @fneg_fabs_as_int_v2f16
; CHECK-SAME: (<2 x half> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg <2 x half> [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast <2 x half> [[TMP2]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[OR]]
;
%bc = bitcast <2 x half> %x to <2 x i16>
%or = or <2 x i16> %bc, <i16 -32768, i16 -32768>
ret <2 x i16> %or
}

define i16 @fneg_fabs_as_int_bf16(bfloat %x) {
; CHECK-LABEL: define i16 @fneg_fabs_as_int_bf16
; CHECK-SAME: (bfloat [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call bfloat @llvm.fabs.bf16(bfloat [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg bfloat [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast bfloat [[TMP2]] to i16
; CHECK-NEXT: ret i16 [[OR]]
;
%bc = bitcast bfloat %x to i16
%or = or i16 %bc, -32768
ret i16 %or
}

define <2 x i16> @fneg_fabs_as_int_v2bf16(<2 x bfloat> %x) {
; CHECK-LABEL: define <2 x i16> @fneg_fabs_as_int_v2bf16
; CHECK-SAME: (<2 x bfloat> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x bfloat> @llvm.fabs.v2bf16(<2 x bfloat> [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg <2 x bfloat> [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast <2 x bfloat> [[TMP2]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[OR]]
;
%bc = bitcast <2 x bfloat> %x to <2 x i16>
%or = or <2 x i16> %bc, <i16 -32768, i16 -32768>
ret <2 x i16> %or
}

define i80 @fneg_fabs_as_int_x86_fp80_f64_mask(x86_fp80 %x) {
; CHECK-LABEL: define i80 @fneg_fabs_as_int_x86_fp80_f64_mask
; CHECK-SAME: (x86_fp80 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call x86_fp80 @llvm.fabs.f80(x86_fp80 [[X]])
; CHECK-NEXT: [[TMP2:%.*]] = fneg x86_fp80 [[TMP1]]
; CHECK-NEXT: [[OR:%.*]] = bitcast x86_fp80 [[TMP2]] to i80
; CHECK-NEXT: ret i80 [[OR]]
;
%bc = bitcast x86_fp80 %x to i80
%or = or i80 %bc, -604462909807314587353088
ret i80 %or
}

define i128 @fneg_fabs_as_int_ppc_fp128_f64_mask(ppc_fp128 %x) {
; CHECK-LABEL: define i128 @fneg_fabs_as_int_ppc_fp128_f64_mask
; CHECK-SAME: (ppc_fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast ppc_fp128 [[X]] to i128
; CHECK-NEXT: [[OR:%.*]] = or i128 [[BC]], -9223372036854775808
; CHECK-NEXT: ret i128 [[OR]]
;
%bc = bitcast ppc_fp128 %x to i128
%or = or i128 %bc, -9223372036854775808
ret i128 %or
}

define i128 @fneg_fabs_as_int_ppc_fp128_f128_mask(ppc_fp128 %x) {
; CHECK-LABEL: define i128 @fneg_fabs_as_int_ppc_fp128_f128_mask
; CHECK-SAME: (ppc_fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BC:%.*]] = bitcast ppc_fp128 [[X]] to i128
; CHECK-NEXT: [[OR:%.*]] = or i128 [[BC]], -170141183460469231731687303715884105728
; CHECK-NEXT: ret i128 [[OR]]
;
%bc = bitcast ppc_fp128 %x to i128
%or = or i128 %bc, -170141183460469231731687303715884105728
ret i128 %or
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) {

define <8 x float> @fneg_fabs(<8 x float> %a) {
; CHECK-LABEL: @fneg_fabs(
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32>
; CHECK-NEXT: [[TMP2:%.*]] = xor <8 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP3:%.*]] = and <8 x i32> [[TMP1]], <i32 poison, i32 poison, i32 poison, i32 poison, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647>
; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <8 x i32> [[TMP2]], <8 x i32> [[TMP3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15>
; CHECK-NEXT: [[TMP5:%.*]] = bitcast <8 x i32> [[TMP4]] to <8 x float>
; CHECK-NEXT: ret <8 x float> [[TMP5]]
; CHECK-NEXT: [[TMP1:%.*]] = fneg <8 x float> [[A:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call <8 x float> @llvm.fabs.v8f32(<8 x float> [[A]])
; CHECK-NEXT: [[DOTUNCASTED:%.*]] = shufflevector <8 x float> [[TMP1]], <8 x float> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15>
; CHECK-NEXT: ret <8 x float> [[DOTUNCASTED]]
;
%a0 = extractelement <8 x float> %a, i32 0
%a1 = extractelement <8 x float> %a, i32 1
Expand Down
10 changes: 4 additions & 6 deletions llvm/test/Transforms/SLPVectorizer/X86/alternate-cast.ll
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) {

define <8 x float> @fneg_fabs(<8 x float> %a) {
; CHECK-LABEL: @fneg_fabs(
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32>
; CHECK-NEXT: [[TMP2:%.*]] = xor <8 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP3:%.*]] = and <8 x i32> [[TMP1]], <i32 poison, i32 poison, i32 poison, i32 poison, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647>
; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <8 x i32> [[TMP2]], <8 x i32> [[TMP3]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15>
; CHECK-NEXT: [[TMP5:%.*]] = bitcast <8 x i32> [[TMP4]] to <8 x float>
; CHECK-NEXT: ret <8 x float> [[TMP5]]
; CHECK-NEXT: [[TMP1:%.*]] = fneg <8 x float> [[A:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call <8 x float> @llvm.fabs.v8f32(<8 x float> [[A]])
; CHECK-NEXT: [[DOTUNCASTED:%.*]] = shufflevector <8 x float> [[TMP1]], <8 x float> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15>
; CHECK-NEXT: ret <8 x float> [[DOTUNCASTED]]
;
%a0 = extractelement <8 x float> %a, i32 0
%a1 = extractelement <8 x float> %a, i32 1
Expand Down