Skip to content

Add the 'initializes' attribute langref and support #84803

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

Merged
merged 39 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2554c82
Add 'initialized' attribute langref
haopliu Mar 11, 2024
a9256bf
Update the LangRef
haopliu Mar 12, 2024
9150ece
Refactor the argument uses collecting to a function
haopliu Mar 12, 2024
206b707
Add 'initialized' attribute support and undo the FunctionAttrs refact…
haopliu Mar 14, 2024
eaf5ca0
Update the LangRef (round 2)
haopliu Mar 14, 2024
52cc649
Update FoldingSet.h
haopliu Mar 14, 2024
f7fddb0
Change the attribute type to ConstantRangeList
haopliu Apr 5, 2024
3b5955a
Rename attr to initializes
haopliu Apr 5, 2024
6a1df7a
Update CRL about accessing the range of an EmptySet/FullSet
haopliu Apr 9, 2024
fe2e0a5
Change CRL.insert to be ordered and no overlapping
haopliu Apr 12, 2024
f73df04
Optimize CRL::insert for common cases
haopliu Apr 16, 2024
63c45f6
Update ConstantRangeList
haopliu Apr 16, 2024
dcc2b38
Add unit tests for BitcodeReader/Verifier/Assembler
haopliu Apr 17, 2024
9723322
Add a space after commas
haopliu Apr 17, 2024
e70988d
Update CRL and unit tests
haopliu Apr 18, 2024
9782c31
Update CRL to merge consecutive ranges
haopliu Apr 23, 2024
a924dd3
Handle a common case in CRL::insert and add CRL::dump
haopliu Apr 23, 2024
45cdc34
Nit: change dbgs() to llvm::dbgs()
haopliu Apr 24, 2024
4eeba08
Change the attr impl to TrailingObjects<ConstantRange>
haopliu Apr 25, 2024
502e062
Update LLVMContextImpl.h
haopliu Apr 26, 2024
fac03b8
Merge branch 'llvm:main' into dse-commit
haopliu May 8, 2024
ea3e7c5
Rebase to the latest main
haopliu May 8, 2024
7630510
Change getInitializes() to return ArrayRef<ConstantRange>
haopliu May 8, 2024
a604b4f
Remove llvm::
haopliu May 8, 2024
f941b24
Update LangRef and ConstantRangeList
haopliu May 9, 2024
e52fd9d
Update BitCodeReader/Writer
haopliu May 9, 2024
8e64fa9
Encode bitwidth once for ConstantRangeList kind attr
haopliu May 9, 2024
9ae0fca
Use SpecificBumpPtrAllocator to allocate mem and make sure to call de…
haopliu May 16, 2024
d4809ab
Refactor readConstantRange and update BitcodeReader
haopliu May 17, 2024
99d36cc
Merge branch 'main' into dse-commit
haopliu May 28, 2024
96191cd
Change the attr imple back to ConstantRangeList
haopliu May 30, 2024
645f577
Add getConstantRangeList unittest
haopliu May 30, 2024
2a8ea9a
Add Bitwidth in FoldingSetNodeId
haopliu Jun 11, 2024
37edecd
Merge branch 'main' into dse-commit
haopliu Jun 11, 2024
80306d7
Clean up a redundant check in BitcodeReader
haopliu Jun 11, 2024
67445fe
Change attr impl to normal Alloc w/ a vector and call dtor for each a…
haopliu Jun 18, 2024
68643a5
nit: use uninitialized_copy in the ConstantRangeListAttributeImpl ctor
haopliu Jun 18, 2024
46e8d87
Remove redundant BitWidth in the attr Profile as APInt::Profile alrea…
haopliu Jun 20, 2024
714d02f
Use ConstantRange::contains() in ConstantRangeList::insert()
haopliu Jun 21, 2024
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
21 changes: 21 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1625,6 +1625,27 @@ Currently, only the following parameter attributes are defined:
``readonly`` or a ``memory`` attribute that does not contain
``argmem: write``.

