-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Allow empty range attribute and add assert for full range #100601
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
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-ir Author: Andreas Jonson (andjo403) Changesalternative to #100465 fix #99619 Full diff: https://github.com/llvm/llvm-project/pull/100601.diff 4 Files Affected:
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 5a80a072dbbd2..cefbe1d760588 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -160,6 +160,7 @@ class Attribute {
static Attribute getWithUWTableKind(LLVMContext &Context, UWTableKind Kind);
static Attribute getWithMemoryEffects(LLVMContext &Context, MemoryEffects ME);
static Attribute getWithNoFPClass(LLVMContext &Context, FPClassTest Mask);
+ static Attribute getWithRange(LLVMContext &Context, const ConstantRange &CR);
/// For a typed attribute, return the equivalent attribute with the type
/// changed to \p ReplacementTy.
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index fd4ae109b4bb8..091065cf6d55f 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2369,7 +2369,9 @@ Error BitcodeReader::parseAttributeGroupBlock() {
return MaybeCR.takeError();
i--;
- B.addConstantRangeAttr(Kind, MaybeCR.get());
+ assert(Kind == Attribute::Range &&
+ "Unhandled ConstantRangeAttribute");
+ B.addRangeAttr(MaybeCR.get());
} else if (Record[i] == 8) {
Attribute::AttrKind Kind;
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index b2fdd218e5d4b..4558e8081a67b 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -286,6 +286,13 @@ Attribute Attribute::getWithNoFPClass(LLVMContext &Context,
return get(Context, NoFPClass, ClassMask);
}
+Attribute Attribute::getWithRange(LLVMContext &Context,
+ const ConstantRange &CR) {
+ assert(!CR.isEmptySet() && "Range must not be empty!");
+ assert(!CR.isFullSet() && "Range must not be full!");
+ return get(Context, Range, CR);
+}
+
Attribute
Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
const std::optional<unsigned> &NumElemsArg) {
@@ -2024,7 +2031,7 @@ AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,
}
AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
- return addConstantRangeAttr(Attribute::Range, CR);
+ return addAttribute(Attribute::getWithRange(Ctx, CR));
}
AttrBuilder &
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 17c0bf72ef05d..f3e0ed385ae2b 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -191,11 +191,11 @@ LLVMAttributeRef LLVMCreateConstantRangeAttribute(LLVMContextRef C,
const uint64_t UpperWords[]) {
auto &Ctx = *unwrap(C);
auto AttrKind = (Attribute::AttrKind)KindID;
+ assert(AttrKind == Attribute::Range && "Unhandled ConstantRangeAttribute");
unsigned NumWords = divideCeil(NumBits, 64);
- return wrap(Attribute::get(
- Ctx, AttrKind,
- ConstantRange(APInt(NumBits, ArrayRef(LowerWords, NumWords)),
- APInt(NumBits, ArrayRef(UpperWords, NumWords)))));
+ return wrap(Attribute::getWithRange(
+ Ctx, ConstantRange(APInt(NumBits, ArrayRef(LowerWords, NumWords)),
+ APInt(NumBits, ArrayRef(UpperWords, NumWords)))));
}
LLVMAttributeRef LLVMCreateStringAttribute(LLVMContextRef C,
|
I'm wondering whether we wouldn't be better off allowing empty ranges. I'm pretty sure that patches like #100899 are going to cause failures in edge cases (where ctpop is in dead code and we infer that no values are valid). Similarly, if we have an existing range attribute and then want to add new information to it and we perform an intersection, we may end up with an empty range. In that case we'd need a special case to leave the original information alone. I think things will overall be more robust if we make empty ranges valid (it just means that the value will always be poison). |
Yes I also started to think about in how may places that needed to have that type of empty/full check to avoid asserts when I looked at that PR, I was not able to think of a case but as you say probably missed some corner case. |
I think it would be somewhat unusual to allow no-op attributes, e.g. we don't do this for some other things like dereferenceable(0) either. Instead, some key places will simply not add the attribute if it would have no effect (e.g. llvm-project/llvm/lib/IR/Attributes.cpp Lines 1932 to 1936 in bb06453
Though my main concern there would be that in textual IR it's kind of hard to distinguish empty & full range without knowing LLVM implementation details, as they are both represented using lo=hi. |
hmm so the ref shall be something like |
or keep the lang ref as is and do as AttrBuilder::addDereferenceableAttr that we only add the attribute if not empty/full |
Not sure about just silently dropping the empty case. For full, this is equivalent to not having the attribute, so that makes sense. For empty, this will result in some non-monotonic behavior. E.g. if you originally have range(0, 5) and then intersect with range(4, 10) you get range(4, 5), but if you intersect with range(5, 10) you instead keep range(0, 5). That is, inferring a better range results in worse attributes being materialized. That doesn't break anything, but it's probably still undesirable. |
Updated the langref to allow empty ranges and asserts for full range but the builder ignores full ranges |
llvm/docs/LangRef.rst
Outdated
- Only for the empty set is ``a`` and ``b`` allowed to be equal and | ||
only for the value 0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found this a bit hard to understand, maybe like this?
- Only for the empty set is ``a`` and ``b`` allowed to be equal and | |
only for the value 0. | |
- The empty range is represented using ``0,0``. | |
- Otherwise, ``a`` and ``b` are not allowed to be equal. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes much better
llvm/lib/AsmParser/LLParser.cpp
Outdated
@@ -3109,8 +3109,8 @@ bool LLParser::parseRangeAttr(AttrBuilder &B) { | |||
if (ParseAPSInt(BitWidth, Lower) || | |||
parseToken(lltok::comma, "expected ','") || ParseAPSInt(BitWidth, Upper)) | |||
return true; | |||
if (Lower == Upper) | |||
return tokError("the range should not represent the full or empty set!"); | |||
if (Lower == Upper && !Lower.isMinValue()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (Lower == Upper && !Lower.isMinValue()) | |
if (Lower == Upper && !Lower.isZero()) |
llvm/lib/IR/Attributes.cpp
Outdated
@@ -286,6 +286,12 @@ Attribute Attribute::getWithNoFPClass(LLVMContext &Context, | |||
return get(Context, NoFPClass, ClassMask); | |||
} | |||
|
|||
Attribute Attribute::getWithRange(LLVMContext &Context, | |||
const ConstantRange &CR) { | |||
assert(!CR.isFullSet() && "Range must not be full!"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be okay to just add this directly into the generic ctor, rather than specific to range
. I would expect that other range-based attributes added in the future will not allow full ranges either. (If they do, we can separate it out at the time.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes that seems resonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
alternative to #100465
fix #99619