Skip to content

Commit 0b59af4

Browse files
authored
[InstCombine] Clear sign-bit of the constant magnitude in copysign (#85787)
Alive2: https://alive2.llvm.org/ce/z/vFykcZ Address the comment #85772 (comment). Unfortunately, non-splat vector constants are not supported because we haven't implemented constant folding of fabs with vector operands.
1 parent da118c9 commit 0b59af4

File tree

3 files changed

+94
-5
lines changed

3 files changed

+94
-5
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,6 +2473,16 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
24732473
if (match(Sign, m_Intrinsic<Intrinsic::copysign>(m_Value(), m_Value(X))))
24742474
return replaceOperand(*II, 1, X);
24752475

2476+
// Clear sign-bit of constant magnitude:
2477+
// copysign -MagC, X --> copysign MagC, X
2478+
// TODO: Support constant folding for fabs
2479+
const APFloat *MagC;
2480+
if (match(Mag, m_APFloat(MagC)) && MagC->isNegative()) {
2481+
APFloat PosMagC = *MagC;
2482+
PosMagC.clearSign();
2483+
return replaceOperand(*II, 0, ConstantFP::get(Mag->getType(), PosMagC));
2484+
}
2485+
24762486
// Peek through changes of magnitude's sign-bit. This call rewrites those:
24772487
// copysign (fabs X), Sign --> copysign X, Sign
24782488
// copysign (fneg X), Sign --> copysign X, Sign

llvm/test/Transforms/InstCombine/copysign-fneg-fabs.ll

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,85 @@ define half @fneg_fabs_copysign_multi_use_fabs(half %x, half %y, ptr %ptr) {
275275
ret half %fabs.copysign
276276
}
277277

278+
define half @copysign_pos(half %a) {
279+
; CHECK-LABEL: @copysign_pos(
280+
; CHECK-NEXT: entry:
281+
; CHECK-NEXT: [[RET:%.*]] = call half @llvm.copysign.f16(half 0xH3C00, half [[A:%.*]])
282+
; CHECK-NEXT: ret half [[RET]]
283+
;
284+
entry:
285+
%ret = call half @llvm.copysign.f16(half 0xH3C00, half %a)
286+
ret half %ret
287+
}
288+
289+
define half @copysign_neg(half %a) {
290+
; CHECK-LABEL: @copysign_neg(
291+
; CHECK-NEXT: entry:
292+
; CHECK-NEXT: [[RET:%.*]] = call half @llvm.copysign.f16(half 0xH3C00, half [[A:%.*]])
293+
; CHECK-NEXT: ret half [[RET]]
294+
;
295+
entry:
296+
%ret = call half @llvm.copysign.f16(half 0xHBC00, half %a)
297+
ret half %ret
298+
}
299+
300+
define half @copysign_negzero(half %a) {
301+
; CHECK-LABEL: @copysign_negzero(
302+
; CHECK-NEXT: entry:
303+
; CHECK-NEXT: [[RET:%.*]] = call half @llvm.copysign.f16(half 0xH0000, half [[A:%.*]])
304+
; CHECK-NEXT: ret half [[RET]]
305+
;
306+
entry:
307+
%ret = call half @llvm.copysign.f16(half 0xH8000, half %a)
308+
ret half %ret
309+
}
310+
311+
define half @copysign_negnan(half %a) {
312+
; CHECK-LABEL: @copysign_negnan(
313+
; CHECK-NEXT: entry:
314+
; CHECK-NEXT: [[RET:%.*]] = call half @llvm.copysign.f16(half 0xH7E00, half [[A:%.*]])
315+
; CHECK-NEXT: ret half [[RET]]
316+
;
317+
entry:
318+
%ret = call half @llvm.copysign.f16(half 0xHFE00, half %a)
319+
ret half %ret
320+
}
321+
322+
define half @copysign_neginf(half %a) {
323+
; CHECK-LABEL: @copysign_neginf(
324+
; CHECK-NEXT: entry:
325+
; CHECK-NEXT: [[RET:%.*]] = call half @llvm.copysign.f16(half 0xH7C00, half [[A:%.*]])
326+
; CHECK-NEXT: ret half [[RET]]
327+
;
328+
entry:
329+
%ret = call half @llvm.copysign.f16(half 0xHFC00, half %a)
330+
ret half %ret
331+
}
332+
333+
define <4 x half> @copysign_splat(<4 x half> %a) {
334+
; CHECK-LABEL: @copysign_splat(
335+
; CHECK-NEXT: entry:
336+
; CHECK-NEXT: [[RET:%.*]] = call <4 x half> @llvm.copysign.v4f16(<4 x half> <half 0xH3C00, half 0xH3C00, half 0xH3C00, half 0xH3C00>, <4 x half> [[A:%.*]])
337+
; CHECK-NEXT: ret <4 x half> [[RET]]
338+
;
339+
entry:
340+
%ret = call <4 x half> @llvm.copysign.v4f16(<4 x half> splat(half 0xHBC00), <4 x half> %a)
341+
ret <4 x half> %ret
342+
}
343+
344+
; TODO: Support constant folding of fabs
345+
346+
define <4 x half> @copysign_vec4(<4 x half> %a) {
347+
; CHECK-LABEL: @copysign_vec4(
348+
; CHECK-NEXT: entry:
349+
; CHECK-NEXT: [[RET:%.*]] = call <4 x half> @llvm.copysign.v4f16(<4 x half> <half 0xH3C00, half 0xHBC00, half undef, half poison>, <4 x half> [[A:%.*]])
350+
; CHECK-NEXT: ret <4 x half> [[RET]]
351+
;
352+
entry:
353+
%ret = call <4 x half> @llvm.copysign.v4f16(<4 x half> <half 0xH3C00, half 0xHBC00, half undef, half poison>, <4 x half> %a)
354+
ret <4 x half> %ret
355+
}
356+
278357
declare half @llvm.fabs.f16(half)
279358
declare <2 x half> @llvm.fabs.v2f16(<2 x half>)
280359
declare half @llvm.copysign.f16(half, half)

llvm/test/Transforms/InstCombine/fcmp.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ define <2 x i1> @is_signbit_set_anyzero(<2 x double> %x) {
644644

645645
define i1 @is_signbit_clear(double %x) {
646646
; CHECK-LABEL: @is_signbit_clear(
647-
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]])
647+
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 4.200000e+01, double [[X:%.*]])
648648
; CHECK-NEXT: [[R:%.*]] = fcmp ogt double [[S]], 0.000000e+00
649649
; CHECK-NEXT: ret i1 [[R]]
650650
;
@@ -655,7 +655,7 @@ define i1 @is_signbit_clear(double %x) {
655655

656656
define i1 @is_signbit_clear_1(double %x) {
657657
; CHECK-LABEL: @is_signbit_clear_1(
658-
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]])
658+
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 4.200000e+01, double [[X:%.*]])
659659
; CHECK-NEXT: [[R:%.*]] = fcmp ugt double [[S]], 0.000000e+00
660660
; CHECK-NEXT: ret i1 [[R]]
661661
;
@@ -666,7 +666,7 @@ define i1 @is_signbit_clear_1(double %x) {
666666

667667
define i1 @is_signbit_clear_2(double %x) {
668668
; CHECK-LABEL: @is_signbit_clear_2(
669-
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]])
669+
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 4.200000e+01, double [[X:%.*]])
670670
; CHECK-NEXT: [[R:%.*]] = fcmp oge double [[S]], 0.000000e+00
671671
; CHECK-NEXT: ret i1 [[R]]
672672
;
@@ -677,7 +677,7 @@ define i1 @is_signbit_clear_2(double %x) {
677677

678678
define i1 @is_signbit_clear_3(double %x) {
679679
; CHECK-LABEL: @is_signbit_clear_3(
680-
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]])
680+
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 4.200000e+01, double [[X:%.*]])
681681
; CHECK-NEXT: [[R:%.*]] = fcmp uge double [[S]], 0.000000e+00
682682
; CHECK-NEXT: ret i1 [[R]]
683683
;
@@ -705,7 +705,7 @@ define i1 @is_signbit_set_extra_use(double %x, ptr %p) {
705705

706706
define i1 @is_signbit_clear_nonzero(double %x) {
707707
; CHECK-LABEL: @is_signbit_clear_nonzero(
708-
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]])
708+
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 4.200000e+01, double [[X:%.*]])
709709
; CHECK-NEXT: [[R:%.*]] = fcmp ogt double [[S]], 1.000000e+00
710710
; CHECK-NEXT: ret i1 [[R]]
711711
;

0 commit comments

Comments
 (0)