Skip to content

Commit 50a9b3d

Browse files
committed
InstCombine: Recognize fneg when performed as bitcasted integer
This is a resurrection of D18874. This was previously wrong with fneg conflated with fsub, but we now have a proper fneg instruction. Additionally, I think it is now clearer that IR float=IEEE float, and a different bit layout would require adding a different IR type. https://reviews.llvm.org/D151934
1 parent 1266086 commit 50a9b3d

File tree

4 files changed

+53
-39
lines changed

4 files changed

+53
-39
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4466,6 +4466,24 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
44664466
// a 'not' op and moving it before the shift. Doing that requires
44674467
// preventing the inverse fold in canShiftBinOpWithConstantRHS().
44684468
}
4469+
4470+
// If we are XORing the sign bit of a floating-point value, convert
4471+
// this to fneg, then cast back to integer.
4472+
//
4473+
// Assumes any IEEE-represented type has the sign bit in the high bit.
4474+
// TODO: Unify with APInt matcher. This version allows undef unlike m_APInt
4475+
Value *CastOp;
4476+
if (match(Op0, m_BitCast(m_Value(CastOp))) && match(Op1, m_SignMask()) &&
4477+
!Builder.GetInsertBlock()->getParent()->hasFnAttribute(
4478+
Attribute::NoImplicitFloat)) {
4479+
Type *EltTy = CastOp->getType()->getScalarType();
4480+
if (EltTy->isFloatingPointTy() && EltTy->isIEEE() &&
4481+
EltTy->getPrimitiveSizeInBits() ==
4482+
I.getType()->getScalarType()->getPrimitiveSizeInBits()) {
4483+
Value *FNeg = Builder.CreateFNeg(CastOp);
4484+
return new BitCastInst(FNeg, I.getType());
4485+
}
4486+
}
44694487
}
44704488

44714489
// FIXME: This should not be limited to scalar (pull into APInt match above).

