Skip to content

Commit 95a311f

Browse files
committed
[LVI][SCCP] Add basic ConstantFPRange support
1 parent a042cd0 commit 95a311f

File tree

7 files changed

+331
-55
lines changed

7 files changed

+331
-55
lines changed

llvm/include/llvm/Analysis/ValueLattice.h

Lines changed: 195 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_ANALYSIS_VALUELATTICE_H
1010
#define LLVM_ANALYSIS_VALUELATTICE_H
1111

12+
#include "llvm/IR/ConstantFPRange.h"
1213
#include "llvm/IR/ConstantRange.h"
1314
#include "llvm/IR/Constants.h"
1415
#include "llvm/Support/Compiler.h"
@@ -39,6 +40,7 @@ class ValueLatticeElement {
3940
/// Transition allowed to the following states:
4041
/// constant
4142
/// constantrange_including_undef
43+
/// constantfprange_including_undef
4244
/// overdefined
4345
undef,
4446

@@ -71,6 +73,21 @@ class ValueLatticeElement {
7173
/// overdefined
7274
constantrange_including_undef,
7375

76+
/// The Value falls within this range. (Used only for floating point typed
77+
/// values.)
78+
/// Transition allowed to the following states:
79+
/// constantfprange (new range must be a superset of the existing range)
80+
/// constantfprange_including_undef
81+
/// overdefined
82+
constantfprange,
83+
84+
/// This Value falls within this range, but also may be undef.
85+
/// Merging it with other constant ranges results in
86+
/// constantfprange_including_undef.
87+
/// Transition allowed to the following states:
88+
/// overdefined
89+
constantfprange_including_undef,
90+
7491
/// We can not precisely model the dynamic values this value might take.
7592
/// No transitions are allowed after reaching overdefined.
7693
overdefined,
@@ -86,6 +103,7 @@ class ValueLatticeElement {
86103
union {
87104
Constant *ConstVal;
88105
ConstantRange Range;
106+
ConstantFPRange FPRange;
89107
};
90108

91109
/// Destroy contents of lattice value, without destructing the object.
@@ -101,6 +119,10 @@ class ValueLatticeElement {
101119
case constantrange:
102120
Range.~ConstantRange();
103121
break;
122+
case constantfprange_including_undef:
123+
case constantfprange:
124+
FPRange.~ConstantFPRange();
125+
break;
104126
};
105127
}
106128

@@ -155,6 +177,11 @@ class ValueLatticeElement {
155177
new (&Range) ConstantRange(Other.Range);
156178
NumRangeExtensions = Other.NumRangeExtensions;
157179
break;
180+
case constantfprange:
181+
case constantfprange_including_undef:
182+
new (&FPRange) ConstantFPRange(Other.FPRange);
183+
NumRangeExtensions = Other.NumRangeExtensions;
184+
break;
158185
case constant:
159186
case notconstant:
160187
ConstVal = Other.ConstVal;
@@ -174,6 +201,11 @@ class ValueLatticeElement {
174201
new (&Range) ConstantRange(std::move(Other.Range));
175202
NumRangeExtensions = Other.NumRangeExtensions;
176203
break;
204+
case constantfprange:
205+
case constantfprange_including_undef:
206+
new (&FPRange) ConstantFPRange(std::move(Other.FPRange));
207+
NumRangeExtensions = Other.NumRangeExtensions;
208+
break;
177209
case constant:
178210
case notconstant:
179211
ConstVal = Other.ConstVal;
@@ -226,6 +258,23 @@ class ValueLatticeElement {
226258
MergeOptions().setMayIncludeUndef(MayIncludeUndef));
227259
return Res;
228260
}
261+
static ValueLatticeElement getFPRange(ConstantFPRange CR,
262+
bool MayIncludeUndef = false) {
263+
if (CR.isFullSet())
264+
return getOverdefined();
265+
266+
if (CR.isEmptySet()) {
267+
ValueLatticeElement Res;
268+
if (MayIncludeUndef)
269+
Res.markUndef();
270+
return Res;
271+
}
272+
273+
ValueLatticeElement Res;
274+
Res.markConstantFPRange(std::move(CR),
275+
MergeOptions().setMayIncludeUndef(MayIncludeUndef));
276+
return Res;
277+
}
229278
static ValueLatticeElement getOverdefined() {
230279
ValueLatticeElement Res;
231280
Res.markOverdefined();
@@ -240,6 +289,9 @@ class ValueLatticeElement {
240289
bool isConstantRangeIncludingUndef() const {
241290
return Tag == constantrange_including_undef;
242291
}
292+
bool isConstantFPRangeIncludingUndef() const {
293+
return Tag == constantfprange_including_undef;
294+
}
243295
/// Returns true if this value is a constant range. Use \p UndefAllowed to
244296
/// exclude non-singleton constant ranges that may also be undef. Note that
245297
/// this function also returns true if the range may include undef, but only
@@ -248,6 +300,16 @@ class ValueLatticeElement {
248300
return Tag == constantrange || (Tag == constantrange_including_undef &&
249301
(UndefAllowed || Range.isSingleElement()));
250302
}
303+
/// Returns true if this value is a constant floating point range. Use \p
304+
/// UndefAllowed to exclude non-singleton constant ranges that may also be
305+
/// undef. Note that this function also returns true if the range may include
306+
/// undef, but only contains a single element. In that case, it can be
307+
/// replaced by a constant.
308+
bool isConstantFPRange(bool UndefAllowed = true) const {
309+
return Tag == constantfprange ||
310+
(Tag == constantfprange_including_undef &&
311+
(UndefAllowed || FPRange.isSingleElement()));
312+
}
251313
bool isOverdefined() const { return Tag == overdefined; }
252314

253315
Constant *getConstant() const {
@@ -270,6 +332,17 @@ class ValueLatticeElement {
270332
return Range;
271333
}
272334

335+
/// Returns the constant floating point range for this value. Use \p
336+
/// UndefAllowed to exclude non-singleton constant ranges that may also be
337+
/// undef. Note that this function also returns a range if the range may
338+
/// include undef, but only contains a single element. In that case, it can be
339+
/// replaced by a constant.
340+
const ConstantFPRange &getConstantFPRange(bool UndefAllowed = true) const {
341+
assert(isConstantFPRange(UndefAllowed) &&
342+
"Cannot get the constant-fprange of a non-constant-fprange!");
343+
return FPRange;
344+
}
345+
273346
std::optional<APInt> asConstantInteger() const {
274347
if (isConstant() && isa<ConstantInt>(getConstant())) {
275348
return cast<ConstantInt>(getConstant())->getValue();
@@ -279,6 +352,15 @@ class ValueLatticeElement {
279352
return std::nullopt;
280353
}
281354

355+
std::optional<APFloat> asConstantFP() const {
356+
if (isConstant() && isa<ConstantFP>(getConstant())) {
357+
return cast<ConstantFP>(getConstant())->getValue();
358+
} else if (isConstantFPRange() && getConstantFPRange().isSingleElement()) {
359+
return *getConstantFPRange().getSingleElement();
360+
}
361+
return std::nullopt;
362+
}
363+
282364
ConstantRange asConstantRange(unsigned BW, bool UndefAllowed = false) const {
283365
if (isConstantRange(UndefAllowed))
284366
return getConstantRange();
@@ -289,11 +371,28 @@ class ValueLatticeElement {
289371
return ConstantRange::getFull(BW);
290372
}
291373

374+
ConstantFPRange asConstantFPRange(const fltSemantics &Sem,
375+
bool UndefAllowed = false) const {
376+
if (isConstantFPRange(UndefAllowed))
377+
return getConstantFPRange();
378+
if (isConstant())
379+
return getConstant()->toConstantFPRange();
380+
if (isUnknown())
381+
return ConstantFPRange::getEmpty(Sem);
382+
return ConstantFPRange::getFull(Sem);
383+
}
384+
292385
ConstantRange asConstantRange(Type *Ty, bool UndefAllowed = false) const {
293386
assert(Ty->isIntOrIntVectorTy() && "Must be integer type");
294387
return asConstantRange(Ty->getScalarSizeInBits(), UndefAllowed);
295388
}
296389

390+
ConstantFPRange asConstantFPRange(Type *Ty, bool UndefAllowed = false) const {
391+
assert(Ty->isFPOrFPVectorTy() && "Must be floating point type");
392+
return asConstantFPRange(Ty->getScalarType()->getFltSemantics(),
393+
UndefAllowed);
394+
}
395+
297396
bool markOverdefined() {
298397
if (isOverdefined())
299398
return false;
@@ -395,6 +494,51 @@ class ValueLatticeElement {
395494
return true;
396495
}
397496

497+
/// Mark the object as constant floating point range with \p NewR. If the
498+
/// object is already a constant range, nothing changes if the existing range
499+
/// is equal to \p NewR and the tag. Otherwise \p NewR must be a superset of
500+
/// the existing range or the object must be undef. The tag is set to
501+
/// constant_range_including_undef if either the existing value or the new
502+
/// range may include undef.
503+
bool markConstantFPRange(ConstantFPRange NewR,
504+
MergeOptions Opts = MergeOptions()) {
505+
assert(!NewR.isEmptySet() && "should only be called for non-empty sets");
506+
507+
if (NewR.isFullSet())
508+
return markOverdefined();
509+
510+
ValueLatticeElementTy OldTag = Tag;
511+
ValueLatticeElementTy NewTag =
512+
(isUndef() || isConstantFPRangeIncludingUndef() || Opts.MayIncludeUndef)
513+
? constantfprange_including_undef
514+
: constantfprange;
515+
if (isConstantFPRange()) {
516+
Tag = NewTag;
517+
if (getConstantFPRange() == NewR)
518+
return Tag != OldTag;
519+
520+
// Simple form of widening. If a range is extended multiple times, go to
521+
// overdefined.
522+
if (Opts.CheckWiden && ++NumRangeExtensions > Opts.MaxWidenSteps)
523+
return markOverdefined();
524+
525+
assert(NewR.contains(getConstantFPRange()) &&
526+
"Existing range must be a subset of NewR");
527+
FPRange = std::move(NewR);
528+
return true;
529+
}
530+
531+
assert(isUnknown() || isUndef() || isConstant());
532+
assert(
533+
(!isConstant() || NewR.contains(getConstant()->toConstantFPRange())) &&
534+
"Constant must be subset of new range");
535+
536+
NumRangeExtensions = 0;
537+
Tag = NewTag;
538+
new (&FPRange) ConstantFPRange(std::move(NewR));
539+
return true;
540+
}
541+
398542
/// Updates this object to approximate both this object and RHS. Returns
399543
/// true if this object has been changed.
400544
bool mergeIn(const ValueLatticeElement &RHS,
@@ -415,6 +559,9 @@ class ValueLatticeElement {
415559
if (RHS.isConstantRange())
416560
return markConstantRange(RHS.getConstantRange(true),
417561
Opts.setMayIncludeUndef());
562+
if (RHS.isConstantFPRange())
563+
return markConstantFPRange(RHS.getConstantFPRange(true),
564+
Opts.setMayIncludeUndef());
418565
return markOverdefined();
419566
}
420567

@@ -429,15 +576,26 @@ class ValueLatticeElement {
429576
return false;
430577
if (RHS.isUndef())
431578
return false;
432-
// If the constant is a vector of integers, try to treat it as a range.
433-
if (getConstant()->getType()->isVectorTy() &&
434-
getConstant()->getType()->getScalarType()->isIntegerTy()) {
435-
ConstantRange L = getConstant()->toConstantRange();
436-
ConstantRange NewR = L.unionWith(
437-
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true));
438-
return markConstantRange(
439-
std::move(NewR),
440-
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef()));
579+
// If the constant is a vector of integers/floating point values, try to
580+
// treat it as a range.
581+
if (getConstant()->getType()->isVectorTy()) {
582+
Type *ScalarTy = getConstant()->getType()->getScalarType();
583+
if (ScalarTy->isIntegerTy()) {
584+
ConstantRange L = getConstant()->toConstantRange();
585+
ConstantRange NewR = L.unionWith(
586+
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true));
587+
return markConstantRange(
588+
std::move(NewR),
589+
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef()));
590+
}
591+
if (ScalarTy->isFloatingPointTy()) {
592+
ConstantFPRange L = getConstant()->toConstantFPRange();
593+
ConstantFPRange NewR = L.unionWith(
594+
RHS.asConstantFPRange(L.getSemantics(), /*UndefAllowed=*/true));
595+
return markConstantFPRange(
596+
std::move(NewR),
597+
Opts.setMayIncludeUndef(RHS.isConstantFPRangeIncludingUndef()));
598+
}
441599
}
442600
markOverdefined();
443601
return true;
@@ -451,18 +609,35 @@ class ValueLatticeElement {
451609
}
452610

453611
auto OldTag = Tag;
454-
assert(isConstantRange() && "New ValueLattice type?");
455-
if (RHS.isUndef()) {
456-
Tag = constantrange_including_undef;
457-
return OldTag != Tag;
612+
if (isConstantRange()) {
613+
if (RHS.isUndef()) {
614+
Tag = constantrange_including_undef;
615+
return OldTag != Tag;
616+
}
617+
618+
const ConstantRange &L = getConstantRange();
619+
ConstantRange NewR = L.unionWith(
620+
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true));
621+
return markConstantRange(
622+
std::move(NewR),
623+
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef()));
458624
}
459625

460-
const ConstantRange &L = getConstantRange();
461-
ConstantRange NewR = L.unionWith(
462-
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true));
463-
return markConstantRange(
464-
std::move(NewR),
465-
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef()));
626+
if (isConstantFPRange()) {
627+
if (RHS.isUndef()) {
628+
Tag = constantfprange_including_undef;
629+
return OldTag != Tag;
630+
}
631+
632+
const ConstantFPRange &L = getConstantFPRange();
633+
ConstantFPRange NewR = L.unionWith(
634+
RHS.asConstantFPRange(L.getSemantics(), /*UndefAllowed=*/true));
635+
return markConstantFPRange(
636+
std::move(NewR),
637+
Opts.setMayIncludeUndef(RHS.isConstantFPRangeIncludingUndef()));
638+
} else {
639+
llvm_unreachable("New ValueLattice type?");
640+
}
466641
}
467642

468643
// Compares this symbolic value with Other using Pred and returns either
@@ -494,7 +669,7 @@ class ValueLatticeElement {
494669
void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; }
495670
};
496671

497-
static_assert(sizeof(ValueLatticeElement) <= 40,
672+
static_assert(sizeof(ValueLatticeElement) <= 64,
498673
"size of ValueLatticeElement changed unexpectedly");
499674

500675
LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,

llvm/include/llvm/IR/Constant.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
namespace llvm {
2222

2323
class ConstantRange;
24+
class ConstantFPRange;
2425
class APInt;
2526

2627
/// This is an important base class in LLVM. It provides the common facilities
@@ -160,6 +161,11 @@ class Constant : public User {
160161
/// range is the union over the element ranges. Poison elements are ignored.
161162
LLVM_ABI ConstantRange toConstantRange() const;
162163

164+
/// Convert constant to an approximate constant floating point range. For
165+
/// vectors, the range is the union over the element ranges. Poison elements
166+
/// are ignored.
167+
ConstantFPRange toConstantFPRange() const;
168+
163169
/// Called if some element of this constant is no longer valid.
164170
/// At this point only other constants may be on the use_list for this
165171
/// constant. Any constants on our Use list must also be destroy'd. The

0 commit comments

Comments
 (0)