-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[LVI][SCCP][CVP] Add basic ConstantFPRange support #111544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dtcxzyw
wants to merge
3
commits into
llvm:main
Choose a base branch
from
dtcxzyw:lvi-cfr
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
#ifndef LLVM_ANALYSIS_VALUELATTICE_H | ||
#define LLVM_ANALYSIS_VALUELATTICE_H | ||
|
||
#include "llvm/IR/ConstantFPRange.h" | ||
#include "llvm/IR/ConstantRange.h" | ||
#include "llvm/IR/Constants.h" | ||
|
||
|
@@ -38,6 +39,7 @@ class ValueLatticeElement { | |
/// Transition allowed to the following states: | ||
/// constant | ||
/// constantrange_including_undef | ||
/// constantfprange_including_undef | ||
/// overdefined | ||
undef, | ||
|
||
|
@@ -70,6 +72,21 @@ class ValueLatticeElement { | |
/// overdefined | ||
constantrange_including_undef, | ||
|
||
/// The Value falls within this range. (Used only for floating point typed | ||
/// values.) | ||
/// Transition allowed to the following states: | ||
/// constantfprange (new range must be a superset of the existing range) | ||
/// constantfprange_including_undef | ||
/// overdefined | ||
constantfprange, | ||
|
||
/// This Value falls within this range, but also may be undef. | ||
/// Merging it with other constant ranges results in | ||
/// constantfprange_including_undef. | ||
/// Transition allowed to the following states: | ||
/// overdefined | ||
constantfprange_including_undef, | ||
|
||
/// We can not precisely model the dynamic values this value might take. | ||
/// No transitions are allowed after reaching overdefined. | ||
overdefined, | ||
|
@@ -85,6 +102,7 @@ class ValueLatticeElement { | |
union { | ||
Constant *ConstVal; | ||
ConstantRange Range; | ||
ConstantFPRange FPRange; | ||
}; | ||
|
||
/// Destroy contents of lattice value, without destructing the object. | ||
|
@@ -100,6 +118,10 @@ class ValueLatticeElement { | |
case constantrange: | ||
Range.~ConstantRange(); | ||
break; | ||
case constantfprange_including_undef: | ||
case constantfprange: | ||
FPRange.~ConstantFPRange(); | ||
break; | ||
}; | ||
} | ||
|
||
|
@@ -154,6 +176,11 @@ class ValueLatticeElement { | |
new (&Range) ConstantRange(Other.Range); | ||
NumRangeExtensions = Other.NumRangeExtensions; | ||
break; | ||
case constantfprange: | ||
case constantfprange_including_undef: | ||
new (&FPRange) ConstantFPRange(Other.FPRange); | ||
NumRangeExtensions = Other.NumRangeExtensions; | ||
break; | ||
case constant: | ||
case notconstant: | ||
ConstVal = Other.ConstVal; | ||
|
@@ -173,6 +200,11 @@ class ValueLatticeElement { | |
new (&Range) ConstantRange(std::move(Other.Range)); | ||
NumRangeExtensions = Other.NumRangeExtensions; | ||
break; | ||
case constantfprange: | ||
case constantfprange_including_undef: | ||
new (&FPRange) ConstantFPRange(Other.FPRange); | ||
NumRangeExtensions = Other.NumRangeExtensions; | ||
break; | ||
case constant: | ||
case notconstant: | ||
ConstVal = Other.ConstVal; | ||
|
@@ -225,6 +257,23 @@ class ValueLatticeElement { | |
MergeOptions().setMayIncludeUndef(MayIncludeUndef)); | ||
return Res; | ||
} | ||
static ValueLatticeElement getFPRange(ConstantFPRange CR, | ||
bool MayIncludeUndef = false) { | ||
if (CR.isFullSet()) | ||
return getOverdefined(); | ||
|
||
if (CR.isEmptySet()) { | ||
ValueLatticeElement Res; | ||
if (MayIncludeUndef) | ||
Res.markUndef(); | ||
return Res; | ||
} | ||
|
||
ValueLatticeElement Res; | ||
Res.markConstantFPRange(std::move(CR), | ||
MergeOptions().setMayIncludeUndef(MayIncludeUndef)); | ||
return Res; | ||
} | ||
static ValueLatticeElement getOverdefined() { | ||
ValueLatticeElement Res; | ||
Res.markOverdefined(); | ||
|
@@ -239,6 +288,9 @@ class ValueLatticeElement { | |
bool isConstantRangeIncludingUndef() const { | ||
return Tag == constantrange_including_undef; | ||
} | ||
bool isConstantFPRangeIncludingUndef() const { | ||
return Tag == constantfprange_including_undef; | ||
} | ||
/// Returns true if this value is a constant range. Use \p UndefAllowed to | ||
/// exclude non-singleton constant ranges that may also be undef. Note that | ||
/// this function also returns true if the range may include undef, but only | ||
|
@@ -247,6 +299,16 @@ class ValueLatticeElement { | |
return Tag == constantrange || (Tag == constantrange_including_undef && | ||
(UndefAllowed || Range.isSingleElement())); | ||
} | ||
/// Returns true if this value is a constant floating point range. Use \p | ||
/// UndefAllowed to exclude non-singleton constant ranges that may also be | ||
/// undef. Note that this function also returns true if the range may include | ||
/// undef, but only contains a single element. In that case, it can be | ||
/// replaced by a constant. | ||
bool isConstantFPRange(bool UndefAllowed = true) const { | ||
return Tag == constantfprange || | ||
(Tag == constantfprange_including_undef && | ||
(UndefAllowed || FPRange.isSingleElement())); | ||
} | ||
bool isOverdefined() const { return Tag == overdefined; } | ||
|
||
Constant *getConstant() const { | ||
|
@@ -269,6 +331,17 @@ class ValueLatticeElement { | |
return Range; | ||
} | ||
|
||
/// Returns the constant floating point range for this value. Use \p | ||
/// UndefAllowed to exclude non-singleton constant ranges that may also be | ||
/// undef. Note that this function also returns a range if the range may | ||
/// include undef, but only contains a single element. In that case, it can be | ||
/// replaced by a constant. | ||
const ConstantFPRange &getConstantFPRange(bool UndefAllowed = true) const { | ||
assert(isConstantFPRange(UndefAllowed) && | ||
"Cannot get the constant-fprange of a non-constant-fprange!"); | ||
return FPRange; | ||
} | ||
|
||
std::optional<APInt> asConstantInteger() const { | ||
if (isConstant() && isa<ConstantInt>(getConstant())) { | ||
return cast<ConstantInt>(getConstant())->getValue(); | ||
|
@@ -278,6 +351,15 @@ class ValueLatticeElement { | |
return std::nullopt; | ||
} | ||
|
||
std::optional<APFloat> asConstantFP() const { | ||
if (isConstant() && isa<ConstantFP>(getConstant())) { | ||
return cast<ConstantFP>(getConstant())->getValue(); | ||
} else if (isConstantFPRange() && getConstantFPRange().isSingleElement()) { | ||
return *getConstantFPRange().getSingleElement(); | ||
} | ||
return std::nullopt; | ||
} | ||
|
||
ConstantRange asConstantRange(unsigned BW, bool UndefAllowed = false) const { | ||
if (isConstantRange(UndefAllowed)) | ||
return getConstantRange(); | ||
|
@@ -288,11 +370,28 @@ class ValueLatticeElement { | |
return ConstantRange::getFull(BW); | ||
} | ||
|
||
ConstantFPRange asConstantFPRange(const fltSemantics &Sem, | ||
bool UndefAllowed = false) const { | ||
if (isConstantFPRange(UndefAllowed)) | ||
return getConstantFPRange(); | ||
if (isConstant()) | ||
return getConstant()->toConstantFPRange(); | ||
if (isUnknown()) | ||
return ConstantFPRange::getEmpty(Sem); | ||
return ConstantFPRange::getFull(Sem); | ||
} | ||
|
||
ConstantRange asConstantRange(Type *Ty, bool UndefAllowed = false) const { | ||
assert(Ty->isIntOrIntVectorTy() && "Must be integer type"); | ||
return asConstantRange(Ty->getScalarSizeInBits(), UndefAllowed); | ||
} | ||
|
||
ConstantFPRange asConstantFPRange(Type *Ty, bool UndefAllowed = false) const { | ||
assert(Ty->isFPOrFPVectorTy() && "Must be floating point type"); | ||
return asConstantFPRange(Ty->getScalarType()->getFltSemantics(), | ||
UndefAllowed); | ||
} | ||
|
||
bool markOverdefined() { | ||
if (isOverdefined()) | ||
return false; | ||
|
@@ -394,6 +493,51 @@ class ValueLatticeElement { | |
return true; | ||
} | ||
|
||
/// Mark the object as constant floating point range with \p NewR. If the | ||
/// object is already a constant range, nothing changes if the existing range | ||
/// is equal to \p NewR and the tag. Otherwise \p NewR must be a superset of | ||
/// the existing range or the object must be undef. The tag is set to | ||
/// constant_range_including_undef if either the existing value or the new | ||
/// range may include undef. | ||
bool markConstantFPRange(ConstantFPRange NewR, | ||
MergeOptions Opts = MergeOptions()) { | ||
assert(!NewR.isEmptySet() && "should only be called for non-empty sets"); | ||
|
||
if (NewR.isFullSet()) | ||
return markOverdefined(); | ||
|
||
ValueLatticeElementTy OldTag = Tag; | ||
ValueLatticeElementTy NewTag = | ||
(isUndef() || isConstantFPRangeIncludingUndef() || Opts.MayIncludeUndef) | ||
? constantfprange_including_undef | ||
: constantfprange; | ||
if (isConstantFPRange()) { | ||
Tag = NewTag; | ||
if (getConstantFPRange() == NewR) | ||
return Tag != OldTag; | ||
|
||
// Simple form of widening. If a range is extended multiple times, go to | ||
// overdefined. | ||
if (Opts.CheckWiden && ++NumRangeExtensions > Opts.MaxWidenSteps) | ||
return markOverdefined(); | ||
|
||
assert(NewR.contains(getConstantFPRange()) && | ||
"Existing range must be a subset of NewR"); | ||
FPRange = std::move(NewR); | ||
return true; | ||
} | ||
|
||
assert(isUnknown() || isUndef() || isConstant()); | ||
assert( | ||
(!isConstant() || NewR.contains(getConstant()->toConstantFPRange())) && | ||
"Constant must be subset of new range"); | ||
|
||
NumRangeExtensions = 0; | ||
Tag = NewTag; | ||
new (&FPRange) ConstantFPRange(std::move(NewR)); | ||
return true; | ||
} | ||
|
||
/// Updates this object to approximate both this object and RHS. Returns | ||
/// true if this object has been changed. | ||
bool mergeIn(const ValueLatticeElement &RHS, | ||
|
@@ -414,6 +558,9 @@ class ValueLatticeElement { | |
if (RHS.isConstantRange()) | ||
return markConstantRange(RHS.getConstantRange(true), | ||
Opts.setMayIncludeUndef()); | ||
if (RHS.isConstantFPRange()) | ||
return markConstantFPRange(RHS.getConstantFPRange(true), | ||
Opts.setMayIncludeUndef()); | ||
return markOverdefined(); | ||
} | ||
|
||
|
@@ -428,15 +575,26 @@ class ValueLatticeElement { | |
return false; | ||
if (RHS.isUndef()) | ||
return false; | ||
// If the constant is a vector of integers, try to treat it as a range. | ||
if (getConstant()->getType()->isVectorTy() && | ||
getConstant()->getType()->getScalarType()->isIntegerTy()) { | ||
ConstantRange L = getConstant()->toConstantRange(); | ||
ConstantRange NewR = L.unionWith( | ||
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true)); | ||
return markConstantRange( | ||
std::move(NewR), | ||
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef())); | ||
// If the constant is a vector of integers/floating point values, try to | ||
// treat it as a range. | ||
if (getConstant()->getType()->isVectorTy()) { | ||
Type *ScalarTy = getConstant()->getType()->getScalarType(); | ||
if (ScalarTy->isIntegerTy()) { | ||
ConstantRange L = getConstant()->toConstantRange(); | ||
ConstantRange NewR = L.unionWith( | ||
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true)); | ||
return markConstantRange( | ||
std::move(NewR), | ||
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef())); | ||
} | ||
if (ScalarTy->isFloatingPointTy()) { | ||
ConstantFPRange L = getConstant()->toConstantFPRange(); | ||
ConstantFPRange NewR = L.unionWith( | ||
RHS.asConstantFPRange(L.getSemantics(), /*UndefAllowed=*/true)); | ||
return markConstantFPRange( | ||
std::move(NewR), | ||
Opts.setMayIncludeUndef(RHS.isConstantFPRangeIncludingUndef())); | ||
} | ||
} | ||
markOverdefined(); | ||
return true; | ||
|
@@ -450,18 +608,35 @@ class ValueLatticeElement { | |
} | ||
|
||
auto OldTag = Tag; | ||
assert(isConstantRange() && "New ValueLattice type?"); | ||
if (RHS.isUndef()) { | ||
Tag = constantrange_including_undef; | ||
return OldTag != Tag; | ||
if (isConstantRange()) { | ||
if (RHS.isUndef()) { | ||
Tag = constantrange_including_undef; | ||
return OldTag != Tag; | ||
} | ||
|
||
const ConstantRange &L = getConstantRange(); | ||
ConstantRange NewR = L.unionWith( | ||
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true)); | ||
return markConstantRange( | ||
std::move(NewR), | ||
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef())); | ||
} | ||
|
||
const ConstantRange &L = getConstantRange(); | ||
ConstantRange NewR = L.unionWith( | ||
RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true)); | ||
return markConstantRange( | ||
std::move(NewR), | ||
Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef())); | ||
if (isConstantFPRange()) { | ||
if (RHS.isUndef()) { | ||
Tag = constantfprange_including_undef; | ||
return OldTag != Tag; | ||
} | ||
|
||
const ConstantFPRange &L = getConstantFPRange(); | ||
ConstantFPRange NewR = L.unionWith( | ||
RHS.asConstantFPRange(L.getSemantics(), /*UndefAllowed=*/true)); | ||
return markConstantFPRange( | ||
std::move(NewR), | ||
Opts.setMayIncludeUndef(RHS.isConstantFPRangeIncludingUndef())); | ||
} else { | ||
llvm_unreachable("New ValueLattice type?"); | ||
} | ||
} | ||
|
||
// Compares this symbolic value with Other using Pred and returns either | ||
|
@@ -492,7 +667,7 @@ class ValueLatticeElement { | |
void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; } | ||
}; | ||
|
||
static_assert(sizeof(ValueLatticeElement) <= 40, | ||
static_assert(sizeof(ValueLatticeElement) <= 64, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks better after #111641. But I believe we can further reduce the size of |
||
"size of ValueLatticeElement changed unexpectedly"); | ||
|
||
raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val); | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.