Skip to content

Commit 5f6506a

Browse files
committed
[DAGCombiner] Relax nsz constraint with fp->int->fp optimizations
1 parent 5d79dd0 commit 5f6506a

File tree

2 files changed

+104
-6
lines changed

2 files changed

+104
-6
lines changed

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18871,6 +18871,37 @@ SDValue DAGCombiner::visitFPOW(SDNode *N) {
1887118871

1887218872
return SDValue();
1887318873
}
18874+
/// Check if a use of a floating-point operation doesn't care about the sign of
18875+
/// zero. This allows us to optimize (sitofp (fptosi x)) -> ftrunc(x) even
18876+
/// without NoSignedZerosFPMath, as long as all uses are sign-insensitive.
18877+
static bool isSignInsensitiveUse(SDNode *Use, unsigned OperandNo,
18878+
SelectionDAG &DAG) {
18879+
switch (Use->getOpcode()) {
18880+
case ISD::SETCC:
18881+
// Comparisons: IEEE 754 specifies +0.0 == -0.0.
18882+
case ISD::FABS:
18883+
// fabs always produces +0.0.
18884+
return true;
18885+
case ISD::FADD:
18886+
case ISD::FSUB: {
18887+
// Arithmetic with non-zero constants fixes the uncertainty around the sign
18888+
// bit.
18889+
SDValue Other = Use->getOperand(1 - OperandNo);
18890+
return DAG.isKnownNeverZeroFloat(Other);
18891+
}
18892+
default:
18893+
return false;
18894+
}
18895+
}
18896+
18897+
/// Check if all uses of a value are insensitive to the sign of zero.
18898+
static bool allUsesSignInsensitive(SDValue V, SelectionDAG &DAG) {
18899+
return all_of(V->uses(), [&](SDUse &Use) {
18900+
SDNode *User = Use.getUser();
18901+
unsigned OperandNo = Use.getOperandNo();
18902+
return isSignInsensitiveUse(User, OperandNo, DAG);
18903+
});
18904+
}
1887418905

