Skip to content
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

[IR] Add new Range attribute using new ConstantRange Attribute type #83171

Merged
merged 4 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,22 @@ Currently, only the following parameter attributes are defined:

This attribute cannot be applied to return values.

``range(<ty> <a>, <b>)``
This attribute expresses the possible range of the parameter or return value.
If the value is not in the specified range, it is converted to poison.
The arguments passed to ``range`` have the following properties:

- The type must match the scalar type of the parameter or return value.
- The pair ``a,b`` represents the range ``[a,b)``.
- Both ``a`` and ``b`` are constants.
- The range is allowed to wrap.
- The range should not represent the full or empty set. That is, ``a!=b``.

This attribute may only be applied to parameters or return values with integer
or vector of integer types.

For vector-typed parameters, the range is applied element-wise.

.. _gc:

Garbage Collector Strategy Names
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/ADT/FoldingSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#ifndef LLVM_ADT_FOLDINGSET_H
#define LLVM_ADT_FOLDINGSET_H

#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -354,6 +355,12 @@ class FoldingSetNodeID {
AddInteger(unsigned(I));
AddInteger(unsigned(I >> 32));
}
void AddInteger(const APInt &Int) {
const auto *Parts = Int.getRawData();
for (int i = 0, N = Int.getNumWords(); i < N; ++i) {
AddInteger(Parts[i]);
}
}

void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
void AddString(StringRef String);
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ namespace llvm {
bool parseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp, LocTy &BuiltinLoc);
bool parseRangeAttr(AttrBuilder &B);
bool parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
Attribute::AttrKind AttrKind);

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ enum AttributeKindCodes {
ATTR_KIND_WRITABLE = 89,
ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
ATTR_KIND_DEAD_ON_UNWIND = 91,
ATTR_KIND_RANGE = 92,
};

