Skip to content

Commit d2404ea

Browse files
committed
Attributor: Assume handling for nofpclass
1 parent a157898 commit d2404ea

File tree

5 files changed

+108
-36
lines changed

5 files changed

+108
-36
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,16 @@ Intrinsic::ID getIntrinsicForCallSite(const CallBase &CB,
219219

220220
/// Returns a pair of values, which if passed to llvm.is.fpclass, returns the
221221
/// same result as an fcmp with the given operands.
222+
///
223+
/// If \p LookThroughSrc is true, consider the input value when computing the
224+
/// mask.
225+
///
226+
/// If \p LookThroughSrc is false, ignore the source value (i.e. the first pair
227+
/// element will always be LHS.
222228
std::pair<Value *, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred,
223-
const Function &F,
224-
Value *LHS, Value *RHS);
229+
const Function &F, Value *LHS,
230+
Value *RHS,
231+
bool LookThroughSrc = true);
225232

226233
struct KnownFPClass {
227234
/// Floating-point classes the value could be one of.

llvm/lib/Analysis/AssumptionCache.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ findAffectedValues(CallBase *CI, TargetTransformInfo *TTI,
8787
AddAffected(Cond);
8888

8989
CmpInst::Predicate Pred;
90-
if (match(Cond, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
90+
if (match(Cond, m_Cmp(Pred, m_Value(A), m_Value(B)))) {
9191
AddAffected(A);
9292
AddAffected(B);
9393

@@ -128,7 +128,18 @@ findAffectedValues(CallBase *CI, TargetTransformInfo *TTI,
128128
if (match(A, m_Add(m_Value(X), m_ConstantInt())) &&
129129
match(B, m_ConstantInt()))
130130
AddAffected(X);
131+
} else if (CmpInst::isFPPredicate(Pred)) {
132+
// fcmp fneg(x), y
133+
// fcmp fabs(x), y
134+
// fcmp fneg(fabs(x)), y
135+
if (match(A, m_FNeg(m_Value(A))))
136+
AddAffected(A);
137+
if (match(A, m_FAbs(m_Value(A))))
138+
AddAffected(A);
131139
}
140+
} else if (match(Cond, m_Intrinsic<Intrinsic::is_fpclass>(m_Value(A),
141+
m_Value(B)))) {
142+
AddAffected(A);
132143
}
133144

134145
if (TTI) {

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4134,7 +4134,8 @@ static bool inputDenormalIsIEEE(const Function &F, const Value *Val) {
41344134
/// same result as an fcmp with the given operands.
41354135
std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred,
41364136
const Function &F,
4137-
Value *LHS, Value *RHS) {
4137+
Value *LHS, Value *RHS,
4138+
bool LookThroughSrc) {
41384139
const APFloat *ConstRHS;
41394140
if (!match(RHS, m_APFloat(ConstRHS)))
41404141
return {nullptr, fcNone};
@@ -4168,7 +4169,7 @@ std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred,
41684169
}
41694170

41704171
Value *Src = LHS;
4171-
const bool IsFabs = match(LHS, m_FAbs(m_Value(Src)));
4172+
const bool IsFabs = LookThroughSrc && match(LHS, m_FAbs(m_Value(Src)));
41724173

41734174
// Compute the test mask that would return true for the ordered comparisons.
41744175
FPClassTest Mask;
@@ -4295,6 +4296,53 @@ std::pair<Value *, FPClassTest> llvm::fcmpToClassTest(FCmpInst::Predicate Pred,
42954296
return {Src, Mask};
42964297
}
42974298

4299+
static FPClassTest computeKnownFPClassFromAssumes(const Value *V,
4300+
const Query &Q) {
4301+
FPClassTest KnownFromAssume = fcNone;
4302+
4303+
// Try to restrict the floating-point classes based on information from
4304+
// assumptions.
4305+
for (auto &AssumeVH : Q.AC->assumptionsFor(V)) {
4306+
if (!AssumeVH)
4307+
continue;
4308+
CallInst *I = cast<CallInst>(AssumeVH);
4309+
const Function *F = I->getFunction();
4310+
4311+
assert(F == Q.CxtI->getParent()->getParent() &&
4312+
"Got assumption for the wrong function!");
4313+
assert(I->getCalledFunction()->getIntrinsicID() == Intrinsic::assume &&
4314+
"must be an assume intrinsic");
4315+
4316+
if (!isValidAssumeForContext(I, Q.CxtI, Q.DT))
4317+
continue;
4318+
4319+
CmpInst::Predicate Pred;
4320+
Value *LHS, *RHS;
4321+
uint64_t ClassVal = 0;
4322+
if (match(I->getArgOperand(0), m_FCmp(Pred, m_Value(LHS), m_Value(RHS)))) {
4323+
auto [TestedValue, TestedMask] =
4324+
fcmpToClassTest(Pred, *F, LHS, RHS, true);
4325+
// First see if we can fold in fabs/fneg into the test.
4326+
if (TestedValue == V)
4327+
KnownFromAssume |= TestedMask;
4328+
else {
4329+
// Try again without the lookthrough if we found a different source
4330+
// value.
4331+
auto [TestedValue, TestedMask] =
4332+
fcmpToClassTest(Pred, *F, LHS, RHS, false);
4333+
if (TestedValue == V)
4334+
KnownFromAssume |= TestedMask;
4335+
}
4336+
} else if (match(I->getArgOperand(0),
4337+
m_Intrinsic<Intrinsic::is_fpclass>(
4338+
m_Value(LHS), m_ConstantInt(ClassVal)))) {
4339+
KnownFromAssume |= static_cast<FPClassTest>(ClassVal);
4340+
}
4341+
}
4342+
4343+
return KnownFromAssume;
4344+
}
4345+
42984346
// TODO: Merge implementations of isKnownNeverNaN, isKnownNeverInfinity,
42994347
// CannotBeNegativeZero, cannotBeOrderedLessThanZero into here.
43004348
void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
@@ -4332,6 +4380,9 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
43324380
KnownNotFromFlags |= fcInf;
43334381
}
43344382

4383+
if (Q.AC)
4384+
KnownNotFromFlags |= computeKnownFPClassFromAssumes(V, Q);
4385+
43354386
// We no longer need to find out about these bits from inputs if we can
43364387
// assume this from flags/attributes.
43374388
InterestedClasses &= ~KnownNotFromFlags;

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10232,6 +10232,9 @@ struct AANoFPClassImpl : AANoFPClass {
1023210232
KnownFPClass KnownFPClass = computeKnownFPClass(&V, DL);
1023310233
addKnownBits(~KnownFPClass.KnownFPClasses);
1023410234
}
10235+
10236+
if (Instruction *CtxI = getCtxI())
10237+
followUsesInMBEC(*this, A, getState(), *CtxI);
1023510238
}
1023610239

1023710240
/// See followUsesInMBEC

llvm/test/Transforms/Attributor/nofpclass.ll

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,12 @@ bb1:
306306

307307
; Should be able to infer nofpclass on both %arg uses
308308
define float @fcmp_ord_assume_callsite_arg_return(float %arg) {
309-
; CHECK-LABEL: define float @fcmp_ord_assume_callsite_arg_return
310-
; CHECK-SAME: (float returned [[ARG:%.*]]) {
309+
; CHECK-LABEL: define nofpclass(inf zero sub norm) float @fcmp_ord_assume_callsite_arg_return
310+
; CHECK-SAME: (float returned nofpclass(inf zero sub norm) [[ARG:%.*]]) {
311311
; CHECK-NEXT: entry:
312312
; CHECK-NEXT: [[IS_NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
313313
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_NAN]]) #[[ATTR6:[0-9]+]]
314-
; CHECK-NEXT: call void @extern.use(float [[ARG]])
314+
; CHECK-NEXT: call void @extern.use(float nofpclass(inf zero sub norm) [[ARG]])
315315
; CHECK-NEXT: ret float [[ARG]]
316316
;
317317
entry:
@@ -431,12 +431,12 @@ define float @call_noinf_return_1(float %arg) {
431431
}
432432

433433
define float @fcmp_olt_assume_one_0_callsite_arg_return(float %arg) {
434-
; CHECK-LABEL: define float @fcmp_olt_assume_one_0_callsite_arg_return
435-
; CHECK-SAME: (float returned [[ARG:%.*]]) {
434+
; CHECK-LABEL: define nofpclass(inf sub norm) float @fcmp_olt_assume_one_0_callsite_arg_return
435+
; CHECK-SAME: (float returned nofpclass(inf sub norm) [[ARG:%.*]]) {
436436
; CHECK-NEXT: entry:
437437
; CHECK-NEXT: [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp one float [[ARG]], 0.000000e+00
438438
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR6]]
439-
; CHECK-NEXT: call void @extern.use(float [[ARG]])
439+
; CHECK-NEXT: call void @extern.use(float nofpclass(inf sub norm) [[ARG]])
440440
; CHECK-NEXT: ret float [[ARG]]
441441
;
442442
entry:
@@ -447,12 +447,12 @@ entry:
447447
}
448448

449449
define float @fcmp_olt_assume_une_0_callsite_arg_return(float %arg) {
450-
; CHECK-LABEL: define float @fcmp_olt_assume_une_0_callsite_arg_return
451-
; CHECK-SAME: (float returned [[ARG:%.*]]) {
450+
; CHECK-LABEL: define nofpclass(nan inf sub norm) float @fcmp_olt_assume_une_0_callsite_arg_return
451+
; CHECK-SAME: (float returned nofpclass(nan inf sub norm) [[ARG:%.*]]) {
452452
; CHECK-NEXT: entry:
453453
; CHECK-NEXT: [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp une float [[ARG]], 0.000000e+00
454454
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR6]]
455-
; CHECK-NEXT: call void @extern.use(float [[ARG]])
455+
; CHECK-NEXT: call void @extern.use(float nofpclass(nan inf sub norm) [[ARG]])
456456
; CHECK-NEXT: ret float [[ARG]]
457457
;
458458
entry:
@@ -463,13 +463,13 @@ entry:
463463
}
464464

465465
define half @fcmp_assume_issubnormal_callsite_arg_return(half %arg) {
466-
; CHECK-LABEL: define half @fcmp_assume_issubnormal_callsite_arg_return
467-
; CHECK-SAME: (half returned [[ARG:%.*]]) {
466+
; CHECK-LABEL: define nofpclass(zero sub) half @fcmp_assume_issubnormal_callsite_arg_return
467+
; CHECK-SAME: (half returned nofpclass(zero sub) [[ARG:%.*]]) {
468468
; CHECK-NEXT: entry:
469-
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR6]]
469+
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half nofpclass(zero sub) [[ARG]]) #[[ATTR6]]
470470
; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
471471
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR6]]
472-
; CHECK-NEXT: call void @extern.use.f16(half [[ARG]])
472+
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(zero sub) [[ARG]])
473473
; CHECK-NEXT: ret half [[ARG]]
474474
;
475475
entry:
@@ -499,15 +499,15 @@ entry:
499499

500500
; Assume not subnormal or zero, and not infinity
501501
define half @fcmp_assume2_callsite_arg_return(half %arg) {
502-
; CHECK-LABEL: define half @fcmp_assume2_callsite_arg_return
503-
; CHECK-SAME: (half returned [[ARG:%.*]]) {
502+
; CHECK-LABEL: define nofpclass(inf norm) half @fcmp_assume2_callsite_arg_return
503+
; CHECK-SAME: (half returned nofpclass(inf norm) [[ARG:%.*]]) {
504504
; CHECK-NEXT: entry:
505-
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR6]]
505+
; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(inf) half @llvm.fabs.f16(half nofpclass(inf norm) [[ARG]]) #[[ATTR6]]
506506
; CHECK-NEXT: [[NOT_SUBNORMAL_OR_ZERO:%.*]] = fcmp oge half [[FABS]], 0xH0400
507507
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[NOT_SUBNORMAL_OR_ZERO]]) #[[ATTR6]]
508508
; CHECK-NEXT: [[NOT_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00
509509
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[NOT_INF]]) #[[ATTR6]]
510-
; CHECK-NEXT: call void @extern.use.f16(half [[ARG]])
510+
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(inf norm) [[ARG]])
511511
; CHECK-NEXT: ret half [[ARG]]
512512
;
513513
entry:
@@ -523,12 +523,12 @@ entry:
523523
}
524524

525525
define float @is_fpclass_assume_arg_return(float %arg) {
526-
; CHECK-LABEL: define float @is_fpclass_assume_arg_return
527-
; CHECK-SAME: (float returned [[ARG:%.*]]) {
526+
; CHECK-LABEL: define nofpclass(ninf nzero pnorm) float @is_fpclass_assume_arg_return
527+
; CHECK-SAME: (float returned nofpclass(ninf nzero pnorm) [[ARG:%.*]]) {
528528
; CHECK-NEXT: entry:
529-
; CHECK-NEXT: [[CLASS_TEST:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 292) #[[ATTR6]]
529+
; CHECK-NEXT: [[CLASS_TEST:%.*]] = call i1 @llvm.is.fpclass.f32(float nofpclass(ninf nzero pnorm) [[ARG]], i32 noundef 292) #[[ATTR6]]
530530
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[CLASS_TEST]]) #[[ATTR6]]
531-
; CHECK-NEXT: call void @extern.use(float [[ARG]])
531+
; CHECK-NEXT: call void @extern.use(float nofpclass(ninf nzero pnorm) [[ARG]])
532532
; CHECK-NEXT: ret float [[ARG]]
533533
;
534534
entry:
@@ -541,16 +541,16 @@ entry:
541541
; Make sure we don't get confused by looking at an unrelated assume
542542
; based on the fabs of the value.
543543
define half @assume_fcmp_fabs_with_other_fabs_assume(half %arg) {
544-
; CHECK-LABEL: define half @assume_fcmp_fabs_with_other_fabs_assume
545-
; CHECK-SAME: (half returned [[ARG:%.*]]) {
544+
; CHECK-LABEL: define nofpclass(zero sub) half @assume_fcmp_fabs_with_other_fabs_assume
545+
; CHECK-SAME: (half returned nofpclass(zero sub) [[ARG:%.*]]) {
546546
; CHECK-NEXT: entry:
547-
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR6]]
547+
; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(inf zero sub norm) half @llvm.fabs.f16(half nofpclass(zero sub) [[ARG]]) #[[ATTR6]]
548548
; CHECK-NEXT: [[UNRELATED_FABS:%.*]] = fcmp one half [[FABS]], 0xH0000
549549
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR6]]
550550
; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
551551
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR6]]
552-
; CHECK-NEXT: call void @extern.use.f16(half [[ARG]])
553-
; CHECK-NEXT: call void @extern.use.f16(half [[FABS]])
552+
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(zero sub) [[ARG]])
553+
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(inf zero sub norm) [[FABS]])
554554
; CHECK-NEXT: ret half [[ARG]]
555555
;
556556
entry:
@@ -568,18 +568,18 @@ entry:
568568
; Make sure if looking through the fabs finds a different source
569569
; value, we still identify a test mask by ignoring the fabs
570570
define half @assume_fcmp_fabs_with_other_fabs_assume_fallback(half %arg) {
571-
; CHECK-LABEL: define half @assume_fcmp_fabs_with_other_fabs_assume_fallback
572-
; CHECK-SAME: (half returned [[ARG:%.*]]) {
571+
; CHECK-LABEL: define nofpclass(pinf zero sub) half @assume_fcmp_fabs_with_other_fabs_assume_fallback
572+
; CHECK-SAME: (half returned nofpclass(pinf zero sub) [[ARG:%.*]]) {
573573
; CHECK-NEXT: entry:
574-
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR6]]
574+
; CHECK-NEXT: [[FABS:%.*]] = call nofpclass(inf zero sub nnorm) half @llvm.fabs.f16(half nofpclass(pinf zero sub) [[ARG]]) #[[ATTR6]]
575575
; CHECK-NEXT: [[ONE_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00
576576
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ONE_INF]]) #[[ATTR6]]
577577
; CHECK-NEXT: [[UNRELATED_FABS:%.*]] = fcmp oeq half [[FABS]], 0xH0000
578578
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR6]]
579579
; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
580580
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR6]]
581-
; CHECK-NEXT: call void @extern.use.f16(half [[ARG]])
582-
; CHECK-NEXT: call void @extern.use.f16(half [[FABS]])
581+
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(pinf zero sub) [[ARG]])
582+
; CHECK-NEXT: call void @extern.use.f16(half nofpclass(inf zero sub nnorm) [[FABS]])
583583
; CHECK-NEXT: ret half [[ARG]]
584584
;
585585
entry:

0 commit comments

Comments
 (0)