Skip to content

Commit d568c2b

Browse files
[RFC][Draft] Extend MemoryEffects to Support Target-Specific Memory Locations
This patch introduces preliminary support for additional memory locations, such as FPMR and ZA, needed to model AArch64 architectural registers as memory dependencies. Currently, these locations are not yet target-specific. The goal is to enable the compiler to express read/write effects on these resources. What This Patch Does: Adds two new memory locations: FPMR and ZA, intended to represent AArch64-specific inaccessible memory types. Current Limitations: These new locations are not yet target-specific in the type-safe sense, they are globally visible and hardcoded. There is no mechanism yet to associate a memory location with its corresponding target (e.g., AArch64 vs RISCV). No changes are made yet to bitcode serialization, parser support, or alias analysis behavior. This patch is not functionally complete — it is a structural prototype to solicit feedback on the direction and I would like some suggestion on how to proceed.
1 parent 0b78426 commit d568c2b

File tree

16 files changed

+261
-17
lines changed

16 files changed

+261
-17
lines changed

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ namespace llvm {
295295
};
296296
bool parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,
297297
bool InAttrGroup);
298+
bool parseInaccessibleMemLocation(IRMemLocation &MemLoc);
298299
bool parseOptionalParamOrReturnAttrs(AttrBuilder &B, bool IsParam);
299300
bool parseOptionalParamAttrs(AttrBuilder &B) {
300301
return parseOptionalParamOrReturnAttrs(B, true);

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,15 @@ enum Kind {
202202
kw_readwrite,
203203
kw_argmem,
204204
kw_inaccessiblemem,
205+
kw_fpmr,
206+
kw_za,
205207
kw_errnomem,
206208

207209
// Legacy attributes:
208210
kw_argmemonly,
209211
kw_inaccessiblememonly,
212+
kw_inaccessiblereadmemonly,
213+
kw_inaccessiblewritememonly,
210214
kw_inaccessiblemem_or_argmemonly,
211215
kw_nocapture,
212216

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ def IntrArgMemOnly : IntrinsicProperty;
4949
// accessible by the module being compiled. This is a weaker form of IntrNoMem.
5050
def IntrInaccessibleMemOnly : IntrinsicProperty;
5151

52+
53+
54+
class IntrinsicMemoryLocation;
55+
// This should be added in the Target, but once in IntrinsicsAArch64.td
56+
// It complains error: "Variable not defined: 'AArch64_FPMR'"
57+
def AArch64_FPMR : IntrinsicMemoryLocation;
58+
def AArch64_ZA: IntrinsicMemoryLocation;
59+
// IntrInaccessible{Read|Write}MemOnly needs to set Location
60+
class IntrInaccessibleReadMemOnly<IntrinsicMemoryLocation idx> : IntrinsicProperty{IntrinsicMemoryLocation Loc=idx;}
61+
class IntrInaccessibleWriteMemOnly<IntrinsicMemoryLocation idx> : IntrinsicProperty{IntrinsicMemoryLocation Loc=idx;}
62+
5263
// IntrInaccessibleMemOrArgMemOnly -- This intrinsic only accesses memory that
5364
// its pointer-typed arguments point to or memory that is not accessible
5465
// by the module being compiled. This is a weaker form of IntrArgMemOnly.

llvm/include/llvm/IR/IntrinsicsAArch64.td

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// This file defines all of the AARCH64-specific intrinsics.
1010
//
1111
//===----------------------------------------------------------------------===//
12-
1312
let TargetPrefix = "aarch64" in {
1413

1514
def int_aarch64_ldxr : Intrinsic<[llvm_i64_ty], [llvm_anyptr_ty],

llvm/include/llvm/Support/ModRef.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ enum class ModRefInfo : uint8_t {
5656
/// Debug print ModRefInfo.
5757
LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, ModRefInfo MR);
5858

59+
enum class InaccessibleTargetMemLocation {
60+
AARCH64_FPMR = 3,
61+
AARCH64_ZA = 4,
62+
};
63+
5964
/// The locations at which a function might access memory.
6065
enum class IRMemLocation {
6166
/// Access to memory via argument pointers.
@@ -65,7 +70,7 @@ enum class IRMemLocation {
6570
/// Errno memory.
6671
ErrnoMem = 2,
6772
/// Any other memory.
68-
Other = 3,
73+
Other = 5,
6974

7075
/// Helpers to iterate all locations in the MemoryEffectsBase class.
7176
First = ArgMem,
@@ -142,6 +147,18 @@ template <typename LocationEnum> class MemoryEffectsBase {
142147
return MemoryEffectsBase(Location::InaccessibleMem, MR);
143148
}
144149

150+
/// Create MemoryEffectsBase that can only read inaccessible memory.
151+
static MemoryEffectsBase
152+
inaccessibleReadMemOnly(Location Loc = Location::InaccessibleMem) {
153+
return MemoryEffectsBase(Loc, ModRefInfo::Ref);
154+
}
155+
156+
/// Create MemoryEffectsBase that can only write inaccessible memory.
157+
static MemoryEffectsBase
158+
inaccessibleWriteMemOnly(Location Loc = Location::InaccessibleMem) {
159+
return MemoryEffectsBase(Loc, ModRefInfo::Mod);
160+
}
161+
145162
/// Create MemoryEffectsBase that can only access errno memory.
146163
static MemoryEffectsBase errnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
147164
return MemoryEffectsBase(Location::ErrnoMem, MR);
@@ -178,6 +195,11 @@ template <typename LocationEnum> class MemoryEffectsBase {
178195
return MemoryEffectsBase(Data);
179196
}
180197

198+
bool isTargetMemLoc(IRMemLocation Loc) {
199+
return static_cast<unsigned>(Loc) >
200+
static_cast<unsigned>(Location::ErrnoMem);
201+
}
202+
181203
/// Convert MemoryEffectsBase into an encoded integer value (used by memory
182204
/// attribute).
183205
uint32_t toIntValue() const {

llvm/include/llvm/TableGen/Record.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/ADT/StringRef.h"
2626
#include "llvm/Support/Casting.h"
2727
#include "llvm/Support/ErrorHandling.h"
28+
#include "llvm/Support/ModRef.h"
2829
#include "llvm/Support/SMLoc.h"
2930
#include "llvm/Support/Timer.h"
3031
#include "llvm/Support/TrailingObjects.h"
@@ -1961,6 +1962,8 @@ class Record {
19611962
/// value is not the right type.
19621963
int64_t getValueAsInt(StringRef FieldName) const;
19631964

1965+
llvm::IRMemLocation getLocationTypeAsInt(StringRef FieldName) const;
1966+
19641967
/// This method looks up the specified field and returns its value as an Dag,
19651968
/// throwing an exception if the field does not exist or if the value is not
19661969
/// the right type.

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,10 +701,14 @@ lltok::Kind LLLexer::LexIdentifier() {
701701
KEYWORD(write);
702702
KEYWORD(readwrite);
703703
KEYWORD(argmem);
704+
KEYWORD(fpmr);
705+
KEYWORD(za);
704706
KEYWORD(inaccessiblemem);
705707
KEYWORD(errnomem);
706708
KEYWORD(argmemonly);
707709
KEYWORD(inaccessiblememonly);
710+
KEYWORD(inaccessiblewritememonly);
711+
KEYWORD(inaccessiblereadmemonly);
708712
KEYWORD(inaccessiblemem_or_argmemonly);
709713
KEYWORD(nocapture);
710714
KEYWORD(address_is_null);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,48 @@ static bool upgradeMemoryAttr(MemoryEffects &ME, lltok::Kind Kind) {
16661666
}
16671667
}
16681668

1669+
static std::optional<MemoryEffects::Location> keywordToLoc(lltok::Kind Tok) {
1670+
switch (Tok) {
1671+
case lltok::kw_argmem:
1672+
return IRMemLocation::ArgMem;
1673+
case lltok::kw_inaccessiblemem:
1674+
return IRMemLocation::InaccessibleMem;
1675+
case lltok::kw_errnomem:
1676+
return IRMemLocation::ErrnoMem;
1677+
case lltok::kw_fpmr:
1678+
return static_cast<IRMemLocation>(
1679+
llvm::InaccessibleTargetMemLocation::AARCH64_FPMR);
1680+
case lltok::kw_za:
1681+
return static_cast<IRMemLocation>(
1682+
llvm::InaccessibleTargetMemLocation::AARCH64_ZA);
1683+
default:
1684+
return std::nullopt;
1685+
}
1686+
}
1687+
1688+
bool LLParser::parseInaccessibleMemLocation(IRMemLocation &MemLoc) {
1689+
// It does not have location
1690+
if (Lex.getKind() != llvm::lltok::lparen)
1691+
return false;
1692+
1693+
Lex.Lex(); // eat '('
1694+
1695+
std::optional<IRMemLocation> LocOpt = keywordToLoc(Lex.getKind());
1696+
if (!LocOpt)
1697+
return tokError("invalid memory location keyword");
1698+
1699+
MemLoc = *LocOpt;
1700+
1701+
Lex.Lex(); // eat the keyword (e.g., 'fpmr', 'za')
1702+
1703+
if (Lex.getKind() != llvm::lltok::rparen)
1704+
return tokError("expected ')' after memory location");
1705+
1706+
Lex.Lex(); // eat ')'
1707+
1708+
return true; // success
1709+
}
1710+
16691711
/// parseFnAttributeValuePairs
16701712
/// ::= <attr> | <attr> '=' <value>
16711713
bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B,
@@ -1676,6 +1718,11 @@ bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B,
16761718
B.clear();
16771719

16781720
MemoryEffects ME = MemoryEffects::unknown();
1721+
// Memory effects can span multiple locations, so we initialize a base
1722+
// MemoryEffects object once with default state, and then incrementally
1723+
// populate or combine effects for individual locations. This avoids
1724+
// rebuilding the full Data structure on each addition.
1725+
bool FirstME = true;
16791726
while (true) {
16801727
lltok::Kind Token = Lex.getKind();
16811728
if (Token == lltok::rbrace)
@@ -1712,6 +1759,36 @@ bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B,
17121759
continue;
17131760
}
17141761

1762+
if (Token == lltok::kw_inaccessiblereadmemonly) {
1763+
Lex.Lex(); // eat the keyword
1764+
1765+
IRMemLocation MemLoc;
1766+
if (parseInaccessibleMemLocation(MemLoc)) {
1767+
if (!FirstME)
1768+
ME = ME.getWithModRef(MemLoc, ModRefInfo::Ref);
1769+
else
1770+
ME &= MemoryEffects::inaccessibleReadMemOnly(MemLoc);
1771+
} else
1772+
ME = MemoryEffects::inaccessibleReadMemOnly();
1773+
FirstME = false;
1774+
continue;
1775+
}
1776+
1777+
if (Token == lltok::kw_inaccessiblewritememonly) {
1778+
Lex.Lex(); // eat the keyword
1779+
1780+
IRMemLocation MemLoc;
1781+
if (parseInaccessibleMemLocation(MemLoc)) {
1782+
if (!FirstME)
1783+
ME = ME.getWithModRef(MemLoc, ModRefInfo::Mod);
1784+
else
1785+
ME &= MemoryEffects::inaccessibleWriteMemOnly(MemLoc);
1786+
} else
1787+
ME &= MemoryEffects::inaccessibleWriteMemOnly();
1788+
FirstME = false;
1789+
continue;
1790+
}
1791+
17151792
Attribute::AttrKind Attr = tokenToAttribute(Token);
17161793
if (Attr == Attribute::None) {
17171794
if (!InAttrGrp)
@@ -2510,19 +2587,6 @@ bool LLParser::parseAllocKind(AllocFnKind &Kind) {
25102587
return false;
25112588
}
25122589

2513-
static std::optional<MemoryEffects::Location> keywordToLoc(lltok::Kind Tok) {
2514-
switch (Tok) {
2515-
case lltok::kw_argmem:
2516-
return IRMemLocation::ArgMem;
2517-
case lltok::kw_inaccessiblemem:
2518-
return IRMemLocation::InaccessibleMem;
2519-
case lltok::kw_errnomem:
2520-
return IRMemLocation::ErrnoMem;
2521-
default:
2522-
return std::nullopt;
2523-
}
2524-
}
2525-
25262590
static std::optional<ModRefInfo> keywordToModRef(lltok::Kind Tok) {
25272591
switch (Tok) {
25282592
case lltok::kw_none:
@@ -2533,6 +2597,10 @@ static std::optional<ModRefInfo> keywordToModRef(lltok::Kind Tok) {
25332597
return ModRefInfo::Mod;
25342598
case lltok::kw_readwrite:
25352599
return ModRefInfo::ModRef;
2600+
case lltok::kw_inaccessiblewritememonly:
2601+
return ModRefInfo::Mod;
2602+
case lltok::kw_inaccessiblereadmemonly:
2603+
return ModRefInfo::Ref;
25362604
default:
25372605
return std::nullopt;
25382606
}

llvm/lib/IR/Attributes.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,10 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
640640
if (MR == OtherMR)
641641
continue;
642642

643+
// Dont want to print Target Location if NoModRef
644+
if (ME.isTargetMemLoc(Loc) && (MR == ModRefInfo::NoModRef))
645+
continue;
646+
643647
if (!First)
644648
OS << ", ";
645649
First = false;
@@ -656,6 +660,15 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
656660
break;
657661
case IRMemLocation::Other:
658662
llvm_unreachable("This is represented as the default access kind");
663+
default: {
664+
InaccessibleTargetMemLocation TargetLoc =
665+
static_cast<InaccessibleTargetMemLocation>(Loc);
666+
if (TargetLoc == InaccessibleTargetMemLocation::AARCH64_FPMR)
667+
OS << "fpmr: ";
668+
if (TargetLoc == InaccessibleTargetMemLocation::AARCH64_ZA)
669+
OS << "za: ";
670+
break;
671+
}
659672
}
660673
OS << getModRefStr(MR);
661674
}

llvm/lib/Support/ModRef.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, MemoryEffects ME) {
4949
case IRMemLocation::Other:
5050
OS << "Other: ";
5151
break;
52+
default: {
53+
InaccessibleTargetMemLocation TargetLoc =
54+
static_cast<InaccessibleTargetMemLocation>(Loc);
55+
if (TargetLoc == InaccessibleTargetMemLocation::AARCH64_FPMR)
56+
OS << "FPMR: ";
57+
if (TargetLoc == InaccessibleTargetMemLocation::AARCH64_ZA)
58+
OS << "ZA: ";
59+
break;
60+
}
5261
}
5362
OS << ME.getModRef(Loc);
5463
});

0 commit comments

Comments
 (0)