enum ComdatSelectionKindCodes {
Expand Down
23 changes: 23 additions & 0 deletions llvm/include/llvm/IR/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class AttributeMask;
class AttributeImpl;
class AttributeListImpl;
class AttributeSetNode;
class ConstantRange;
class FoldingSetNodeID;
class Function;
class LLVMContext;
Expand Down Expand Up @@ -103,6 +104,9 @@ class Attribute {
static bool isTypeAttrKind(AttrKind Kind) {
return Kind >= FirstTypeAttr && Kind <= LastTypeAttr;
}
static bool isConstantRangeAttrKind(AttrKind Kind) {
return Kind >= FirstConstantRangeAttr && Kind <= LastConstantRangeAttr;
}

static bool canUseAsFnAttr(AttrKind Kind);
static bool canUseAsParamAttr(AttrKind Kind);
Expand All @@ -125,6 +129,8 @@ class Attribute {
static Attribute get(LLVMContext &Context, StringRef Kind,
StringRef Val = StringRef());
static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
static Attribute get(LLVMContext &Context, AttrKind Kind,
const ConstantRange &CR);

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

/// Return true if the attribute is a ConstantRange attribute.
bool isConstantRangeAttribute() const;

/// Return true if the attribute is any kind of attribute.
bool isValid() const { return pImpl; }

Expand Down Expand Up @@ -213,6 +222,10 @@ class Attribute {
/// a type attribute.
Type *getValueAsType() const;

/// Return the attribute's value as a ConstantRange. This requires the
/// attribute to be a ConstantRange attribute.
ConstantRange getValueAsConstantRange() const;

/// Returns the alignment field of an attribute as a byte alignment
/// value.
MaybeAlign getAlignment() const;
Expand Down Expand Up @@ -251,6 +264,9 @@ class Attribute {
/// Return the FPClassTest for nofpclass
FPClassTest getNoFPClass() const;

/// Returns the value of the range attribute.
ConstantRange getRange() const;

/// The Attribute is converted to a string of equivalent mnemonic. This
/// is, presumably, for writing out the mnemonics for the assembly writer.
std::string getAsString(bool InAttrGrp = false) const;
Expand Down Expand Up @@ -1189,6 +1205,13 @@ class AttrBuilder {
// Add nofpclass attribute
AttrBuilder &addNoFPClassAttr(FPClassTest NoFPClassMask);

/// Add a ConstantRange attribute with the given range.
AttrBuilder &addConstantRangeAttr(Attribute::AttrKind Kind,
const ConstantRange &CR);

/// Add range attribute.
AttrBuilder &addRangeAttr(const ConstantRange &CR);

ArrayRef<Attribute> attrs() const { return Attrs; }

bool operator==(const AttrBuilder &B) const;
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class StrBoolAttr<string S> : Attr<S, []>;
/// Arbitrary string attribute.
class ComplexStrAttr<string S, list<AttrProperty> P> : Attr<S, P>;

/// ConstantRange attribute.
class ConstantRangeAttr<string S, list<AttrProperty> P> : Attr<S, P>;

/// Target-independent enum attributes.

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

/// Parameter or return value is within the specified range.
def Range : ConstantRangeAttr<"range", [ParamAttr, RetAttr]>;

/// Function does not access memory.
def ReadNone : EnumAttr<"readnone", [ParamAttr]>;

Expand Down
43 changes: 43 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,

return true;
}
case Attribute::Range:
return parseRangeAttr(B);
default:
B.addAttribute(Attr);
Lex.Lex();
Expand Down Expand Up @@ -2997,6 +2999,47 @@ bool LLParser::parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
return false;
}

/// parseRangeAttr
/// ::= range(<ty> <n>,<n>)
bool LLParser::parseRangeAttr(AttrBuilder &B) {
Lex.Lex();

APInt Lower;
APInt Upper;
Type *Ty = nullptr;
LocTy TyLoc;

auto ParseAPSInt = [&](unsigned BitWidth, APInt &Val) {
if (Lex.getKind() != lltok::APSInt)
return tokError("expected integer");
if (Lex.getAPSIntVal().getBitWidth() > BitWidth)
return tokError(
"integer is too large for the bit width of specified type");
Val = Lex.getAPSIntVal().extend(BitWidth);
Lex.Lex();
return false;
};

if (parseToken(lltok::lparen, "expected '('") || parseType(Ty, TyLoc))
return true;
if (!Ty->isIntegerTy())
return error(TyLoc, "the range must have integer type!");

unsigned BitWidth = Ty->getPrimitiveSizeInBits();

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 (parseToken(lltok::rparen, "expected ')'"))
return true;

B.addRangeAttr(ConstantRange(Lower, Upper));
return false;
}

/// parseOptionalOperandBundles
/// ::= /*empty*/
/// ::= '[' OperandBundle [, OperandBundle ]* ']'
Expand Down
41 changes: 41 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,30 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
return getFnValueByID(ValNo, Ty, TyID, ConstExprInsertBB);
}

Expected<ConstantRange> readConstantRange(ArrayRef<uint64_t> Record,
unsigned &OpNum) {
if (Record.size() - OpNum < 3)
return error("Too few records for range");
unsigned BitWidth = Record[OpNum++];
if (BitWidth > 64) {
unsigned LowerActiveWords = Record[OpNum];
unsigned UpperActiveWords = Record[OpNum++] >> 32;
if (Record.size() - OpNum < LowerActiveWords + UpperActiveWords)
return error("Too few records for range");
APInt Lower =
readWideAPInt(ArrayRef(&Record[OpNum], LowerActiveWords), BitWidth);
OpNum += LowerActiveWords;
APInt Upper =
readWideAPInt(ArrayRef(&Record[OpNum], UpperActiveWords), BitWidth);
OpNum += UpperActiveWords;
return ConstantRange(Lower, Upper);
} else {
int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[OpNum++]);
int64_t End = BitcodeReader::decodeSignRotatedValue(Record[OpNum++]);
return ConstantRange(APInt(BitWidth, Start), APInt(BitWidth, End));
}
}

/// Upgrades old-style typeless byval/sret/inalloca attributes by adding the
/// corresponding argument's pointee type. Also upgrades intrinsics that now
/// require an elementtype attribute.
Expand Down Expand Up @@ -2103,6 +2127,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::CoroDestroyOnlyWhenComplete;
case bitc::ATTR_KIND_DEAD_ON_UNWIND:
return Attribute::DeadOnUnwind;
case bitc::ATTR_KIND_RANGE:
return Attribute::Range;
}
}

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