``initializes((Lo1, Hi1), ...)``
This attribute indicates that the function initializes the ranges of the
pointer parameter's memory, ``[%p+LoN, %p+HiN)``. Initialization of memory
means the first memory access is a non-volatile, non-atomic write. The
write must happen before the function returns. If the function unwinds,
the write may not happen.

This attribute only holds for the memory accessed via this pointer
parameter. Other arbitrary accesses to the same memory via other pointers
are allowed.

The ``writable`` or ``dereferenceable`` attribute do not imply the
``initializes`` attribute. The ``initializes`` attribute does not imply
``writeonly`` since ``initializes`` allows reading from the pointer
after writing.

This attribute is a list of constant ranges in ascending order with no
overlapping or consecutive list elements. ``LoN/HiN`` are 64-bit integers,
and negative values are allowed in case the argument points partway into
an allocation. An empty list is not allowed.

``dead_on_unwind``
At a high level, this attribute indicates that the pointer argument is dead
if the call unwinds, in the sense that the caller will not depend on the
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 @@ -372,6 +372,7 @@ namespace llvm {
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp, LocTy &BuiltinLoc);
bool parseRangeAttr(AttrBuilder &B);
bool parseInitializesAttr(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 @@ -755,6 +755,7 @@ enum AttributeKindCodes {
ATTR_KIND_DEAD_ON_UNWIND = 91,
ATTR_KIND_RANGE = 92,
ATTR_KIND_SANITIZE_NUMERICAL_STABILITY = 93,
ATTR_KIND_INITIALIZES = 94,
};

enum ComdatSelectionKindCodes {
Expand Down
24 changes: 24 additions & 0 deletions llvm/include/llvm/IR/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class AttributeImpl;
class AttributeListImpl;
class AttributeSetNode;
class ConstantRange;
class ConstantRangeList;
class FoldingSetNodeID;
class Function;
class LLVMContext;
Expand Down Expand Up @@ -107,6 +108,10 @@ class Attribute {
static bool isConstantRangeAttrKind(AttrKind Kind) {
return Kind >= FirstConstantRangeAttr && Kind <= LastConstantRangeAttr;
}
static bool isConstantRangeListAttrKind(AttrKind Kind) {
return Kind >= FirstConstantRangeListAttr &&
Kind <= LastConstantRangeListAttr;
}

static bool canUseAsFnAttr(AttrKind Kind);
static bool canUseAsParamAttr(AttrKind Kind);
Expand All @@ -131,6 +136,8 @@ class Attribute {
static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
static Attribute get(LLVMContext &Context, AttrKind Kind,
const ConstantRange &CR);
static Attribute get(LLVMContext &Context, AttrKind Kind,
ArrayRef<ConstantRange> Val);

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

/// Return true if the attribute is a ConstantRangeList attribute.
bool isConstantRangeListAttribute() const;

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

Expand Down Expand Up @@ -226,6 +236,10 @@ class Attribute {
/// attribute to be a ConstantRange attribute.
const ConstantRange &getValueAsConstantRange() const;

/// Return the attribute's value as a ConstantRange array. This requires the
/// attribute to be a ConstantRangeList attribute.
ArrayRef<ConstantRange> getValueAsConstantRangeList() const;

/// Returns the alignment field of an attribute as a byte alignment
/// value.
MaybeAlign getAlignment() const;
Expand Down Expand Up @@ -267,6 +281,9 @@ class Attribute {
/// Returns the value of the range attribute.
const ConstantRange &getRange() const;

/// Returns the value of the initializes attribute.
ArrayRef<ConstantRange> getInitializes() 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 @@ -1222,6 +1239,13 @@ class AttrBuilder {
/// Add range attribute.
AttrBuilder &addRangeAttr(const ConstantRange &CR);

/// Add a ConstantRangeList attribute with the given ranges.
AttrBuilder &addConstantRangeListAttr(Attribute::AttrKind Kind,
ArrayRef<ConstantRange> Val);

/// Add initializes attribute.
AttrBuilder &addInitializesAttr(const ConstantRangeList &CRL);

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 @@ -47,6 +47,9 @@ class ComplexStrAttr<string S, list<AttrProperty> P> : Attr<S, P>;
/// ConstantRange attribute.
class ConstantRangeAttr<string S, list<AttrProperty> P> : Attr<S, P>;

/// ConstantRangeList attribute.
class ConstantRangeListAttr<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 @@ -112,6 +115,9 @@ def FnRetThunkExtern : EnumAttr<"fn_ret_thunk_extern", [FnAttr]>;
/// Pass structure in an alloca.
def InAlloca : TypeAttr<"inalloca", [ParamAttr]>;

/// Pointer argument memory is initialized.
def Initializes : ConstantRangeListAttr<"initializes", [ParamAttr]>;

/// Source said inlining was desirable.
def InlineHint : EnumAttr<"inlinehint", [FnAttr]>;

Expand Down
93 changes: 93 additions & 0 deletions llvm/include/llvm/IR/ConstantRangeList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//===- ConstantRangeList.h - A list of constant ranges ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Represent a list of signed ConstantRange and do NOT support wrap around the
// end of the numeric range. Ranges in the list are ordered and not overlapping.
// Ranges should have the same bitwidth. Each range's lower should be less than
// its upper.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_IR_CONSTANTRANGELIST_H
#define LLVM_IR_CONSTANTRANGELIST_H

#include "llvm/ADT/APInt.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/Support/Debug.h"
#include <cstddef>
#include <cstdint>

namespace llvm {

class raw_ostream;

/// This class represents a list of constant ranges.
class [[nodiscard]] ConstantRangeList {
SmallVector<ConstantRange, 2> Ranges;

public:
ConstantRangeList() = default;
ConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
assert(isOrderedRanges(RangesRef));
for (const ConstantRange &R : RangesRef) {
assert(R.getBitWidth() == getBitWidth());
Ranges.push_back(R);
}
}

// Return true if the ranges are non-overlapping and increasing.
static bool isOrderedRanges(ArrayRef<ConstantRange> RangesRef);
static std::optional<ConstantRangeList>
getConstantRangeList(ArrayRef<ConstantRange> RangesRef);

ArrayRef<ConstantRange> rangesRef() const { return Ranges; }
SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
SmallVectorImpl<ConstantRange>::const_iterator begin() const {
return Ranges.begin();
}
SmallVectorImpl<ConstantRange>::const_iterator end() const {
return Ranges.end();
}
ConstantRange getRange(unsigned i) const { return Ranges[i]; }

/// Return true if this list contains no members.
bool empty() const { return Ranges.empty(); }

/// Get the bit width of this ConstantRangeList.
uint32_t getBitWidth() const { return 64; }

/// Return the number of ranges in this ConstantRangeList.
size_t size() const { return Ranges.size(); }

/// Insert a new range to Ranges and keep the list ordered.
void insert(const ConstantRange &NewRange);
void insert(int64_t Lower, int64_t Upper) {
insert(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
APInt(64, Upper, /*isSigned=*/true)));
}

/// Return true if this range list is equal to another range list.
bool operator==(const ConstantRangeList &CRL) const {
return Ranges == CRL.Ranges;
}
bool operator!=(const ConstantRangeList &CRL) const {
return !operator==(CRL);
}

/// Print out the ranges to a stream.
void print(raw_ostream &OS) const;

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void dump() const;
#endif
};

} // end namespace llvm

#endif // LLVM_IR_CONSTANTRANGELIST_H
49 changes: 49 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Comdat.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/ConstantRangeList.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
Expand Down Expand Up @@ -1626,6 +1627,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
}
case Attribute::Range:
return parseRangeAttr(B);
case Attribute::Initializes:
return parseInitializesAttr(B);
default:
B.addAttribute(Attr);
Lex.Lex();
Expand Down Expand Up @@ -3101,6 +3104,52 @@ bool LLParser::parseRangeAttr(AttrBuilder &B) {
return false;
}

/// parseInitializesAttr
/// ::= initializes((Lo1,Hi1),(Lo2,Hi2),...)
bool LLParser::parseInitializesAttr(AttrBuilder &B) {
Lex.Lex();

auto ParseAPSInt = [&](APInt &Val) {
if (Lex.getKind() != lltok::APSInt)
return tokError("expected integer");
Val = Lex.getAPSIntVal().extend(64);
Lex.Lex();
return false;
};

if (parseToken(lltok::lparen, "expected '('"))
return true;

SmallVector<ConstantRange, 2> RangeList;
// Parse each constant range.
do {
APInt Lower, Upper;
if (parseToken(lltok::lparen, "expected '('"))
return true;

if (ParseAPSInt(Lower) || parseToken(lltok::comma, "expected ','") ||
ParseAPSInt(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;

RangeList.push_back(ConstantRange(Lower, Upper));
} while (EatIfPresent(lltok::comma));

if (parseToken(lltok::rparen, "expected ')'"))
return true;

auto CRLOrNull = ConstantRangeList::getConstantRangeList(RangeList);
if (!CRLOrNull.has_value())
return tokError("Invalid (unordered or overlapping) range list");
B.addInitializesAttr(*CRLOrNull);
return false;
}

/// parseOptionalOperandBundles
/// ::= /*empty*/
/// ::= '[' OperandBundle [, OperandBundle ]* ']'
Expand Down
49 changes: 44 additions & 5 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Comdat.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/ConstantRangeList.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
Expand Down Expand Up @@ -836,10 +837,10 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
}

Expected<ConstantRange> readConstantRange(ArrayRef<uint64_t> Record,
unsigned &OpNum) {
if (Record.size() - OpNum < 3)
unsigned &OpNum,
unsigned BitWidth) {
if (Record.size() - OpNum < 2)
return error("Too few records for range");
unsigned BitWidth = Record[OpNum++];
if (BitWidth > 64) {
unsigned LowerActiveWords = Record[OpNum];
unsigned UpperActiveWords = Record[OpNum++] >> 32;
Expand All @@ -859,6 +860,14 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
}
}

Expected<ConstantRange>
readBitWidthAndConstantRange(ArrayRef<uint64_t> Record, unsigned &OpNum) {
if (Record.size() - OpNum < 1)
return error("Too few records for range");
unsigned BitWidth = Record[OpNum++];
return readConstantRange(Record, OpNum, BitWidth);
}

/// 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 @@ -2172,6 +2181,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::DeadOnUnwind;
case bitc::ATTR_KIND_RANGE:
return Attribute::Range;
case bitc::ATTR_KIND_INITIALIZES:
return Attribute::Initializes;
}
}

Expand Down Expand Up @@ -2350,12 +2361,39 @@ Error BitcodeReader::parseAttributeGroupBlock() {
if (!Attribute::isConstantRangeAttrKind(Kind))
return error("Not a ConstantRange attribute");

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

B.addConstantRangeAttr(Kind, MaybeCR.get());
} else if (Record[i] == 8) {
Attribute::AttrKind Kind;

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

SmallVector<ConstantRange, 2> Val;
if (i + 2 > e)
return error("Too few records for constant range list");
unsigned RangeSize = Record[i++];
unsigned BitWidth = Record[i++];
for (unsigned Idx = 0; Idx < RangeSize; ++Idx) {
Expected<ConstantRange> MaybeCR =
readConstantRange(Record, i, BitWidth);
if (!MaybeCR)
return MaybeCR.takeError();
Val.push_back(MaybeCR.get());
}
i--;

if (!ConstantRangeList::isOrderedRanges(Val))
return error("Invalid (unordered or overlapping) range list");
B.addConstantRangeListAttr(Kind, Val);
} else {
return error("Invalid attribute group entry");
}
Expand Down Expand Up @@ -3370,7 +3408,8 @@ Error BitcodeReader::parseConstants() {
(void)InRangeIndex;
} else if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE) {
Flags = Record[OpNum++];
Expected<ConstantRange> MaybeInRange = readConstantRange(Record, OpNum);
Expected<ConstantRange> MaybeInRange =
readBitWidthAndConstantRange(Record, OpNum);
if (!MaybeInRange)
return MaybeInRange.takeError();
InRange = MaybeInRange.get();
Expand Down
Loading