Skip to content

Commit

Permalink
Reapply [IR] Add new Range attribute using new ConstantRange Attribut…
Browse files Browse the repository at this point in the history
…e type (#84617)

The only change from #83171 is the
change of the allocator so the destructor is called for
ConstantRangeAttributeImpl.

reverts #84549
  • Loading branch information
andjo403 committed Mar 9, 2024
1 parent 11cd2a3 commit 4028267
Show file tree
Hide file tree
Showing 19 changed files with 341 additions and 26 deletions.
16 changes: 16 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,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 @@ -369,6 +369,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 @@ -1596,6 +1596,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 @@ -3008,6 +3010,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

0 comments on commit 4028267

Please sign in to comment.