Skip to content

Commit 689b479

Browse files
committed
Initializes attribute support
1 parent ef2ca97 commit 689b479

File tree

24 files changed

+689
-11
lines changed

24 files changed

+689
-11
lines changed

llvm/docs/LangRef.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,26 @@ Currently, only the following parameter attributes are defined:
16211621
``readonly`` or a ``memory`` attribute that does not contain
16221622
``argmem: write``.
16231623

1624+
``initializes((Lo1, Hi1), ...)``
1625+
This attribute indicates that the function initializes the ranges of the
1626+
pointer parameter's memory, ``[%p+LoN, %p+HiN)``. Initialization of memory
1627+
means the first memory access is a non-volatile, non-atomic write. The
1628+
write must happen before the function returns. If the function unwinds,
1629+
the write may not happen.
1630+
1631+
This attribute only holds for the memory accessed via this pointer
1632+
parameter. Other arbitrary accesses to the same memory via other pointers
1633+
are allowed.
1634+
1635+
The ``writable`` or ``dereferenceable`` attribute does not imply the
1636+
``initializes`` attribute. The ``initializes`` does not imply ``writeonly``
1637+
since ``initializes`` allows reading from the pointer after writing.
1638+
1639+
This attribute is a list of constant ranges in ascending order with no
1640+
overlapping or consecutive list elements. ``LoN/HiN`` are 64-bit ints, and
1641+
negative values are allowed in case the argument points partway into
1642+
an allocation. An empty list is not allowed.
1643+
16241644
``dead_on_unwind``
16251645
At a high level, this attribute indicates that the pointer argument is dead
16261646
if the call unwinds, in the sense that the caller will not depend on the

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ namespace llvm {
373373
std::vector<unsigned> &FwdRefAttrGrps,
374374
bool inAttrGrp, LocTy &BuiltinLoc);
375375
bool parseRangeAttr(AttrBuilder &B);
376+
bool parseInitializesAttr(AttrBuilder &B);
376377
bool parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
377378
Attribute::AttrKind AttrKind);
378379

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ enum AttributeKindCodes {
744744
ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
745745
ATTR_KIND_DEAD_ON_UNWIND = 91,
746746
ATTR_KIND_RANGE = 92,
747+
ATTR_KIND_INITIALIZES = 93,
747748
};
748749

