Skip to content

Commit

Permalink
ValueTracking: Improve trunc handling in computeKnownFPClass
Browse files Browse the repository at this point in the history
  • Loading branch information
arsenm committed Apr 26, 2023
1 parent 2ff52ea commit 77e3fea
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 23 deletions.
26 changes: 20 additions & 6 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,40 +238,54 @@ struct KnownFPClass {
/// definitely set or false if the sign bit is definitely unset.
std::optional<bool> SignBit;

/// Return true if it's known this can never be one of the mask entries.
bool isKnownNever(FPClassTest Mask) const {
return (KnownFPClasses & Mask) == fcNone;
}

bool isUnknown() const {
return KnownFPClasses == fcAllFlags && !SignBit;
}

/// Return true if it's known this can never be a nan.
bool isKnownNeverNaN() const {
return (KnownFPClasses & fcNan) == fcNone;
return isKnownNever(fcNan);
}

/// Return true if it's known this can never be an infinity.
bool isKnownNeverInfinity() const {
return (KnownFPClasses & fcInf) == fcNone;
return isKnownNever(fcInf);
}

/// Return true if it's known this can never be +infinity.
bool isKnownNeverPosInfinity() const {
return (KnownFPClasses & fcPosInf) == fcNone;
return isKnownNever(fcPosInf);
}

/// Return true if it's known this can never be -infinity.
bool isKnownNeverNegInfinity() const {
return (KnownFPClasses & fcNegInf) == fcNone;
return isKnownNever(fcNegInf);
}

/// Return true if it's known this can never be a subnormal
bool isKnownNeverSubnormal() const {
return (KnownFPClasses & fcSubnormal) == fcNone;
return isKnownNever(fcSubnormal);
}

/// Return true if it's known this can never be a negativesubnormal
bool isKnownNeverNegSubnormal() const {
return isKnownNever(fcNegSubnormal);
}

/// Return true if it's known this can never be a zero. This means a literal
/// [+-]0, and does not include denormal inputs implicitly treated as [+-]0.
bool isKnownNeverZero() const {
return (KnownFPClasses & fcZero) == fcNone;
return isKnownNever(fcZero);
}

/// Return true if it's known this can never be a literal negative zero.
bool isKnownNeverNegZero() const {
return isKnownNever(fcNegZero);
}

/// Return true if it's know this can never be interpreted as a zero. This
Expand Down
26 changes: 23 additions & 3 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4620,8 +4620,13 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
}
case Intrinsic::trunc: {
KnownFPClass KnownSrc;
computeKnownFPClass(II->getArgOperand(0), DemandedElts,
InterestedClasses, KnownSrc, Depth + 1, Q, TLI);

FPClassTest InterestedSrcs = InterestedClasses;
if (InterestedClasses & fcZero)
InterestedClasses |= fcNormal | fcSubnormal;

computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
KnownSrc, Depth + 1, Q, TLI);

// Integer results cannot be subnormal.
Known.knownNot(fcSubnormal);
Expand All @@ -4635,6 +4640,21 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
// Non-constrained intrinsics do not guarantee signaling nan quieting.
if (KnownSrc.isKnownNeverNaN())
Known.knownNot(fcNan);

if (KnownSrc.isKnownNever(fcPosNormal))
Known.knownNot(fcPosNormal);

if (KnownSrc.isKnownNever(fcNegNormal))
Known.knownNot(fcNegNormal);

if (KnownSrc.isKnownNever(fcPosZero | fcPosSubnormal | fcPosNormal))
Known.knownNot(fcPosZero);

if (KnownSrc.isKnownNever(fcNegZero | fcNegSubnormal | fcNegNormal))
Known.knownNot(fcNegZero);

// Sign should be preserved
Known.SignBit = KnownSrc.SignBit;
break;
}
case Intrinsic::exp:
Expand Down Expand Up @@ -4675,7 +4695,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
if ((InterestedClasses & fcNegInf) != fcNone)
InterestedSrcs |= fcZero | fcSubnormal;
if ((InterestedClasses & fcNan) != fcNone)
InterestedSrcs |= fcNan | KnownFPClass::OrderedLessThanZeroMask;
InterestedSrcs |= fcNan | (fcNegative & ~fcNan);

