Skip to content

Commit 3c8ef54

Browse files
committed
[IR] Add new Range attribute using new ConstantRange Attribute type
1 parent 12df1cf commit 3c8ef54

File tree

17 files changed

+321
-26
lines changed

17 files changed

+321
-26
lines changed

llvm/docs/LangRef.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,24 @@ Currently, only the following parameter attributes are defined:
16341634

16351635
This attribute cannot be applied to return values.
16361636

1637+
``range(<ty>,<a>,<b>)``
1638+
This attribute expresses the possible range the parameter is in. If the
1639+
value of the parameter is not in the specified range, a poison value is
1640+
returned instead.
1641+
The argument passed to ``range`` has the following properties:
1642+
1643+
- The type must match the scalar type of the parameter.
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,
1648+
``a!=b``.
1649+
1650+
This attribute may only be applied to parameters with integer or vector of
1651+
integer types.
1652+
1653+
For vector-typed parameters, the range is applied element-wise.
1654+
16371655
.. _gc:
16381656

16391657
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(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
@@ -366,6 +366,7 @@ namespace llvm {
366366
bool parseFnAttributeValuePairs(AttrBuilder &B,
367367
std::vector<unsigned> &FwdRefAttrGrps,
368368
bool inAttrGrp, LocTy &BuiltinLoc);
369+
bool parseRangeAttr(AttrBuilder &B);
369370
bool parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
370371
Attribute::AttrKind AttrKind);
371372

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+
/// Function does not access memory.
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: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,9 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
15851585

15861586
return true;
15871587
}
1588+
case Attribute::Range: {
1589+
return parseRangeAttr(B);
1590+
}
15881591
default:
15891592
B.addAttribute(Attr);
15901593
Lex.Lex();
@@ -2997,6 +3000,53 @@ bool LLParser::parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
29973000
return false;
29983001
}
29993002

3003+
/// parseRangeAttr
3004+
/// ::= range(<ty>,<n>,<n>)
3005+
bool LLParser::parseRangeAttr(AttrBuilder &B) {
3006+
Lex.Lex();
3007+
3008+
APInt Lower;
3009+
APInt Upper;
3010+
Type *Ty = nullptr;
3011+
LocTy TyLoc;
3012+
3013+
auto ParseAPSInt = [&](llvm::TypeSize BitWidth, APInt &Val) {
3014+
if (Lex.getKind() != lltok::APSInt)
3015+
return tokError("expected integer");
3016+
if (Lex.getAPSIntVal().getBitWidth() > BitWidth)
3017+
return tokError("integer is to large for the BitWidth");
3018+
Val = Lex.getAPSIntVal().extend(BitWidth);
3019+
Lex.Lex();
3020+
return false;
3021+
};
3022+
3023+
if (!EatIfPresent(lltok::lparen))
3024+
return tokError("expected '('");
3025+
if (parseType(Ty, TyLoc))
3026+
return true;
3027+
if (!Ty->isIntegerTy())
3028+
return error(TyLoc, "must have integer type");
3029+
3030+
auto BitWidth = Ty->getPrimitiveSizeInBits();
3031+
3032+
if (!EatIfPresent(lltok::comma))
3033+
return tokError("expected ','");
3034+
if (ParseAPSInt(BitWidth, Lower))
3035+
return true;
3036+
if (!EatIfPresent(lltok::comma))
3037+
return tokError("expected ','");
3038+
if (ParseAPSInt(BitWidth, Upper))
3039+
return true;
3040+
if (Lower == Upper)
3041+
return tokError("The range should not represent the full or empty set!");
3042+
3043+
if (!EatIfPresent(lltok::rparen))
3044+
return tokError("expected ')'");
3045+
3046+
B.addRangeAttr(ConstantRange(Lower, Upper));
3047+
return false;
3048+
}
3049+
30003050
/// parseOptionalOperandBundles
30013051
/// ::= /*empty*/
30023052
/// ::= '[' OperandBundle [, OperandBundle ]* ']'

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,6 +2103,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
21032103
return Attribute::CoroDestroyOnlyWhenComplete;
21042104
case bitc::ATTR_KIND_DEAD_ON_UNWIND:
21052105
return Attribute::DeadOnUnwind;
2106+
case bitc::ATTR_KIND_RANGE:
2107+
return Attribute::Range;
21062108
}
21072109
}
21082110