1887518906
static SDValue foldFPToIntToFP(SDNode *N, const SDLoc &DL, SelectionDAG &DAG,
1887618907
const TargetLowering &TLI) {
@@ -18892,12 +18923,13 @@ static SDValue foldFPToIntToFP(SDNode *N, const SDLoc &DL, SelectionDAG &DAG,
1889218923
bool IsSigned = N->getOpcode() == ISD::SINT_TO_FP;
1889318924
assert(IsSigned || IsUnsigned);
1889418925

18895-
bool IsSignedZeroSafe = DAG.getTarget().Options.NoSignedZerosFPMath;
18926+
bool IsSignedZeroSafe = DAG.getTarget().Options.NoSignedZerosFPMath ||
18927+
allUsesSignInsensitive(SDValue(N, 0), DAG);
1889618928
// For signed conversions: The optimization changes signed zero behavior.
1889718929
if (IsSigned && !IsSignedZeroSafe)
1889818930
return SDValue();
1889918931
// For unsigned conversions, we need FABS to canonicalize -0.0 to +0.0
18900-
// (unless NoSignedZerosFPMath is set).
18932+
// (unless outputting a signed zero is OK).
1890118933
if (IsUnsigned && !IsSignedZeroSafe && !TLI.isFAbsFree(VT))
1890218934
return SDValue();
1890318935

@@ -19376,10 +19408,17 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) {
1937619408
// FIXME: This is duplicated in getNegatibleCost, but getNegatibleCost doesn't
1937719409
// know it was called from a context with a nsz flag if the input fsub does
1937819410
// not.
19379-
if (N0.getOpcode() == ISD::FSUB && N->getFlags().hasNoSignedZeros() &&
19380-
N0.hasOneUse()) {
19381-
return DAG.getNode(ISD::FSUB, SDLoc(N), VT, N0.getOperand(1),
19382-
N0.getOperand(0));
19411+
if (N0.getOpcode() == ISD::FSUB && N0.hasOneUse()) {
19412+
SDValue X = N0.getOperand(0);
19413+
SDValue Y = N0.getOperand(1);
19414+
19415+
// Safe if NoSignedZeros, or if we can prove X != Y (avoiding the -0.0 vs
19416+
// +0.0 issue) For now, we use a conservative check: if either operand is
19417+
// known never zero, then X - Y can't produce a signed zero from X == Y.
19418+
if (N->getFlags().hasNoSignedZeros() || DAG.isKnownNeverZeroFloat(X) ||
19419+
DAG.isKnownNeverZeroFloat(Y)) {
19420+
return DAG.getNode(ISD::FSUB, SDLoc(N), VT, Y, X);
19421+
}
1938319422
}
1938419423

1938519424
if (SimplifyDemandedBits(SDValue(N, 0)))

llvm/test/CodeGen/AArch64/fp-to-int-to-fp.ll

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,66 @@ entry:
134134
ret float %f
135135
}
136136

137+
define i1 @test_fcmp(float %x) {
138+
; CHECK-LABEL: test_fcmp:
139+
; CHECK: // %bb.0:
140+
; CHECK-NEXT: frintz s0, s0
141+
; CHECK-NEXT: fcmp s0, #0.0
142+
; CHECK-NEXT: cset w0, eq
143+
; CHECK-NEXT: ret
144+
;
145+
; NO-SIGNED-ZEROS-LABEL: test_fcmp:
146+
; NO-SIGNED-ZEROS: // %bb.0:
147+
; NO-SIGNED-ZEROS-NEXT: frintz s0, s0
148+
; NO-SIGNED-ZEROS-NEXT: fcmp s0, #0.0
149+
; NO-SIGNED-ZEROS-NEXT: cset w0, eq
150+
; NO-SIGNED-ZEROS-NEXT: ret
151+
%conv1 = fptosi float %x to i32
152+
%conv2 = sitofp i32 %conv1 to float
153+
%cmp = fcmp oeq float %conv2, 0.0
154+
ret i1 %cmp
155+
}
156+
157+
define float @test_fadd(float %x) {
158+
; CHECK-LABEL: test_fadd:
159+
; CHECK: // %bb.0:
160+
; CHECK-NEXT: frintz s0, s0
161+
; CHECK-NEXT: fmov s1, #1.00000000
162+
; CHECK-NEXT: fadd s0, s0, s1
163+
; CHECK-NEXT: ret
164+
;
165+
; NO-SIGNED-ZEROS-LABEL: test_fadd:
166+
; NO-SIGNED-ZEROS: // %bb.0:
167+
; NO-SIGNED-ZEROS-NEXT: frintz s0, s0
168+
; NO-SIGNED-ZEROS-NEXT: fmov s1, #1.00000000
169+
; NO-SIGNED-ZEROS-NEXT: fadd s0, s0, s1
170+
; NO-SIGNED-ZEROS-NEXT: ret
171+
%conv1 = fptosi float %x to i32
172+
%conv2 = sitofp i32 %conv1 to float
173+
%add = fadd float %conv2, 1.0
174+
ret float %add
175+
}
176+
177+
define float @test_fabs(float %x) {
178+
; CHECK-LABEL: test_fabs:
179+
; CHECK: // %bb.0:
180+
; CHECK-NEXT: frintz s0, s0
181+
; CHECK-NEXT: fabs s0, s0
182+
; CHECK-NEXT: ret
183+
;
184+
; NO-SIGNED-ZEROS-LABEL: test_fabs:
185+
; NO-SIGNED-ZEROS: // %bb.0:
186+
; NO-SIGNED-ZEROS-NEXT: frintz s0, s0
187+
; NO-SIGNED-ZEROS-NEXT: fabs s0, s0
188+
; NO-SIGNED-ZEROS-NEXT: ret
189+
%conv1 = fptosi float %x to i32
190+
%conv2 = sitofp i32 %conv1 to float
191+
%abs = call float @llvm.fabs.f32(float %conv2)
192+
ret float %abs
193+
}
194+
137195
declare i32 @llvm.smin.i32(i32, i32)
138196
declare i32 @llvm.smax.i32(i32, i32)
139197
declare i32 @llvm.umin.i32(i32, i32)
140198
declare i32 @llvm.umax.i32(i32, i32)
199+
declare float @llvm.fabs.f32(float)

0 commit comments

Comments
 (0)