749750
enum ComdatSelectionKindCodes {

llvm/include/llvm/IR/Attributes.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class AttributeImpl;
3838
class AttributeListImpl;
3939
class AttributeSetNode;
4040
class ConstantRange;
41+
class ConstantRangeList;
4142
class FoldingSetNodeID;
4243
class Function;
4344
class LLVMContext;
@@ -107,6 +108,10 @@ class Attribute {
107108
static bool isConstantRangeAttrKind(AttrKind Kind) {
108109
return Kind >= FirstConstantRangeAttr && Kind <= LastConstantRangeAttr;
109110
}
111+
static bool isConstantRangeListAttrKind(AttrKind Kind) {
112+
return Kind >= FirstConstantRangeListAttr &&
113+
Kind <= LastConstantRangeListAttr;
114+
}
110115

111116
static bool canUseAsFnAttr(AttrKind Kind);
112117
static bool canUseAsParamAttr(AttrKind Kind);
@@ -131,6 +136,8 @@ class Attribute {
131136
static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
132137
static Attribute get(LLVMContext &Context, AttrKind Kind,
133138
const ConstantRange &CR);
139+
static Attribute get(LLVMContext &Context, AttrKind Kind,
140+
const ConstantRangeList &CRL);
134141

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

199+
/// Return true if the attribute is a ConstantRangeList attribute.
200+
bool isConstantRangeListAttribute() const;
201+
192202
/// Return true if the attribute is any kind of attribute.
193203
bool isValid() const { return pImpl; }
194204

@@ -226,6 +236,10 @@ class Attribute {
226236
/// attribute to be a ConstantRange attribute.
227237
ConstantRange getValueAsConstantRange() const;
228238

239+
/// Return the attribute's value as a ConstantRangeList. This requires the
240+
/// attribute to be a ConstantRangeList attribute.
241+
ConstantRangeList getValueAsConstantRangeList() const;
242+
229243
/// Returns the alignment field of an attribute as a byte alignment
230244
/// value.
231245
MaybeAlign getAlignment() const;
@@ -267,6 +281,9 @@ class Attribute {
267281
/// Returns the value of the range attribute.
268282
ConstantRange getRange() const;
269283

284+
/// Returns the value of the initializes attribute.
285+
ConstantRangeList getInitializes() const;
286+
270287
/// The Attribute is converted to a string of equivalent mnemonic. This
271288
/// is, presumably, for writing out the mnemonics for the assembly writer.
272289
std::string getAsString(bool InAttrGrp = false) const;
@@ -1222,6 +1239,13 @@ class AttrBuilder {
12221239
/// Add range attribute.
12231240
AttrBuilder &addRangeAttr(const ConstantRange &CR);
12241241

1242+
/// Add a ConstantRangeList attribute with the given range.
1243+
AttrBuilder &addConstantRangeListAttr(Attribute::AttrKind Kind,
1244+
const ConstantRangeList &CRL);
1245+
1246+
/// Add initializes attribute.
1247+
AttrBuilder &addInitializesAttr(const ConstantRangeList &CRL);
1248+
12251249
ArrayRef<Attribute> attrs() const { return Attrs; }
12261250

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

50+
/// ConstantRangeList attribute.
51+
class ConstantRangeListAttr<string S, list<AttrProperty> P> : Attr<S, P>;
52+
5053
/// Target-independent enum attributes.
5154

5255
/// Alignment of parameter (5 bits) stored as log2 of alignment with +1 bias.
@@ -112,6 +115,9 @@ def FnRetThunkExtern : EnumAttr<"fn_ret_thunk_extern", [FnAttr]>;
112115
/// Pass structure in an alloca.
113116
def InAlloca : TypeAttr<"inalloca", [ParamAttr]>;
114117

118+
/// Pointer argument memory is initialized.
119+
def Initializes : ConstantRangeListAttr<"initializes", [ParamAttr]>;
120+
115121
/// Source said inlining was desirable.
116122
def InlineHint : EnumAttr<"inlinehint", [FnAttr]>;
117123

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//===- ConstantRangeList.h - A list of constant range -----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Represent a list of signed ConstantRange and do NOT support wrap around the
10+
// end of the numeric range. Ranges in the list are ordered and no overlapping.
11+
// Ranges should have the same bitwidth. Each range's lower should be less than
12+
// its upper.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef LLVM_IR_CONSTANTRANGELIST_H
17+
#define LLVM_IR_CONSTANTRANGELIST_H
18+
19+
#include "llvm/ADT/APInt.h"
20+
#include "llvm/IR/ConstantRange.h"
21+
#include <cstddef>
22+
#include <cstdint>
23+
24+
namespace llvm {
25+
26+
class raw_ostream;
27+
28+
/// This class represents a list of constant ranges.
29+
class [[nodiscard]] ConstantRangeList {
30+
SmallVector<ConstantRange, 2> Ranges;
31+
32+
public:
33+
SmallVectorImpl<ConstantRange>::iterator begin() { return Ranges.begin(); }
34+
SmallVectorImpl<ConstantRange>::iterator end() { return Ranges.end(); }
35+
SmallVectorImpl<ConstantRange>::const_iterator begin() const {
36+
return Ranges.begin();
37+
}
38+
SmallVectorImpl<ConstantRange>::const_iterator end() const {
39+
return Ranges.end();
40+
}
41+
ConstantRange getRange(unsigned i) const {
42+
assert(i < Ranges.size());
43+
return Ranges[i];
44+
}
45+
46+
/// Return true if this list contains no members.
47+
bool empty() const { return Ranges.empty(); }
48+
49+
/// Get the bit width of this ConstantRangeList.
50+
uint32_t getBitWidth() const { return 64; }
51+
52+
/// Return the number of ranges in this ConstantRangeList.
53+
size_t size() const { return Ranges.size(); }
54+
55+
/// Insert a new range to Ranges and keep the list ordered.
56+
void insert(const ConstantRange &NewRange);
57+
void insert(int64_t Lower, int64_t Upper) {
58+
insert(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
59+
APInt(64, Upper, /*isSigned=*/true)));
60+
}
61+
62+
// Append a new Range to Ranges. Caller should make sure
63+
// the list is still ordered after appending.
64+
void append(const ConstantRange &Range) { Ranges.push_back(Range); }
65+
void append(int64_t Lower, int64_t Upper) {
66+
append(ConstantRange(APInt(64, Lower, /*isSigned=*/true),
67+
APInt(64, Upper, /*isSigned=*/true)));
68+
}
69+
70+
/// Return the range list that results from the union of this range
71+
/// with another range list.
72+
ConstantRangeList unionWith(const ConstantRangeList &CRL) const;
73+
74+
/// Return the range list that results from the intersection of this range
75+
/// with another range list.
76+
ConstantRangeList intersectWith(const ConstantRangeList &CRL) const;
77+
78+
/// Return true if this range list is equal to another range list.
79+
bool operator==(const ConstantRangeList &CRL) const {
80+
return Ranges == CRL.Ranges;
81+
}
82+
bool operator!=(const ConstantRangeList &CRL) const {
83+
return !operator==(CRL);
84+
}
85+
86+
/// Print out the ranges to a stream.
87+
void print(raw_ostream &OS) const;
88+
};
89+
90+
} // end namespace llvm
91+
92+
#endif // LLVM_IR_CONSTANTRANGELIST_H

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/IR/CallingConv.h"
2626
#include "llvm/IR/Comdat.h"
2727
#include "llvm/IR/ConstantRange.h"
28+
#include "llvm/IR/ConstantRangeList.h"
2829
#include "llvm/IR/Constants.h"
2930
#include "llvm/IR/DebugInfoMetadata.h"
3031
#include "llvm/IR/DerivedTypes.h"
@@ -1628,6 +1629,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
16281629
}
16291630
case Attribute::Range:
16301631
return parseRangeAttr(B);
1632+
case Attribute::Initializes:
1633+
return parseInitializesAttr(B);
16311634
default:
16321635
B.addAttribute(Attr);
16331636
Lex.Lex();
@@ -3099,6 +3102,49 @@ bool LLParser::parseRangeAttr(AttrBuilder &B) {
30993102
return false;
31003103
}
31013104

3105+
/// parseInitializesAttr
3106+
/// ::= initializes((Lo1,Hi1),(Lo2,Hi2),...)
3107+
bool LLParser::parseInitializesAttr(AttrBuilder &B) {
3108+
Lex.Lex();
3109+
3110+
auto ParseAPSInt = [&](APInt &Val) {
3111+
if (Lex.getKind() != lltok::APSInt)
3112+
return tokError("expected integer");
3113+
Val = Lex.getAPSIntVal().extend(64);
3114+
Lex.Lex();
3115+
return false;
3116+
};
3117+
3118+
if (parseToken(lltok::lparen, "expected '('"))
3119+
return true;
3120+
3121+
ConstantRangeList CRL;
3122+
// Parse each constant range.
3123+
do {
3124+
APInt Lower, Upper;
3125+
if (parseToken(lltok::lparen, "expected '('"))
3126+
return true;
3127+
3128+
if (ParseAPSInt(Lower) || parseToken(lltok::comma, "expected ','") ||
3129+
ParseAPSInt(Upper))
3130+
return true;
3131+
3132+
if (Lower == Upper)
3133+
return tokError("the range should not represent the full or empty set!");
3134+
3135+
if (parseToken(lltok::rparen, "expected ')'"))
3136+
return true;
3137+
3138+
CRL.append(ConstantRange(Lower, Upper));
3139+
} while (EatIfPresent(lltok::comma));
3140+
3141+
if (parseToken(lltok::rparen, "expected ')'"))
3142+
return true;
3143+
3144+
B.addInitializesAttr(CRL);
3145+
return false;
3146+
}
3147+
31023148
/// parseOptionalOperandBundles
31033149
/// ::= /*empty*/
31043150
/// ::= '[' OperandBundle [, OperandBundle ]* ']'

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/IR/CallingConv.h"
3131
#include "llvm/IR/Comdat.h"
3232
#include "llvm/IR/Constant.h"
33+
#include "llvm/IR/ConstantRangeList.h"
3334
#include "llvm/IR/Constants.h"
3435
#include "llvm/IR/DataLayout.h"
3536
#include "llvm/IR/DebugInfo.h"
@@ -2148,6 +2149,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
21482149
return Attribute::DeadOnUnwind;
21492150
case bitc::ATTR_KIND_RANGE:
21502151
return Attribute::Range;
2152+
case bitc::ATTR_KIND_INITIALIZES:
2153+
return Attribute::Initializes;
21512154
}
21522155
}
21532156

@@ -2332,6 +2335,22 @@ Error BitcodeReader::parseAttributeGroupBlock() {
23322335
i--;
23332336

23342337
B.addConstantRangeAttr(Kind, MaybeCR.get());
2338+
} else if (Record[i] == 8) {
2339+
Attribute::AttrKind Kind;
2340+
if (Error Err = parseAttrKind(Record[++i], &Kind))
2341+
return Err;
2342+
if (!Attribute::isConstantRangeListAttrKind(Kind))
2343+
return error("Not a constant range list attribute");
2344+
2345+
ConstantRangeList CRL;
2346+
int RangeSize = Record[++i];
2347+
assert(i + 2 * RangeSize < e);
2348+
for (int Idx = 0; Idx < RangeSize; ++Idx) {
2349+
int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[++i]);
2350+
int64_t End = BitcodeReader::decodeSignRotatedValue(Record[++i]);
2351+
CRL.append(Start, End);
2352+
}
2353+
B.addConstantRangeListAttr(Kind, CRL);
23352354
} else {
23362355
return error("Invalid attribute group entry");
23372356
}

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "llvm/IR/BasicBlock.h"
3434
#include "llvm/IR/Comdat.h"
3535
#include "llvm/IR/Constant.h"
36+
#include "llvm/IR/ConstantRangeList.h"
3637
#include "llvm/IR/Constants.h"
3738
#include "llvm/IR/DebugInfoMetadata.h"
3839
#include "llvm/IR/DebugLoc.h"
@@ -859,6 +860,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
859860
return bitc::ATTR_KIND_DEAD_ON_UNWIND;
860861
case Attribute::Range:
861862
return bitc::ATTR_KIND_RANGE;
863+
case Attribute::Initializes:
864+
return bitc::ATTR_KIND_INITIALIZES;
862865
case Attribute::EndAttrKinds:
863866
llvm_unreachable("Can not encode end-attribute kinds marker.");
864867
case Attribute::None:
@@ -943,11 +946,20 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
943946
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
944947
if (Ty)
945948
Record.push_back(VE.getTypeID(Attr.getValueAsType()));
946-
} else {
947-
assert(Attr.isConstantRangeAttribute());
949+
} else if (Attr.isConstantRangeAttribute()) {
948950
Record.push_back(7);
949951
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
950952
emitConstantRange(Record, Attr.getValueAsConstantRange());
953+
} else {
954+
assert(Attr.isConstantRangeListAttribute());
955+
Record.push_back(8);
956+
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
957+
ConstantRangeList CRL = Attr.getValueAsConstantRangeList();
958+
Record.push_back(CRL.size());
959+
for (auto &CR : CRL) {
960+
emitSignedInt64(Record, CR.getLower().getSExtValue());
961+
emitSignedInt64(Record, CR.getUpper().getSExtValue());
962+
}
951963
}
952964
}
953965

0 commit comments

Comments
 (0)