@@ -2272,6 +2274,34 @@ Error BitcodeReader::parseAttributeGroupBlock() {
22722274
return error("Not a type attribute");
22732275

22742276
B.addTypeAttr(Kind, HasType ? getTypeByID(Record[++i]) : nullptr);
2277+
} else if (Record[i] == 7 || Record[i] == 8) {
2278+
bool WideAPInt = Record[i++] == 8;
2279+
Attribute::AttrKind Kind;
2280+
if (Error Err = parseAttrKind(Record[i++], &Kind))
2281+
return Err;
2282+
if (!Attribute::isConstantRangeAttrKind(Kind))
2283+
return error("Not a ConstantRange attribute");
2284+
2285+
unsigned ValueBitWidth = Record[i++];
2286+
unsigned ActiveWords = 1;
2287+
if (WideAPInt)
2288+
ActiveWords = Record[i++];
2289+
APInt Lower =
2290+
readWideAPInt(ArrayRef(&Record[i], ActiveWords), ValueBitWidth);
2291+
i += ActiveWords;
2292+
ActiveWords = 1;
2293+
if (WideAPInt)
2294+
ActiveWords = Record[i++];
2295+
APInt Upper =
2296+
readWideAPInt(ArrayRef(&Record[i], ActiveWords), ValueBitWidth);
2297+
i += ActiveWords - 1;
2298+
2299+
if (Lower == Upper)
2300+
return error(
2301+
"The range should not represent the full or empty set!");
2302+
2303+
ConstantRange Range(Lower, Upper);
2304+
B.addConstantRangeAttr(Kind, Range);
22752305
} else {
22762306
return error("Invalid attribute group entry");
22772307
}

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 39 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,24 @@ 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+
859879
void ModuleBitcodeWriter::writeAttributeGroupTable() {
860880
const std::vector<ValueEnumerator::IndexAndAttrSet> &AttrGrps =
861881
VE.getAttributeGroups();
@@ -889,13 +909,30 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
889909
Record.append(Val.begin(), Val.end());
890910
Record.push_back(0);
891911
}
892-
} else {
893-
assert(Attr.isTypeAttribute());
912+
} else if (Attr.isTypeAttribute()) {
894913
Type *Ty = Attr.getValueAsType();
895914
Record.push_back(Ty ? 6 : 5);
896915
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
897916
if (Ty)
898917
Record.push_back(VE.getTypeID(Attr.getValueAsType()));
918+
} else {
919+
assert(Attr.isConstantRangeAttribute());
920+
ConstantRange Range = Attr.getValueAsConstantRange();
921+
bool WideAPInt = Range.getBitWidth() > 64;
922+
Record.push_back(WideAPInt ? 8 : 7);
923+
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
924+
Record.push_back(Range.getBitWidth());
925+
if (WideAPInt) {
926+
const APInt &Lower = Range.getLower();
927+
Record.push_back(Lower.getActiveWords());
928+
emitWideAPInt(Record, Lower);
929+
const APInt &Upper = Range.getUpper();
930+
Record.push_back(Upper.getActiveWords());
931+
emitWideAPInt(Record, Upper);
932+
} else {
933+
emitSignedInt64(Record, *Range.getLower().getRawData());
934+
emitSignedInt64(Record, *Range.getUpper().getRawData());
935+
}
899936
}
900937
}
901938

@@ -1716,24 +1753,6 @@ void ModuleBitcodeWriter::writeDIGenericSubrange(
17161753
Record.clear();
17171754
}
17181755

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-
17371756
void ModuleBitcodeWriter::writeDIEnumerator(const DIEnumerator *N,
17381757
SmallVectorImpl<uint64_t> &Record,
17391758
unsigned Abbrev) {

0 commit comments

Comments
 (0)