KnownFPClass KnownSrc;
computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
Expand Down
28 changes: 14 additions & 14 deletions llvm/test/Transforms/Attributor/nofpclass-trunc.ll
Original file line number Diff line number Diff line change
Expand Up @@ -105,29 +105,29 @@ define float @ret_trunc_nonzero(float nofpclass(nzero) %arg0) {
}

define float @ret_trunc_nonorm(float nofpclass(norm) %arg0) {
; CHECK-LABEL: define nofpclass(sub) float @ret_trunc_nonorm
; CHECK-LABEL: define nofpclass(sub norm) float @ret_trunc_nonorm
; CHECK-SAME: (float nofpclass(norm) [[ARG0:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub norm) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.trunc.f32(float %arg0)
ret float %call
}

define float @ret_trunc_nonnorm(float nofpclass(nnorm) %arg0) {
; CHECK-LABEL: define nofpclass(sub) float @ret_trunc_nonnorm
; CHECK-LABEL: define nofpclass(sub nnorm) float @ret_trunc_nonnorm
; CHECK-SAME: (float nofpclass(nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub nnorm) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.trunc.f32(float %arg0)
ret float %call
}

define float @ret_trunc_nopnorm(float nofpclass(pnorm) %arg0) {
; CHECK-LABEL: define nofpclass(sub) float @ret_trunc_nopnorm
; CHECK-LABEL: define nofpclass(sub pnorm) float @ret_trunc_nopnorm
; CHECK-SAME: (float nofpclass(pnorm) [[ARG0:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub pnorm) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.trunc.f32(float %arg0)
Expand Down Expand Up @@ -155,39 +155,39 @@ define float @ret_trunc_nopsub(float nofpclass(psub) %arg0) {
}

define float @ret_trunc_nonorm_nosub(float nofpclass(norm sub) %arg0) {
; CHECK-LABEL: define nofpclass(sub) float @ret_trunc_nonorm_nosub
; CHECK-LABEL: define nofpclass(sub norm) float @ret_trunc_nonorm_nosub
; CHECK-SAME: (float nofpclass(sub norm) [[ARG0:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub norm) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.trunc.f32(float %arg0)
ret float %call
}

define float @ret_trunc_nopnorm_nopsub(float nofpclass(pnorm psub) %arg0) {
; CHECK-LABEL: define nofpclass(sub) float @ret_trunc_nopnorm_nopsub
; CHECK-LABEL: define nofpclass(sub pnorm) float @ret_trunc_nopnorm_nopsub
; CHECK-SAME: (float nofpclass(psub pnorm) [[ARG0:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub pnorm) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.trunc.f32(float %arg0)
ret float %call
}

define float @ret_trunc_nonnorm_nonsub(float nofpclass(nnorm nsub) %arg0) {
; CHECK-LABEL: define nofpclass(sub) float @ret_trunc_nonnorm_nonsub
; CHECK-LABEL: define nofpclass(sub nnorm) float @ret_trunc_nonnorm_nonsub
; CHECK-SAME: (float nofpclass(nsub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub nnorm) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.trunc.f32(float %arg0)
ret float %call
}

define float @ret_trunc_nopnorm_nonsub(float nofpclass(pnorm nsub) %arg0) {
; CHECK-LABEL: define nofpclass(sub) float @ret_trunc_nopnorm_nonsub
; CHECK-LABEL: define nofpclass(sub pnorm) float @ret_trunc_nopnorm_nonsub
; CHECK-SAME: (float nofpclass(nsub pnorm) [[ARG0:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub pnorm) float @llvm.trunc.f32(float [[ARG0]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.trunc.f32(float %arg0)
Expand Down

0 comments on commit 77e3fea

Please sign in to comment.