Skip to content

Commit 7fbe3cf

Browse files
nikicSvyatoslavScherbina
authored andcommitted
[IR] Add support for memory attribute
This implements IR and bitcode support for the memory attribute, as specified in https://reviews.llvm.org/D135597. The new attribute is not used for anything yet (and as such, the old memory attributes are unaffected). Differential Revision: https://reviews.llvm.org/D135592 (cherry picked from commit e9754f0)
1 parent 31cf38b commit 7fbe3cf

File tree

14 files changed

+311
-5
lines changed

14 files changed

+311
-5
lines changed

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace llvm {
4242
class Comdat;
4343
class MDString;
4444
class MDNode;
45+
class MemoryEffects;
4546
struct SlotMapping;
4647

4748
/// ValID - Represents a reference of a definition of some sort with no type.
@@ -284,6 +285,7 @@ namespace llvm {
284285
bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
285286
bool parseOptionalUWTableKind(UWTableKind &Kind);
286287
bool parseAllocKind(AllocFnKind &Kind);
288+
Optional<MemoryEffects> parseMemoryAttr();
287289
bool parseScopeAndOrdering(bool IsAtomic, SyncScope::ID &SSID,
288290
AtomicOrdering &Ordering);
289291
bool parseScope(SyncScope::ID &SSID);

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ enum Kind {
183183
kw_##DISPLAY_NAME,
184184
#include "llvm/IR/Attributes.inc"
185185

186+
// Memory attribute:
187+
kw_read,
188+
kw_write,
189+
kw_readwrite,
190+
kw_argmem,
191+
kw_inaccessiblemem,
192+
186193
kw_type,
187194
kw_opaque,
188195

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ enum AttributeKindCodes {
690690
ATTR_KIND_PRESPLIT_COROUTINE = 83,
691691
ATTR_KIND_FNRETTHUNK_EXTERN = 84,
692692
ATTR_KIND_SKIP_PROFILE = 85,
693+
ATTR_KIND_MEMORY = 86,
693694
};
694695

695696
enum ComdatSelectionKindCodes {

llvm/include/llvm/IR/Attributes.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class AttributeSetNode;
4242
class FoldingSetNodeID;
4343
class Function;
4444
class LLVMContext;
45+
class MemoryEffects;
4546
class Type;
4647

4748
enum class AllocFnKind : uint64_t {
@@ -243,6 +244,9 @@ class Attribute {
243244
// Returns the allocator function kind.
244245
AllocFnKind getAllocKind() const;
245246

247+
/// Returns memory effects.
248+
MemoryEffects getMemoryEffects() const;
249+
246250
/// The Attribute is converted to a string of equivalent mnemonic. This
247251
/// is, presumably, for writing out the mnemonics for the assembly writer.
248252
std::string getAsString(bool InAttrGrp = false) const;
@@ -1220,6 +1224,9 @@ class AttrBuilder {
12201224
// This turns the allocator kind into the form used internally in Attribute.
12211225
AttrBuilder &addAllocKindAttr(AllocFnKind Kind);
12221226

1227+
/// Add memory effect attribute.
1228+
AttrBuilder &addMemoryAttr(MemoryEffects ME);
1229+
12231230
ArrayRef<Attribute> attrs() const { return Attrs; }
12241231

12251232
bool operator==(const AttrBuilder &B) const;

llvm/include/llvm/IR/Attributes.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ def InReg : EnumAttr<"inreg", [ParamAttr, RetAttr]>;
126126
/// Build jump-instruction tables and replace refs.
127127
def JumpTable : EnumAttr<"jumptable", [FnAttr]>;
128128

129+
/// Memory effects of the function.
130+
def Memory : IntAttr<"memory", [FnAttr]>;
131+
129132
/// Function must be optimized for size first.
130133
def MinSize : EnumAttr<"minsize", [FnAttr]>;
131134

llvm/include/llvm/IR/ModRef.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,6 @@ class MemoryEffects {
8282
return (uint32_t)Loc * BitsPerLoc;
8383
}
8484

85-
static auto locations() {
86-
return enum_seq_inclusive(Location::ArgMem, Location::Other,
87-
force_iteration_on_noniterable_enum);
88-
}
89-
9085
MemoryEffects(uint32_t Data) : Data(Data) {}
9186

9287
void setModRef(Location Loc, ModRefInfo MR) {
@@ -97,6 +92,12 @@ class MemoryEffects {
9792
friend raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB);
9893

9994
public:
95+
/// Returns iterator over all supported location kinds.
96+
static auto locations() {
97+
return enum_seq_inclusive(Location::ArgMem, Location::Other,
98+
force_iteration_on_noniterable_enum);
99+
}
100+
100101
/// Create MemoryEffects that can access only the given location with the
101102
/// given ModRefInfo.
102103
MemoryEffects(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); }
@@ -147,6 +148,18 @@ class MemoryEffects {
147148
return FRMB;
148149
}
149150

151+
/// Create MemoryEffects from an encoded integer value (used by memory
152+
/// attribute).
153+
static MemoryEffects createFromIntValue(uint32_t Data) {
154+
return MemoryEffects(Data);
155+
}
156+
157+
/// Convert MemoryEffects into an encoded integer value (used by memory
158+
/// attribute).
159+
uint32_t toIntValue() const {
160+
return Data;
161+
}
162+
150163
/// Get ModRefInfo for the given Location.
151164
ModRefInfo getModRef(Location Loc) const {
152165
return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask);

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,12 @@ lltok::Kind LLLexer::LexIdentifier() {
644644
KEYWORD(DISPLAY_NAME);
645645
#include "llvm/IR/Attributes.inc"
646646

647+
KEYWORD(read);
648+
KEYWORD(write);
649+
KEYWORD(readwrite);
650+
KEYWORD(argmem);
651+
KEYWORD(inaccessiblemem);
652+
647653
KEYWORD(type);
648654
KEYWORD(opaque);
649655

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/ADT/APSInt.h"
1515
#include "llvm/ADT/DenseMap.h"
1616
#include "llvm/ADT/None.h"
17+
#include "llvm/ADT/ScopeExit.h"
1718
#include "llvm/ADT/STLExtras.h"
1819
#include "llvm/ADT/SmallPtrSet.h"
1920
#include "llvm/AsmParser/LLToken.h"
@@ -36,6 +37,7 @@
3637
#include "llvm/IR/Intrinsics.h"
3738
#include "llvm/IR/LLVMContext.h"
3839
#include "llvm/IR/Metadata.h"
40+
#include "llvm/IR/ModRef.h"
3941
#include "llvm/IR/Module.h"
4042
#include "llvm/IR/Operator.h"
4143
#include "llvm/IR/Value.h"
@@ -1466,6 +1468,13 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
14661468
B.addAllocKindAttr(Kind);
14671469
return false;
14681470
}
1471+
case Attribute::Memory: {
1472+
Optional<MemoryEffects> ME = parseMemoryAttr();
1473+
if (!ME)
1474+
return true;
1475+
B.addMemoryAttr(*ME);
1476+
return false;
1477+
}
14691478
default:
14701479
B.addAttribute(Attr);
14711480
Lex.Lex();
@@ -2187,6 +2196,87 @@ bool LLParser::parseAllocKind(AllocFnKind &Kind) {
21872196
return false;
21882197
}
21892198

2199+
static Optional<MemoryEffects::Location> keywordToLoc(lltok::Kind Tok) {
2200+
switch (Tok) {
2201+
case lltok::kw_argmem:
2202+
return MemoryEffects::ArgMem;
2203+
case lltok::kw_inaccessiblemem:
2204+
return MemoryEffects::InaccessibleMem;
2205+
default:
2206+
return None;
2207+
}
2208+
}
2209+
2210+
static Optional<ModRefInfo> keywordToModRef(lltok::Kind Tok) {
2211+
switch (Tok) {
2212+
case lltok::kw_none:
2213+
return ModRefInfo::NoModRef;
2214+
case lltok::kw_read:
2215+
return ModRefInfo::Ref;
2216+
case lltok::kw_write:
2217+
return ModRefInfo::Mod;
2218+
case lltok::kw_readwrite:
2219+
return ModRefInfo::ModRef;
2220+
default:
2221+
return None;
2222+
}
2223+
}
2224+
2225+
Optional<MemoryEffects> LLParser::parseMemoryAttr() {
2226+
MemoryEffects ME = MemoryEffects::none();
2227+
2228+
// We use syntax like memory(argmem: read), so the colon should not be
2229+
// interpreted as a label terminator.
2230+
Lex.setIgnoreColonInIdentifiers(true);
2231+
auto _ = make_scope_exit([&] { Lex.setIgnoreColonInIdentifiers(false); });
2232+
2233+
Lex.Lex();
2234+
if (!EatIfPresent(lltok::lparen)) {
2235+
tokError("expected '('");
2236+
return None;
2237+
}
2238+
2239+
bool SeenLoc = false;
2240+
do {
2241+
Optional<MemoryEffects::Location> Loc = keywordToLoc(Lex.getKind());
2242+
if (Loc) {
2243+
Lex.Lex();
2244+
if (!EatIfPresent(lltok::colon)) {
2245+
tokError("expected ':' after location");
2246+
return None;
2247+
}
2248+
}
2249+
2250+
Optional<ModRefInfo> MR = keywordToModRef(Lex.getKind());
2251+
if (!MR) {
2252+
if (!Loc)
2253+
tokError("expected memory location (argmem, inaccessiblemem) "
2254+
"or access kind (none, read, write, readwrite)");
2255+
else
2256+
tokError("expected access kind (none, read, write, readwrite)");
2257+
return None;
2258+
}
2259+
2260+
Lex.Lex();
2261+
if (Loc) {
2262+
SeenLoc = true;
2263+
ME = ME.getWithModRef(*Loc, *MR);
2264+
} else {
2265+
if (SeenLoc) {
2266+
tokError("default access kind must be specified first");
2267+
return None;
2268+
}
2269+
ME = MemoryEffects(*MR);
2270+
}
2271+
2272+
if (EatIfPresent(lltok::rparen))
2273+
return ME;
2274+
} while (EatIfPresent(lltok::comma));
2275+
2276+
tokError("unterminated memory attribute");
2277+
return None;
2278+
}
2279+
21902280
/// parseOptionalCommaAlign
21912281
/// ::=
21922282
/// ::= ',' align 4

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include "llvm/IR/IntrinsicsARM.h"
5656
#include "llvm/IR/LLVMContext.h"
5757
#include "llvm/IR/Metadata.h"
58+
#include "llvm/IR/ModRef.h"
5859
#include "llvm/IR/Module.h"
5960
#include "llvm/IR/ModuleSummaryIndex.h"
6061
#include "llvm/IR/Operator.h"
@@ -1880,6 +1881,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
18801881
return Attribute::InReg;
18811882
case bitc::ATTR_KIND_JUMP_TABLE:
18821883
return Attribute::JumpTable;
1884+
case bitc::ATTR_KIND_MEMORY:
1885+
return Attribute::Memory;
18831886
case bitc::ATTR_KIND_MIN_SIZE:
18841887
return Attribute::MinSize;
18851888
case bitc::ATTR_KIND_NAKED:
@@ -2124,6 +2127,8 @@ Error BitcodeReader::parseAttributeGroupBlock() {
21242127
B.addUWTableAttr(UWTableKind(Record[++i]));
21252128
else if (Kind == Attribute::AllocKind)
21262129
B.addAllocKindAttr(static_cast<AllocFnKind>(Record[++i]));
2130+
else if (Kind == Attribute::Memory)
2131+
B.addMemoryAttr(MemoryEffects::createFromIntValue(Record[++i]));
21272132
} else if (Record[i] == 3 || Record[i] == 4) { // String attribute
21282133
bool HasValue = (Record[i++] == 4);
21292134
SmallString<64> KindStr;

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
656656
return bitc::ATTR_KIND_ALLOCATED_POINTER;
657657
case Attribute::AllocKind:
658658
return bitc::ATTR_KIND_ALLOC_KIND;
659+
case Attribute::Memory:
660+
return bitc::ATTR_KIND_MEMORY;
659661
case Attribute::Naked:
660662
return bitc::ATTR_KIND_NAKED;
661663
case Attribute::Nest:

llvm/lib/IR/Attributes.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/Config/llvm-config.h"
2727
#include "llvm/IR/Function.h"
2828
#include "llvm/IR/LLVMContext.h"
29+
#include "llvm/IR/ModRef.h"
2930
#include "llvm/IR/Type.h"
3031
#include "llvm/Support/Compiler.h"
3132
#include "llvm/Support/ErrorHandling.h"
@@ -383,6 +384,26 @@ AllocFnKind Attribute::getAllocKind() const {
383384
return AllocFnKind(pImpl->getValueAsInt());
384385
}
385386

387+
MemoryEffects Attribute::getMemoryEffects() const {
388+
assert(hasAttribute(Attribute::Memory) &&
389+
"Can only call getMemoryEffects() on memory attribute");
390+
return MemoryEffects::createFromIntValue(pImpl->getValueAsInt());
391+
}
392+
393+
static const char *getModRefStr(ModRefInfo MR) {
394+
switch (MR) {
395+
case ModRefInfo::NoModRef:
396+
return "none";
397+
case ModRefInfo::Ref:
398+
return "read";
399+
case ModRefInfo::Mod:
400+
return "write";
401+
case ModRefInfo::ModRef:
402+
return "readwrite";
403+
}
404+
llvm_unreachable("Invalid ModRefInfo");
405+
}
406+
386407
std::string Attribute::getAsString(bool InAttrGrp) const {
387408
if (!pImpl) return {};
388409

@@ -474,6 +495,48 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
474495
.str();
475496
}
476497

498+
if (hasAttribute(Attribute::Memory)) {
499+
std::string Result;
500+
raw_string_ostream OS(Result);
501+
bool First = true;
502+
OS << "memory(";
503+
504+
MemoryEffects ME = getMemoryEffects();
505+
506+
// Print access kind for "other" as the default access kind. This way it
507+
// will apply to any new location kinds that get split out of "other".
508+
ModRefInfo OtherMR = ME.getModRef(MemoryEffects::Other);
509+
if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) {
510+
First = false;
511+
OS << getModRefStr(OtherMR);
512+
}
513+
514+
for (auto Loc : MemoryEffects::locations()) {
515+
ModRefInfo MR = ME.getModRef(Loc);
516+
if (MR == OtherMR)
517+
continue;
518+
519+
if (!First)
520+
OS << ", ";
521+
First = false;
522+
523+
switch (Loc) {
524+
case MemoryEffects::ArgMem:
525+
OS << "argmem: ";
526+
break;
527+
case MemoryEffects::InaccessibleMem:
528+
OS << "inaccessiblemem: ";
529+
break;
530+
case MemoryEffects::Other:
531+
llvm_unreachable("This is represented as the default access kind");
532+
}
533+
OS << getModRefStr(MR);
534+
}
535+
OS << ")";
536+
OS.flush();
537+
return Result;
538+
}
539+
477540
// Convert target-dependent attributes to strings of the form:
478541
//
479542
// "kind"
@@ -1723,6 +1786,10 @@ AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) {
17231786
return addRawIntAttr(Attribute::UWTable, uint64_t(Kind));
17241787
}
17251788

1789+
AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) {
1790+
return addRawIntAttr(Attribute::Memory, ME.toIntValue());
1791+
}
1792+
17261793
AttrBuilder &AttrBuilder::addAllocKindAttr(AllocFnKind Kind) {
17271794
return addRawIntAttr(Attribute::AllocKind, static_cast<uint64_t>(Kind));
17281795
}

llvm/lib/Transforms/Utils/CodeExtractor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
922922
case Attribute::WriteOnly:
923923
case Attribute::AllocKind:
924924
case Attribute::PresplitCoroutine:
925+
case Attribute::Memory:
925926
continue;
926927
// Those attributes should be safe to propagate to the extracted function.
927928
case Attribute::AlwaysInline:

0 commit comments

Comments
 (0)