Skip to content

Commit 5c0da58

Browse files
committed
InstCombine: Recognize fabs as bitcasted integer
In the past we sort of pretended float might be implementable as a non-IEEE type but that never realistically would work. Exotic FP types would need to be added to the IR. Turning these into FP operations enables FP tracking optimizations. https://reviews.llvm.org/D151937
1 parent 50a9b3d commit 5c0da58

File tree

5 files changed

+64
-51
lines changed

5 files changed

+64
-51
lines changed

Diff for: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -2455,6 +2455,25 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
24552455
}
24562456
}
24572457

2458+
// If we are clearing the sign bit of a floating-point value, convert this to
2459+
// fabs, then cast back to integer.
2460+
//
2461+
// Assumes any IEEE-represented type has the sign bit in the high bit.
2462+
// TODO: Unify with APInt matcher. This version allows undef unlike m_APInt
2463+
Value *CastOp;
2464+
if (match(Op0, m_BitCast(m_Value(CastOp))) &&
2465+
match(Op1, m_MaxSignedValue()) &&
2466+
!Builder.GetInsertBlock()->getParent()->hasFnAttribute(
2467+
Attribute::NoImplicitFloat)) {
2468+
Type *EltTy = CastOp->getType()->getScalarType();
2469+
if (EltTy->isFloatingPointTy() && EltTy->isIEEE() &&
2470+
EltTy->getPrimitiveSizeInBits() ==
2471+
I.getType()->getScalarType()->getPrimitiveSizeInBits()) {
2472+
Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp);
2473+
return new BitCastInst(FAbs, I.getType());
2474+
}
2475+
}
2476+
24582477
if (match(&I, m_And(m_OneUse(m_Shl(m_ZExt(m_Value(X)), m_Value(Y))),
24592478
m_SignMask())) &&
24602479
match(Y, m_SpecificInt_ICMP(
@@ -4470,6 +4489,9 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
44704489
// If we are XORing the sign bit of a floating-point value, convert
44714490
// this to fneg, then cast back to integer.
44724491
//
4492+
// This is generous interpretation of noimplicitfloat, this is not a true
4493+
// floating-point operation.
4494+
//
44734495
// Assumes any IEEE-represented type has the sign bit in the high bit.
44744496
// TODO: Unify with APInt matcher. This version allows undef unlike m_APInt
44754497
Value *CastOp;

Diff for: llvm/test/Transforms/InstCombine/fabs-as-int.ll

+31-37
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ define <2 x i32> @fabs_as_int_v2f32_noimplicitfloat(<2 x float> %x) noimplicitfl
3030
define float @fabs_as_int_f32_castback(float %val) {
3131
; CHECK-LABEL: define float @fabs_as_int_f32_castback
3232
; CHECK-SAME: (float [[VAL:%.*]]) {
33-
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
34-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[BITCAST]], 2147483647
35-
; CHECK-NEXT: [[FABS:%.*]] = bitcast i32 [[AND]] to float
36-
; CHECK-NEXT: ret float [[FABS]]
33+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]])
34+
; CHECK-NEXT: ret float [[TMP1]]
3735
;
3836
%bitcast = bitcast float %val to i32
3937
%and = and i32 %bitcast, 2147483647
@@ -44,10 +42,8 @@ define float @fabs_as_int_f32_castback(float %val) {
4442
define float @not_fabs_as_int_f32_castback_wrongconst(float %val) {
4543
; CHECK-LABEL: define float @not_fabs_as_int_f32_castback_wrongconst
4644
; CHECK-SAME: (float [[VAL:%.*]]) {
47-
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
48-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[BITCAST]], 2147483647
49-
; CHECK-NEXT: [[FABS:%.*]] = bitcast i32 [[AND]] to float
50-
; CHECK-NEXT: ret float [[FABS]]
45+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]])
46+
; CHECK-NEXT: ret float [[TMP1]]
5147
;
5248
%bitcast = bitcast float %val to i32
5349
%and = and i32 %bitcast, 2147483647
@@ -58,11 +54,9 @@ define float @not_fabs_as_int_f32_castback_wrongconst(float %val) {
5854
define float @fabs_as_int_f32_castback_multi_use(float %val, ptr %ptr) {
5955
; CHECK-LABEL: define float @fabs_as_int_f32_castback_multi_use
6056
; CHECK-SAME: (float [[VAL:%.*]], ptr [[PTR:%.*]]) {
61-
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
62-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[BITCAST]], 2147483647
63-
; CHECK-NEXT: store i32 [[AND]], ptr [[PTR]], align 4
64-
; CHECK-NEXT: [[FABS:%.*]] = bitcast i32 [[AND]] to float
65-
; CHECK-NEXT: ret float [[FABS]]
57+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]])
58+
; CHECK-NEXT: store float [[TMP1]], ptr [[PTR]], align 4
59+
; CHECK-NEXT: ret float [[TMP1]]
6660
;
6761
%bitcast = bitcast float %val to i32
6862
%and = and i32 %bitcast, 2147483647
@@ -74,8 +68,8 @@ define float @fabs_as_int_f32_castback_multi_use(float %val, ptr %ptr) {
7468
define i64 @fabs_as_int_f64(double %x) {
7569
; CHECK-LABEL: define i64 @fabs_as_int_f64
7670
; CHECK-SAME: (double [[X:%.*]]) {
77-
; CHECK-NEXT: [[BC:%.*]] = bitcast double [[X]] to i64
78-
; CHECK-NEXT: [[AND:%.*]] = and i64 [[BC]], 9223372036854775807
71+
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]])
72+
; CHECK-NEXT: [[AND:%.*]] = bitcast double [[TMP1]] to i64
7973
; CHECK-NEXT: ret i64 [[AND]]
8074
;
8175
%bc = bitcast double %x to i64
@@ -86,8 +80,8 @@ define i64 @fabs_as_int_f64(double %x) {
8680
define <2 x i64> @fabs_as_int_v2f64(<2 x double> %x) {
8781
; CHECK-LABEL: define <2 x i64> @fabs_as_int_v2f64
8882
; CHECK-SAME: (<2 x double> [[X:%.*]]) {
89-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x double> [[X]] to <2 x i64>
90-
; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> [[BC]], <i64 9223372036854775807, i64 9223372036854775807>
83+
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x double> @llvm.fabs.v2f64(<2 x double> [[X]])
84+
; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x double> [[TMP1]] to <2 x i64>
9185
; CHECK-NEXT: ret <2 x i64> [[AND]]
9286
;
9387
%bc = bitcast <2 x double> %x to <2 x i64>
@@ -98,8 +92,8 @@ define <2 x i64> @fabs_as_int_v2f64(<2 x double> %x) {
9892
define i64 @fabs_as_int_f64_swap(double %x) {
9993
; CHECK-LABEL: define i64 @fabs_as_int_f64_swap
10094
; CHECK-SAME: (double [[X:%.*]]) {
101-
; CHECK-NEXT: [[BC:%.*]] = bitcast double [[X]] to i64
102-
; CHECK-NEXT: [[AND:%.*]] = and i64 [[BC]], 9223372036854775807
95+
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]])
96+
; CHECK-NEXT: [[AND:%.*]] = bitcast double [[TMP1]] to i64
10397
; CHECK-NEXT: ret i64 [[AND]]
10498
;
10599
%bc = bitcast double %x to i64
@@ -110,8 +104,8 @@ define i64 @fabs_as_int_f64_swap(double %x) {
110104
define i32 @fabs_as_int_f32(float %x) {
111105
; CHECK-LABEL: define i32 @fabs_as_int_f32
112106
; CHECK-SAME: (float [[X:%.*]]) {
113-
; CHECK-NEXT: [[BC:%.*]] = bitcast float [[X]] to i32
114-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[BC]], 2147483647
107+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
108+
; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32
115109
; CHECK-NEXT: ret i32 [[AND]]
116110
;
117111
%bc = bitcast float %x to i32
@@ -122,8 +116,8 @@ define i32 @fabs_as_int_f32(float %x) {
122116
define <2 x i32> @fabs_as_int_v2f32(<2 x float> %x) {
123117
; CHECK-LABEL: define <2 x i32> @fabs_as_int_v2f32
124118
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
125-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x float> [[X]] to <2 x i32>
126-
; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[BC]], <i32 2147483647, i32 2147483647>
119+
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X]])
120+
; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x float> [[TMP1]] to <2 x i32>
127121
; CHECK-NEXT: ret <2 x i32> [[AND]]
128122
;
129123
%bc = bitcast <2 x float> %x to <2 x i32>
@@ -146,8 +140,8 @@ define <2 x i32> @not_fabs_as_int_v2f32_nonsplat(<2 x float> %x) {
146140
define <3 x i32> @fabs_as_int_v3f32_undef(<3 x float> %x) {
147141
; CHECK-LABEL: define <3 x i32> @fabs_as_int_v3f32_undef
148142
; CHECK-SAME: (<3 x float> [[X:%.*]]) {
149-
; CHECK-NEXT: [[BC:%.*]] = bitcast <3 x float> [[X]] to <3 x i32>
150-
; CHECK-NEXT: [[AND:%.*]] = and <3 x i32> [[BC]], <i32 2147483647, i32 undef, i32 2147483647>
143+
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x float> @llvm.fabs.v3f32(<3 x float> [[X]])
144+
; CHECK-NEXT: [[AND:%.*]] = bitcast <3 x float> [[TMP1]] to <3 x i32>
151145
; CHECK-NEXT: ret <3 x i32> [[AND]]
152146
;
153147
%bc = bitcast <3 x float> %x to <3 x i32>
@@ -199,8 +193,8 @@ define float @not_fabs_as_int_f32_bitcast_from_v2i16(<2 x i16> %val) {
199193
define i128 @fabs_as_int_fp128_f64_mask(fp128 %x) {
200194
; CHECK-LABEL: define i128 @fabs_as_int_fp128_f64_mask
201195
; CHECK-SAME: (fp128 [[X:%.*]]) {
202-
; CHECK-NEXT: [[BC:%.*]] = bitcast fp128 [[X]] to i128
203-
; CHECK-NEXT: [[AND:%.*]] = and i128 [[BC]], 170141183460469231731687303715884105727
196+
; CHECK-NEXT: [[TMP1:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X]])
197+
; CHECK-NEXT: [[AND:%.*]] = bitcast fp128 [[TMP1]] to i128
204198
; CHECK-NEXT: ret i128 [[AND]]
205199
;
206200
%bc = bitcast fp128 %x to i128
@@ -211,8 +205,8 @@ define i128 @fabs_as_int_fp128_f64_mask(fp128 %x) {
211205
define i128 @fabs_as_int_fp128_f128_mask(fp128 %x) {
212206
; CHECK-LABEL: define i128 @fabs_as_int_fp128_f128_mask
213207
; CHECK-SAME: (fp128 [[X:%.*]]) {
214-
; CHECK-NEXT: [[BC:%.*]] = bitcast fp128 [[X]] to i128
215-
; CHECK-NEXT: [[AND:%.*]] = and i128 [[BC]], 170141183460469231731687303715884105727
208+
; CHECK-NEXT: [[TMP1:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X]])
209+
; CHECK-NEXT: [[AND:%.*]] = bitcast fp128 [[TMP1]] to i128
216210
; CHECK-NEXT: ret i128 [[AND]]
217211
;
218212
%bc = bitcast fp128 %x to i128
@@ -223,8 +217,8 @@ define i128 @fabs_as_int_fp128_f128_mask(fp128 %x) {
223217
define i16 @fabs_as_int_f16(half %x) {
224218
; CHECK-LABEL: define i16 @fabs_as_int_f16
225219
; CHECK-SAME: (half [[X:%.*]]) {
226-
; CHECK-NEXT: [[BC:%.*]] = bitcast half [[X]] to i16
227-
; CHECK-NEXT: [[AND:%.*]] = and i16 [[BC]], 32767
220+
; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X]])
221+
; CHECK-NEXT: [[AND:%.*]] = bitcast half [[TMP1]] to i16
228222
; CHECK-NEXT: ret i16 [[AND]]
229223
;
230224
%bc = bitcast half %x to i16
@@ -235,8 +229,8 @@ define i16 @fabs_as_int_f16(half %x) {
235229
define <2 x i16> @fabs_as_int_v2f16(<2 x half> %x) {
236230
; CHECK-LABEL: define <2 x i16> @fabs_as_int_v2f16
237231
; CHECK-SAME: (<2 x half> [[X:%.*]]) {
238-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x half> [[X]] to <2 x i16>
239-
; CHECK-NEXT: [[AND:%.*]] = and <2 x i16> [[BC]], <i16 32767, i16 32767>
232+
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X]])
233+
; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x half> [[TMP1]] to <2 x i16>
240234
; CHECK-NEXT: ret <2 x i16> [[AND]]
241235
;
242236
%bc = bitcast <2 x half> %x to <2 x i16>
@@ -247,8 +241,8 @@ define <2 x i16> @fabs_as_int_v2f16(<2 x half> %x) {
247241
define i16 @fabs_as_int_bf16(bfloat %x) {
248242
; CHECK-LABEL: define i16 @fabs_as_int_bf16
249243
; CHECK-SAME: (bfloat [[X:%.*]]) {
250-
; CHECK-NEXT: [[BC:%.*]] = bitcast bfloat [[X]] to i16
251-
; CHECK-NEXT: [[AND:%.*]] = and i16 [[BC]], 32767
244+
; CHECK-NEXT: [[TMP1:%.*]] = call bfloat @llvm.fabs.bf16(bfloat [[X]])
245+
; CHECK-NEXT: [[AND:%.*]] = bitcast bfloat [[TMP1]] to i16
252246
; CHECK-NEXT: ret i16 [[AND]]
253247
;
254248
%bc = bitcast bfloat %x to i16
@@ -259,8 +253,8 @@ define i16 @fabs_as_int_bf16(bfloat %x) {
259253
define <2 x i16> @fabs_as_int_v2bf16(<2 x bfloat> %x) {
260254
; CHECK-LABEL: define <2 x i16> @fabs_as_int_v2bf16
261255
; CHECK-SAME: (<2 x bfloat> [[X:%.*]]) {
262-
; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x bfloat> [[X]] to <2 x i16>
263-
; CHECK-NEXT: [[AND:%.*]] = and <2 x i16> [[BC]], <i16 32767, i16 32767>
256+
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x bfloat> @llvm.fabs.v2bf16(<2 x bfloat> [[X]])
257+
; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x bfloat> [[TMP1]] to <2 x i16>
264258
; CHECK-NEXT: ret <2 x i16> [[AND]]
265259
;
266260
%bc = bitcast <2 x bfloat> %x to <2 x i16>

Diff for: llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ define <2 x i32> @fneg_fabs_as_int_v2f32_noimplicitfloat(<2 x float> %x) noimpli
2828
define float @fneg_fabs_fabs_as_int_f32_and_or(float %val) {
2929
; CHECK-LABEL: define float @fneg_fabs_fabs_as_int_f32_and_or
3030
; CHECK-SAME: (float [[VAL:%.*]]) {
31-
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32
32-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[BITCAST]], -2147483648
31+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]])
32+
; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32
33+
; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND]], -2147483648
3334
; CHECK-NEXT: [[FNEG_FABS:%.*]] = bitcast i32 [[OR]] to float
3435
; CHECK-NEXT: ret float [[FNEG_FABS]]
3536
;

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

+4-6
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) {
7676

7777
define <8 x float> @fneg_fabs(<8 x float> %a) {
7878
; CHECK-LABEL: @fneg_fabs(
79-
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32>
80-
; CHECK-NEXT: [[TMP2:%.*]] = fneg <8 x float> [[A]]
81-
; 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:%.*]] = 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>
84-
; CHECK-NEXT: ret <8 x float> [[TMP5]]
79+
; CHECK-NEXT: [[TMP1:%.*]] = fneg <8 x float> [[A:%.*]]
80+
; CHECK-NEXT: [[TMP2:%.*]] = call <8 x float> @llvm.fabs.v8f32(<8 x float> [[A]])
81+
; 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>
82+
; CHECK-NEXT: ret <8 x float> [[DOTUNCASTED]]
8583
;
8684
%a0 = extractelement <8 x float> %a, i32 0
8785
%a1 = extractelement <8 x float> %a, i32 1

Diff for: llvm/test/Transforms/SLPVectorizer/X86/alternate-cast.ll

+4-6
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) {
7676

7777
define <8 x float> @fneg_fabs(<8 x float> %a) {
7878
; CHECK-LABEL: @fneg_fabs(
79-
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32>
80-
; CHECK-NEXT: [[TMP2:%.*]] = fneg <8 x float> [[A]]
81-
; 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:%.*]] = 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>
84-
; CHECK-NEXT: ret <8 x float> [[TMP5]]
79+
; CHECK-NEXT: [[TMP1:%.*]] = fneg <8 x float> [[A:%.*]]
80+
; CHECK-NEXT: [[TMP2:%.*]] = call <8 x float> @llvm.fabs.v8f32(<8 x float> [[A]])
81+
; 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>
82+
; CHECK-NEXT: ret <8 x float> [[DOTUNCASTED]]
8583
;
8684
%a0 = extractelement <8 x float> %a, i32 0
8785
%a1 = extractelement <8 x float> %a, i32 1

0 commit comments

Comments
 (0)