Skip to content

Commit 4028267

Browse files
authored
Reapply [IR] Add new Range attribute using new ConstantRange Attribute type (#84617)
The only change from #83171 is the change of the allocator so the destructor is called for ConstantRangeAttributeImpl. reverts #84549
1 parent 11cd2a3 commit 4028267

19 files changed

+341
-26
lines changed

llvm/docs/LangRef.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,22 @@ Currently, only the following parameter attributes are defined:
16351635

16361636
This attribute cannot be applied to return values.
16371637

1638+
``range(<ty> <a>, <b>)``
1639+
This attribute expresses the possible range of the parameter or return value.
1640+
If the value is not in the specified range, it is converted to poison.
1641+
The arguments passed to ``range`` have the following properties:
1642+
1643+
- The type must match the scalar type of the parameter or return value.
1644+
- The pair ``a,b`` represents the range ``[a,b)``.
1645+
- Both ``a`` and ``b`` are constants.
1646+
- The range is allowed to wrap.
1647+
- The range should not represent the full or empty set. That is, ``a!=b``.
1648+
1649+
This attribute may only be applied to parameters or return values with integer
1650+
or vector of integer types.
1651+
1652+
For vector-typed parameters, the range is applied element-wise.
1653+
16381654
.. _gc:
16391655

16401656
Garbage Collector Strategy Names

llvm/include/llvm/ADT/FoldingSet.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#ifndef LLVM_ADT_FOLDINGSET_H
1717
#define LLVM_ADT_FOLDINGSET_H
1818

19+
#include "llvm/ADT/APInt.h"
1920
#include "llvm/ADT/Hashing.h"
2021
#include "llvm/ADT/STLForwardCompat.h"
2122
#include "llvm/ADT/SmallVector.h"
@@ -354,6 +355,12 @@ class FoldingSetNodeID {
354355
AddInteger(unsigned(I));
355356
AddInteger(unsigned(I >> 32));
356357
}
358+
void AddInteger(const APInt &Int) {
359+
const auto *Parts = Int.getRawData();
360+
for (int i = 0, N = Int.getNumWords(); i < N; ++i) {
361+
AddInteger(Parts[i]);
362+
}
363+
}
357364

358365
void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
359366
void AddString(StringRef String);

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ namespace llvm {
369369
bool parseFnAttributeValuePairs(AttrBuilder &B,
370370
std::vector<unsigned> &FwdRefAttrGrps,
371371
bool inAttrGrp, LocTy &BuiltinLoc);
372+
bool parseRangeAttr(AttrBuilder &B);
372373
bool parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
373374
Attribute::AttrKind AttrKind);
374375

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ enum AttributeKindCodes {
724724
ATTR_KIND_WRITABLE = 89,
725725
ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
726726
ATTR_KIND_DEAD_ON_UNWIND = 91,
727+
ATTR_KIND_RANGE = 92,
727728
};
728729

729730
enum ComdatSelectionKindCodes {

llvm/include/llvm/IR/Attributes.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class AttributeMask;
3737
class AttributeImpl;
3838
class AttributeListImpl;
3939
class AttributeSetNode;
40+
class ConstantRange;
4041
class FoldingSetNodeID;
4142
class Function;
4243
class LLVMContext;
@@ -103,6 +104,9 @@ class Attribute {
103104
static bool isTypeAttrKind(AttrKind Kind) {
104105
return Kind >= FirstTypeAttr && Kind <= LastTypeAttr;
105106
}
107+
static bool isConstantRangeAttrKind(AttrKind Kind) {
108+
return Kind >= FirstConstantRangeAttr && Kind <= LastConstantRangeAttr;
109+
}
106110

107111
static bool canUseAsFnAttr(AttrKind Kind);
108112
static bool canUseAsParamAttr(AttrKind Kind);
@@ -125,6 +129,8 @@ class Attribute {
125129
static Attribute get(LLVMContext &Context, StringRef Kind,
126130
StringRef Val = StringRef());
127131
static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
132+
static Attribute get(LLVMContext &Context, AttrKind Kind,
133+
const ConstantRange &CR);
128134

129135
/// Return a uniquified Attribute object that has the specific
130136
/// alignment set.
@@ -180,6 +186,9 @@ class Attribute {
180186
/// Return true if the attribute is a type attribute.
181187
bool isTypeAttribute() const;
182188

189+
/// Return true if the attribute is a ConstantRange attribute.
190+
bool isConstantRangeAttribute() const;
191+
183192
/// Return true if the attribute is any kind of attribute.
184193
bool isValid() const { return pImpl; }
185194

@@ -213,6 +222,10 @@ class Attribute {
213222
/// a type attribute.
214223
Type *getValueAsType() const;
215224

225+
/// Return the attribute's value as a ConstantRange. This requires the
226+
/// attribute to be a ConstantRange attribute.
227+
ConstantRange getValueAsConstantRange() const;
228+
216229
/// Returns the alignment field of an attribute as a byte alignment
217230
/// value.
218231
MaybeAlign getAlignment() const;
@@ -251,6 +264,9 @@ class Attribute {
251264
/// Return the FPClassTest for nofpclass
252265
FPClassTest getNoFPClass() const;
253266

267+
/// Returns the value of the range attribute.
268+
ConstantRange getRange() const;
269+
254270
/// The Attribute is converted to a string of equivalent mnemonic. This
255271
/// is, presumably, for writing out the mnemonics for the assembly writer.
256272
std::string getAsString(bool InAttrGrp = false) const;
@@ -1189,6 +1205,13 @@ class AttrBuilder {
11891205
// Add nofpclass attribute
11901206
AttrBuilder &addNoFPClassAttr(FPClassTest NoFPClassMask);
11911207

1208+
/// Add a ConstantRange attribute with the given range.
1209+
AttrBuilder &addConstantRangeAttr(Attribute::AttrKind Kind,
1210+
const ConstantRange &CR);
1211+
1212+
/// Add range attribute.
1213+
AttrBuilder &addRangeAttr(const ConstantRange &CR);
1214+
11921215
ArrayRef<Attribute> attrs() const { return Attrs; }
11931216

11941217
bool operator==(const AttrBuilder &B) const;

llvm/include/llvm/IR/Attributes.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class StrBoolAttr<string S> : Attr<S, []>;
4444
/// Arbitrary string attribute.
4545
class ComplexStrAttr<string S, list<AttrProperty> P> : Attr<S, P>;
4646

47+
/// ConstantRange attribute.
48+
class ConstantRangeAttr<string S, list<AttrProperty> P> : Attr<S, P>;
49+
4750
/// Target-independent enum attributes.
4851

4952
/// Alignment of parameter (5 bits) stored as log2 of alignment with +1 bias.
@@ -218,6 +221,9 @@ def OptimizeNone : EnumAttr<"optnone", [FnAttr]>;
218221
/// Similar to byval but without a copy.
219222
def Preallocated : TypeAttr<"preallocated", [FnAttr, ParamAttr]>;
220223

224+
/// Parameter or return value is within the specified range.
225+
def Range : ConstantRangeAttr<"range", [ParamAttr, RetAttr]>;
226+
221227
/// Function does not access memory.
222228
def ReadNone : EnumAttr<"readnone", [ParamAttr]>;
223229

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
15961596

15971597
return true;
15981598
}
1599+
case Attribute::Range:
1600+
return parseRangeAttr(B);
15991601
default:
16001602
B.addAttribute(Attr);
16011603
Lex.Lex();
@@ -3008,6 +3010,47 @@ bool LLParser::parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
30083010
return false;
30093011
}
30103012

3013+
/// parseRangeAttr
3014+
/// ::= range(<ty> <n>,<n>)
3015+
bool LLParser::parseRangeAttr(AttrBuilder &B) {
3016+
Lex.Lex();
3017+
3018+
APInt Lower;
3019+
APInt Upper;
3020+
Type *Ty = nullptr;
3021+
LocTy TyLoc;
3022+
3023+
auto ParseAPSInt = [&](unsigned BitWidth, APInt &Val) {
3024+
if (Lex.getKind() != lltok::APSInt)
3025+
return tokError("expected integer");
3026+
if (Lex.getAPSIntVal().getBitWidth() > BitWidth)
3027+
return tokError(
3028+
"integer is too large for the bit width of specified type");
3029+
Val = Lex.getAPSIntVal().extend(BitWidth);
3030+
Lex.Lex();
3031+
return false;
3032+
};
3033+
3034+
if (parseToken(lltok::lparen, "expected '('") || parseType(Ty, TyLoc))
3035+
return true;
3036+
if (!Ty->isIntegerTy())
3037+
return error(TyLoc, "the range must have integer type!");
3038+
3039+
unsigned BitWidth = Ty->getPrimitiveSizeInBits();
3040+
3041+
if (ParseAPSInt(BitWidth, Lower) ||
3042+
parseToken(lltok::comma, "expected ','") || ParseAPSInt(BitWidth, Upper))
3043+
return true;
3044+
if (Lower == Upper)
3045+
return tokError("the range should not represent the full or empty set!");
3046+
3047+
if (parseToken(lltok::rparen, "expected ')'"))
3048+
return true;
3049+
3050+
B.addRangeAttr(ConstantRange(Lower, Upper));
3051+
return false;
3052+
}
3053+
30113054
/// parseOptionalOperandBundles
30123055
/// ::= /*empty*/
30133056
/// ::= '[' OperandBundle [, OperandBundle ]* ']'

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,30 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
815815
return getFnValueByID(ValNo, Ty, TyID, ConstExprInsertBB);
816816
}
817817

818+
Expected<ConstantRange> readConstantRange(ArrayRef<uint64_t> Record,
819+
unsigned &OpNum) {
820+
if (Record.size() - OpNum < 3)
821+
return error("Too few records for range");
822+
unsigned BitWidth = Record[OpNum++];
823+
if (BitWidth > 64) {
824+
unsigned LowerActiveWords = Record[OpNum];
825+
unsigned UpperActiveWords = Record[OpNum++] >> 32;
826+
if (Record.size() - OpNum < LowerActiveWords + UpperActiveWords)
827+
return error("Too few records for range");
828+
APInt Lower =
829+
readWideAPInt(ArrayRef(&Record[OpNum], LowerActiveWords), BitWidth);
830+
OpNum += LowerActiveWords;
831+
APInt Upper =
832+
readWideAPInt(ArrayRef(&Record[OpNum], UpperActiveWords), BitWidth);
833+
OpNum += UpperActiveWords;
834+
return ConstantRange(Lower, Upper);
835+
} else {
836+
int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[OpNum++]);
837+
int64_t End = BitcodeReader::decodeSignRotatedValue(Record[OpNum++]);
838+
return ConstantRange(APInt(BitWidth, Start), APInt(BitWidth, End));
839+
}
840+
}
841+
818842
/// Upgrades old-style typeless byval/sret/inalloca attributes by adding the
819843
/// corresponding argument's pointee type. Also upgrades intrinsics that now
820844
/// require an elementtype attribute.
@@ -2103,6 +2127,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
21032127
return Attribute::CoroDestroyOnlyWhenComplete;
21042128
case bitc::ATTR_KIND_DEAD_ON_UNWIND:
21052129
return Attribute::DeadOnUnwind;
2130+
case bitc::ATTR_KIND_RANGE:
2131+
return Attribute::Range;
21062132
}
21072133
}
21082134

@@ -2272,6 +2298,21 @@ Error BitcodeReader::parseAttributeGroupBlock() {
22722298
return error("Not a type attribute");
22732299

22742300
B.addTypeAttr(Kind, HasType ? getTypeByID(Record[++i]) : nullptr);
2301+
} else if (Record[i] == 7) {
2302+
Attribute::AttrKind Kind;
2303+
2304+
i++;
2305+
if (Error Err = parseAttrKind(Record[i++], &Kind))
2306+
return Err;
2307+
if (!Attribute::isConstantRangeAttrKind(Kind))
2308+
return error("Not a ConstantRange attribute");
2309+
2310+
Expected<ConstantRange> MaybeCR = readConstantRange(Record, i);
2311+
if (!MaybeCR)
2312+
return MaybeCR.takeError();
2313+
i--;
2314+
2315+
B.addConstantRangeAttr(Kind, MaybeCR.get());
22752316
} else {
22762317
return error("Invalid attribute group entry");
22772318
}

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
844844
return bitc::ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE;
845845
case Attribute::DeadOnUnwind:
846846
return bitc::ATTR_KIND_DEAD_ON_UNWIND;
847+
case Attribute::Range:
848+
return bitc::ATTR_KIND_RANGE;
847849
case Attribute::EndAttrKinds:
848850
llvm_unreachable("Can not encode end-attribute kinds marker.");
849851
case Attribute::None:
@@ -856,6 +858,39 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
856858
llvm_unreachable("Trying to encode unknown attribute");
857859
}
858860

861+
static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
862+
if ((int64_t)V >= 0)
863+
Vals.push_back(V << 1);
864+
else
865+
Vals.push_back((-V << 1) | 1);
866+
}
867+
868+
static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A) {
869+
// We have an arbitrary precision integer value to write whose
870+
// bit width is > 64. However, in canonical unsigned integer
871+
// format it is likely that the high bits are going to be zero.
872+
// So, we only write the number of active words.
873+
unsigned NumWords = A.getActiveWords();
874+
const uint64_t *RawData = A.getRawData();
875+
for (unsigned i = 0; i < NumWords; i++)
876+
emitSignedInt64(Vals, RawData[i]);
877+
}
878+
879+
static void emitConstantRange(SmallVectorImpl<uint64_t> &Record,
880+
const ConstantRange &CR) {
881+
unsigned BitWidth = CR.getBitWidth();
882+
Record.push_back(BitWidth);
883+
if (BitWidth > 64) {
884+
Record.push_back(CR.getLower().getActiveWords() |
885+
(uint64_t(CR.getUpper().getActiveWords()) << 32));
886+
emitWideAPInt(Record, CR.getLower());
887+
emitWideAPInt(Record, CR.getUpper());
888+
} else {
889+
emitSignedInt64(Record, CR.getLower().getSExtValue());
890+
emitSignedInt64(Record, CR.getUpper().getSExtValue());
891+
}
892+
}
893+
859894
void ModuleBitcodeWriter::writeAttributeGroupTable() {
860895
const std::vector<ValueEnumerator::IndexAndAttrSet> &AttrGrps =
861896
VE.getAttributeGroups();
@@ -889,13 +924,17 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
889924
Record.append(Val.begin(), Val.end());
890925
Record.push_back(0);
891926
}
892-
} else {
893-
assert(Attr.isTypeAttribute());
927+
} else if (Attr.isTypeAttribute()) {
894928
Type *Ty = Attr.getValueAsType();
895929
Record.push_back(Ty ? 6 : 5);
896930
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
897931
if (Ty)
898932
Record.push_back(VE.getTypeID(Attr.getValueAsType()));
933+
} else {
934+
assert(Attr.isConstantRangeAttribute());
935+
Record.push_back(7);
936+
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
937+
emitConstantRange(Record, Attr.getValueAsConstantRange());
899938
}
900939
}
901940

@@ -1716,24 +1755,6 @@ void ModuleBitcodeWriter::writeDIGenericSubrange(
17161755
Record.clear();
17171756
}
17181757

1719-
static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
1720-
if ((int64_t)V >= 0)
1721-
Vals.push_back(V << 1);
1722-
else
1723-
Vals.push_back((-V << 1) | 1);
1724-
}
1725-
1726-
static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A) {
1727-
// We have an arbitrary precision integer value to write whose
1728-
// bit width is > 64. However, in canonical unsigned integer
1729-
// format it is likely that the high bits are going to be zero.
1730-
// So, we only write the number of active words.
1731-
unsigned NumWords = A.getActiveWords();
1732-
const uint64_t *RawData = A.getRawData();
1733-
for (unsigned i = 0; i < NumWords; i++)
1734-
emitSignedInt64(Vals, RawData[i]);
1735-
}
1736-
17371758
void ModuleBitcodeWriter::writeDIEnumerator(const DIEnumerator *N,
17381759
SmallVectorImpl<uint64_t> &Record,
17391760
unsigned Abbrev) {

0 commit comments

Comments
 (0)