llvm/test/Transforms/InstCombine/fneg-as-int.ll

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ define <2 x i32> @fneg_as_int_v2f32_noimplicitfloat(<2 x float> %x) noimplicitfl
3030
define float @fneg_as_int_f32_castback(float %val) {
3131
; CHECK-LABEL: define float @fneg_as_int_f32_castback
3232
; CHECK-SAME: (float [[VAL:%.*]]) {
33-
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
34-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[BITCAST]], -2147483648
35-
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[XOR]] to float
36-
; CHECK-NEXT: ret float [[FNEG]]
33+
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[VAL]]
34+
; CHECK-NEXT: ret float [[TMP1]]
3735
;
3836
%bitcast = bitcast float %val to i32
3937
%xor = xor i32 %bitcast, -2147483648
@@ -58,11 +56,9 @@ define float @not_fneg_as_int_f32_castback_wrongconst(float %val) {
5856
define float @fneg_as_int_f32_castback_multi_use(float %val, ptr %ptr) {
5957
; CHECK-LABEL: define float @fneg_as_int_f32_castback_multi_use
6058
; CHECK-SAME: (float [[VAL:%.*]], ptr [[PTR:%.*]]) {
61-
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
62-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[BITCAST]], -2147483648
63-
; CHECK-NEXT: store i32 [[XOR]], ptr [[PTR]], align 4
64-
; CHECK-NEXT: [[FNEG:%.*]] = bitcast i32 [[XOR]] to float
65-
; CHECK-NEXT: ret float [[FNEG]]
59+
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[VAL]]
60+
; CHECK-NEXT: store float [[TMP1]], ptr [[PTR]], align 4
61+
; CHECK-NEXT: ret float [[TMP1]]
6662
;
6763
%bitcast = bitcast float %val to i32
6864
%xor = xor i32 %bitcast, -2147483648
@@ -74,8 +70,8 @@ define float @fneg_as_int_f32_castback_multi_use(float %val, ptr %ptr) {
7470
define i64 @fneg_as_int_f64(double %x) {
7571
; CHECK-LABEL: define i64 @fneg_as_int_f64
7672
; CHECK-SAME: (double [[X:%.*]]) {
77-
; CHECK-NEXT: [[BC:%.*]] = bitcast double [[X]] to i64
78-
; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[BC]], -9223372036854775808
73+
; CHECK-NEXT: [[TMP1:%.*]] = fneg double [[X]]
74+
; CHECK-NEXT: [[XOR:%.*]] = bitcast double [[TMP1]] to i64
7975
; CHECK-NEXT: ret i64 [[XOR]]
8076
;
8177
%bc = bitcast double %x to i64
@@ -86,8 +82,8 @@ define i64 @fneg_as_int_f64(double %x) {
8682
define <2 x i64> @fneg_as_int_v2f64(<2 x double> %x) {
8783
; CHECK-LABEL: define <2 x i64> @fneg_as_int_v2f64
8884
; CHECK-SAME: (<2 x double> [[X:%.*]]) {
89-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x double> [[X]] to <2 x i64>
90-
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i64> [[BC]], <i64 -9223372036854775808, i64 -9223372036854775808>
85+
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x double> [[X]]
86+
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x double> [[TMP1]] to <2 x i64>
9187
; CHECK-NEXT: ret <2 x i64> [[XOR]]
9288
;
9389
%bc = bitcast <2 x double> %x to <2 x i64>
@@ -98,8 +94,8 @@ define <2 x i64> @fneg_as_int_v2f64(<2 x double> %x) {
9894
define i64 @fneg_as_int_f64_swap(double %x) {
9995
; CHECK-LABEL: define i64 @fneg_as_int_f64_swap
10096
; CHECK-SAME: (double [[X:%.*]]) {
101-
; CHECK-NEXT: [[BC:%.*]] = bitcast double [[X]] to i64
102-
; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[BC]], -9223372036854775808
97+
; CHECK-NEXT: [[TMP1:%.*]] = fneg double [[X]]
98+
; CHECK-NEXT: [[XOR:%.*]] = bitcast double [[TMP1]] to i64
10399
; CHECK-NEXT: ret i64 [[XOR]]
104100
;
105101
%bc = bitcast double %x to i64
@@ -110,8 +106,8 @@ define i64 @fneg_as_int_f64_swap(double %x) {
110106
define i32 @fneg_as_int_f32(float %x) {
111107
; CHECK-LABEL: define i32 @fneg_as_int_f32
112108
; CHECK-SAME: (float [[X:%.*]]) {
113-
; CHECK-NEXT: [[BC:%.*]] = bitcast float [[X]] to i32
114-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[BC]], -2147483648
109+
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[X]]
110+
; CHECK-NEXT: [[XOR:%.*]] = bitcast float [[TMP1]] to i32
115111
; CHECK-NEXT: ret i32 [[XOR]]
116112
;
117113
%bc = bitcast float %x to i32
@@ -122,8 +118,8 @@ define i32 @fneg_as_int_f32(float %x) {
122118
define <2 x i32> @fneg_as_int_v2f32(<2 x float> %x) {
123119
; CHECK-LABEL: define <2 x i32> @fneg_as_int_v2f32
124120
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
125-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x float> [[X]] to <2 x i32>
126-
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[BC]], <i32 -2147483648, i32 -2147483648>
121+
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x float> [[X]]
122+
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x float> [[TMP1]] to <2 x i32>
127123
; CHECK-NEXT: ret <2 x i32> [[XOR]]
128124
;
129125
%bc = bitcast <2 x float> %x to <2 x i32>
@@ -146,8 +142,8 @@ define <2 x i32> @not_fneg_as_int_v2f32_nonsplat(<2 x float> %x) {
146142
define <3 x i32> @fneg_as_int_v3f32_undef(<3 x float> %x) {
147143
; CHECK-LABEL: define <3 x i32> @fneg_as_int_v3f32_undef
148144
; CHECK-SAME: (<3 x float> [[X:%.*]]) {
149-
; CHECK-NEXT: [[BC:%.*]] = bitcast <3 x float> [[X]] to <3 x i32>
150-
; CHECK-NEXT: [[XOR:%.*]] = xor <3 x i32> [[BC]], <i32 -2147483648, i32 undef, i32 -2147483648>
145+
; CHECK-NEXT: [[TMP1:%.*]] = fneg <3 x float> [[X]]
146+
; CHECK-NEXT: [[XOR:%.*]] = bitcast <3 x float> [[TMP1]] to <3 x i32>
151147
; CHECK-NEXT: ret <3 x i32> [[XOR]]
152148
;
153149
%bc = bitcast <3 x float> %x to <3 x i32>
@@ -211,8 +207,8 @@ define i128 @fneg_as_int_fp128_f64_mask(fp128 %x) {
211207
define i128 @fneg_as_int_fp128_f128_mask(fp128 %x) {
212208
; CHECK-LABEL: define i128 @fneg_as_int_fp128_f128_mask
213209
; CHECK-SAME: (fp128 [[X:%.*]]) {
214-
; CHECK-NEXT: [[BC:%.*]] = bitcast fp128 [[X]] to i128
215-
; CHECK-NEXT: [[XOR:%.*]] = xor i128 [[BC]], -170141183460469231731687303715884105728
210+
; CHECK-NEXT: [[TMP1:%.*]] = fneg fp128 [[X]]
211+
; CHECK-NEXT: [[XOR:%.*]] = bitcast fp128 [[TMP1]] to i128
216212
; CHECK-NEXT: ret i128 [[XOR]]
217213
;
218214
%bc = bitcast fp128 %x to i128
@@ -223,8 +219,8 @@ define i128 @fneg_as_int_fp128_f128_mask(fp128 %x) {
223219
define i16 @fneg_as_int_f16(half %x) {
224220
; CHECK-LABEL: define i16 @fneg_as_int_f16
225221
; CHECK-SAME: (half [[X:%.*]]) {
226-
; CHECK-NEXT: [[BC:%.*]] = bitcast half [[X]] to i16
227-
; CHECK-NEXT: [[XOR:%.*]] = xor i16 [[BC]], -32768
222+
; CHECK-NEXT: [[TMP1:%.*]] = fneg half [[X]]
223+
; CHECK-NEXT: [[XOR:%.*]] = bitcast half [[TMP1]] to i16
228224
; CHECK-NEXT: ret i16 [[XOR]]
229225
;
230226
%bc = bitcast half %x to i16
@@ -235,8 +231,8 @@ define i16 @fneg_as_int_f16(half %x) {
235231
define <2 x i16> @fneg_as_int_v2f16(<2 x half> %x) {
236232
; CHECK-LABEL: define <2 x i16> @fneg_as_int_v2f16
237233
; CHECK-SAME: (<2 x half> [[X:%.*]]) {
238-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x half> [[X]] to <2 x i16>
239-
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i16> [[BC]], <i16 -32768, i16 -32768>
234+
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x half> [[X]]
235+
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x half> [[TMP1]] to <2 x i16>
240236
; CHECK-NEXT: ret <2 x i16> [[XOR]]
241237
;
242238
%bc = bitcast <2 x half> %x to <2 x i16>
@@ -247,8 +243,8 @@ define <2 x i16> @fneg_as_int_v2f16(<2 x half> %x) {
247243
define i16 @fneg_as_int_bf16(bfloat %x) {
248244
; CHECK-LABEL: define i16 @fneg_as_int_bf16
249245
; CHECK-SAME: (bfloat [[X:%.*]]) {
250-
; CHECK-NEXT: [[BC:%.*]] = bitcast bfloat [[X]] to i16
251-
; CHECK-NEXT: [[XOR:%.*]] = xor i16 [[BC]], -32768
246+
; CHECK-NEXT: [[TMP1:%.*]] = fneg bfloat [[X]]
247+
; CHECK-NEXT: [[XOR:%.*]] = bitcast bfloat [[TMP1]] to i16
252248
; CHECK-NEXT: ret i16 [[XOR]]
253249
;
254250
%bc = bitcast bfloat %x to i16
@@ -259,8 +255,8 @@ define i16 @fneg_as_int_bf16(bfloat %x) {
259255
define <2 x i16> @fneg_as_int_v2bf16(<2 x bfloat> %x) {
260256
; CHECK-LABEL: define <2 x i16> @fneg_as_int_v2bf16
261257
; CHECK-SAME: (<2 x bfloat> [[X:%.*]]) {
262-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x bfloat> [[X]] to <2 x i16>
263-
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i16> [[BC]], <i16 -32768, i16 -32768>
258+
; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x bfloat> [[X]]
259+
; CHECK-NEXT: [[XOR:%.*]] = bitcast <2 x bfloat> [[TMP1]] to <2 x i16>
264260
; CHECK-NEXT: ret <2 x i16> [[XOR]]
265261
;
266262
%bc = bitcast <2 x bfloat> %x to <2 x i16>
@@ -271,8 +267,8 @@ define <2 x i16> @fneg_as_int_v2bf16(<2 x bfloat> %x) {
271267
define i80 @fneg_as_int_x86_fp80_f64_mask(x86_fp80 %x) {
272268
; CHECK-LABEL: define i80 @fneg_as_int_x86_fp80_f64_mask
273269
; CHECK-SAME: (x86_fp80 [[X:%.*]]) {
274-
; CHECK-NEXT: [[BC:%.*]] = bitcast x86_fp80 [[X]] to i80
275-
; CHECK-NEXT: [[XOR:%.*]] = xor i80 [[BC]], -604462909807314587353088
270+
; CHECK-NEXT: [[TMP1:%.*]] = fneg x86_fp80 [[X]]
271+
; CHECK-NEXT: [[XOR:%.*]] = bitcast x86_fp80 [[TMP1]] to i80
276272
; CHECK-NEXT: ret i80 [[XOR]]
277273
;
278274
%bc = bitcast x86_fp80 %x to i80

llvm/test/Transforms/SLPVectorizer/X86/alternate-cast-inseltpoison.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) {
7777
define <8 x float> @fneg_fabs(<8 x float> %a) {
7878
; CHECK-LABEL: @fneg_fabs(
7979
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32>
80-
; CHECK-NEXT: [[TMP2:%.*]] = xor <8 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 poison, i32 poison, i32 poison, i32 poison>
80+
; CHECK-NEXT: [[TMP2:%.*]] = fneg <8 x float> [[A]]
8181
; CHECK-NEXT: [[TMP3:%.*]] = and <8 x i32> [[TMP1]], <i32 poison, i32 poison, i32 poison, i32 poison, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647>
82-
; 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>
83-
; CHECK-NEXT: [[TMP5:%.*]] = bitcast <8 x i32> [[TMP4]] to <8 x float>
82+
; CHECK-NEXT: [[TMP4:%.*]] = bitcast <8 x i32> [[TMP3]] to <8 x float>
83+
; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x float> [[TMP2]], <8 x float> [[TMP4]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15>
8484
; CHECK-NEXT: ret <8 x float> [[TMP5]]
8585
;
8686
%a0 = extractelement <8 x float> %a, i32 0

llvm/test/Transforms/SLPVectorizer/X86/alternate-cast.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) {
7777
define <8 x float> @fneg_fabs(<8 x float> %a) {
7878
; CHECK-LABEL: @fneg_fabs(
7979
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32>
80-
; CHECK-NEXT: [[TMP2:%.*]] = xor <8 x i32> [[TMP1]], <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 poison, i32 poison, i32 poison, i32 poison>
80+
; CHECK-NEXT: [[TMP2:%.*]] = fneg <8 x float> [[A]]
8181
; CHECK-NEXT: [[TMP3:%.*]] = and <8 x i32> [[TMP1]], <i32 poison, i32 poison, i32 poison, i32 poison, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647>
82-
; 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>
83-
; CHECK-NEXT: [[TMP5:%.*]] = bitcast <8 x i32> [[TMP4]] to <8 x float>
82+
; CHECK-NEXT: [[TMP4:%.*]] = bitcast <8 x i32> [[TMP3]] to <8 x float>
83+
; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x float> [[TMP2]], <8 x float> [[TMP4]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15>
8484
; CHECK-NEXT: ret <8 x float> [[TMP5]]
8585
;
8686
%a0 = extractelement <8 x float> %a, i32 0

0 commit comments

Comments
 (0)