B.addTypeAttr(Kind, HasType ? getTypeByID(Record[++i]) : nullptr);
} else if (Record[i] == 7) {
Attribute::AttrKind Kind;

i++;
if (Error Err = parseAttrKind(Record[i++], &Kind))
return Err;
if (!Attribute::isConstantRangeAttrKind(Kind))
return error("Not a ConstantRange attribute");

Expected<ConstantRange> MaybeCR = readConstantRange(Record, i);
if (!MaybeCR)
return MaybeCR.takeError();
i--;

B.addConstantRangeAttr(Kind, MaybeCR.get());
} else {
return error("Invalid attribute group entry");
}
Expand Down
61 changes: 41 additions & 20 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE;
case Attribute::DeadOnUnwind:
return bitc::ATTR_KIND_DEAD_ON_UNWIND;
case Attribute::Range:
return bitc::ATTR_KIND_RANGE;
case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None:
Expand All @@ -856,6 +858,39 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
llvm_unreachable("Trying to encode unknown attribute");
}

static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
if ((int64_t)V >= 0)
Vals.push_back(V << 1);
else
Vals.push_back((-V << 1) | 1);
}

static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A) {
// We have an arbitrary precision integer value to write whose
// bit width is > 64. However, in canonical unsigned integer
// format it is likely that the high bits are going to be zero.
// So, we only write the number of active words.
unsigned NumWords = A.getActiveWords();
const uint64_t *RawData = A.getRawData();
for (unsigned i = 0; i < NumWords; i++)
emitSignedInt64(Vals, RawData[i]);
}

static void emitConstantRange(SmallVectorImpl<uint64_t> &Record,
const ConstantRange &CR) {
unsigned BitWidth = CR.getBitWidth();
Record.push_back(BitWidth);
if (BitWidth > 64) {
Record.push_back(CR.getLower().getActiveWords() |
(uint64_t(CR.getUpper().getActiveWords()) << 32));
emitWideAPInt(Record, CR.getLower());
emitWideAPInt(Record, CR.getUpper());
} else {
emitSignedInt64(Record, CR.getLower().getSExtValue());
emitSignedInt64(Record, CR.getUpper().getSExtValue());
}
}

void ModuleBitcodeWriter::writeAttributeGroupTable() {
const std::vector<ValueEnumerator::IndexAndAttrSet> &AttrGrps =
VE.getAttributeGroups();
Expand Down Expand Up @@ -889,13 +924,17 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
Record.append(Val.begin(), Val.end());
Record.push_back(0);
}
} else {
assert(Attr.isTypeAttribute());
} else if (Attr.isTypeAttribute()) {
Type *Ty = Attr.getValueAsType();
Record.push_back(Ty ? 6 : 5);
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
if (Ty)
Record.push_back(VE.getTypeID(Attr.getValueAsType()));
} else {
assert(Attr.isConstantRangeAttribute());
Record.push_back(7);
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
emitConstantRange(Record, Attr.getValueAsConstantRange());
}
}

Expand Down Expand Up @@ -1716,24 +1755,6 @@ void ModuleBitcodeWriter::writeDIGenericSubrange(
Record.clear();
}

static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
if ((int64_t)V >= 0)
Vals.push_back(V << 1);
else
Vals.push_back((-V << 1) | 1);
}

static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A) {
// We have an arbitrary precision integer value to write whose
// bit width is > 64. However, in canonical unsigned integer
// format it is likely that the high bits are going to be zero.
// So, we only write the number of active words.
unsigned NumWords = A.getActiveWords();
const uint64_t *RawData = A.getRawData();
for (unsigned i = 0; i < NumWords; i++)
emitSignedInt64(Vals, RawData[i]);
}

void ModuleBitcodeWriter::writeDIEnumerator(const DIEnumerator *N,
SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev) {
Expand Down
Loading
Loading