diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h --- a/llvm/include/llvm/AsmParser/LLParser.h +++ b/llvm/include/llvm/AsmParser/LLParser.h @@ -20,6 +20,7 @@ #include "llvm/IR/FMF.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/Support/ModRef.h" #include #include @@ -42,7 +43,6 @@ class Comdat; class MDString; class MDNode; - class MemoryEffects; struct SlotMapping; /// ValID - Represents a reference of a definition of some sort with no type. diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -22,6 +22,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/ModRef.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include #include @@ -39,7 +40,6 @@ class FoldingSetNodeID; class Function; class LLVMContext; -class MemoryEffects; class Type; class raw_ostream; enum FPClassTest : unsigned; diff --git a/llvm/include/llvm/Support/ModRef.h b/llvm/include/llvm/Support/ModRef.h --- a/llvm/include/llvm/Support/ModRef.h +++ b/llvm/include/llvm/Support/ModRef.h @@ -55,22 +55,23 @@ /// Debug print ModRefInfo. raw_ostream &operator<<(raw_ostream &OS, ModRefInfo MR); -/// Summary of how a function affects memory in the program. -/// -/// Loads from constant globals are not considered memory accesses for this -/// interface. Also, functions may freely modify stack space local to their -/// invocation without having to report it through these interfaces. -class MemoryEffects { +/// The locations at which a function might access memory. +enum IRMemLocation { + /// Access to memory via argument pointers. + ArgMem = 0, + /// Memory that is inaccessible via LLVM IR. + InaccessibleMem = 1, + /// Any other memory. + Other = 2, + + /// Helpers to iterate all locations in the MemoryEffectsBase class. + First = ArgMem, + Last = Other, +}; + +template class MemoryEffectsBase { public: - /// The locations at which a function might access memory. - enum Location { - /// Access to memory via argument pointers. - ArgMem = 0, - /// Memory that is inaccessible via LLVM IR. - InaccessibleMem = 1, - /// Any other memory. - Other = 2, - }; + using Location = LocationEnum; private: uint32_t Data = 0; @@ -82,79 +83,79 @@ return (uint32_t)Loc * BitsPerLoc; } - MemoryEffects(uint32_t Data) : Data(Data) {} + MemoryEffectsBase(uint32_t Data) : Data(Data) {} void setModRef(Location Loc, ModRefInfo MR) { Data &= ~(LocMask << getLocationPos(Loc)); Data |= static_cast(MR) << getLocationPos(Loc); } - friend raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB); - public: /// Returns iterator over all supported location kinds. static auto locations() { - return enum_seq_inclusive(Location::ArgMem, Location::Other, + return enum_seq_inclusive(Location::First, Location::Last, force_iteration_on_noniterable_enum); } - /// Create MemoryEffects that can access only the given location with the + /// Create MemoryEffectsBase that can access only the given location with the /// given ModRefInfo. - MemoryEffects(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); } + MemoryEffectsBase(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); } - /// Create MemoryEffects that can access any location with the given + /// Create MemoryEffectsBase that can access any location with the given /// ModRefInfo. - explicit MemoryEffects(ModRefInfo MR) { + explicit MemoryEffectsBase(ModRefInfo MR) { for (Location Loc : locations()) setModRef(Loc, MR); } - /// Create MemoryEffects that can read and write any memory. - static MemoryEffects unknown() { - return MemoryEffects(ModRefInfo::ModRef); + /// Create MemoryEffectsBase that can read and write any memory. + static MemoryEffectsBase unknown() { + return MemoryEffectsBase(ModRefInfo::ModRef); } - /// Create MemoryEffects that cannot read or write any memory. - static MemoryEffects none() { - return MemoryEffects(ModRefInfo::NoModRef); + /// Create MemoryEffectsBase that cannot read or write any memory. + static MemoryEffectsBase none() { + return MemoryEffectsBase(ModRefInfo::NoModRef); } - /// Create MemoryEffects that can read any memory. - static MemoryEffects readOnly() { - return MemoryEffects(ModRefInfo::Ref); + /// Create MemoryEffectsBase that can read any memory. + static MemoryEffectsBase readOnly() { + return MemoryEffectsBase(ModRefInfo::Ref); } - /// Create MemoryEffects that can write any memory. - static MemoryEffects writeOnly() { - return MemoryEffects(ModRefInfo::Mod); + /// Create MemoryEffectsBase that can write any memory. + static MemoryEffectsBase writeOnly() { + return MemoryEffectsBase(ModRefInfo::Mod); } - /// Create MemoryEffects that can only access argument memory. - static MemoryEffects argMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { - return MemoryEffects(ArgMem, MR); + /// Create MemoryEffectsBase that can only access argument memory. + static MemoryEffectsBase argMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { + return MemoryEffectsBase(Location::ArgMem, MR); } - /// Create MemoryEffects that can only access inaccessible memory. - static MemoryEffects inaccessibleMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { - return MemoryEffects(InaccessibleMem, MR); + /// Create MemoryEffectsBase that can only access inaccessible memory. + static MemoryEffectsBase + inaccessibleMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { + return MemoryEffectsBase(Location::InaccessibleMem, MR); } - /// Create MemoryEffects that can only access inaccessible or argument memory. - static MemoryEffects + /// Create MemoryEffectsBase that can only access inaccessible or argument + /// memory. + static MemoryEffectsBase inaccessibleOrArgMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { - MemoryEffects FRMB = none(); - FRMB.setModRef(ArgMem, MR); - FRMB.setModRef(InaccessibleMem, MR); + MemoryEffectsBase FRMB = none(); + FRMB.setModRef(Location::ArgMem, MR); + FRMB.setModRef(Location::InaccessibleMem, MR); return FRMB; } - /// Create MemoryEffects from an encoded integer value (used by memory + /// Create MemoryEffectsBase from an encoded integer value (used by memory /// attribute). - static MemoryEffects createFromIntValue(uint32_t Data) { - return MemoryEffects(Data); + static MemoryEffectsBase createFromIntValue(uint32_t Data) { + return MemoryEffectsBase(Data); } - /// Convert MemoryEffects into an encoded integer value (used by memory + /// Convert MemoryEffectsBase into an encoded integer value (used by memory /// attribute). uint32_t toIntValue() const { return Data; @@ -165,16 +166,16 @@ return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask); } - /// Get new MemoryEffects with modified ModRefInfo for Loc. - MemoryEffects getWithModRef(Location Loc, ModRefInfo MR) const { - MemoryEffects ME = *this; + /// Get new MemoryEffectsBase with modified ModRefInfo for Loc. + MemoryEffectsBase getWithModRef(Location Loc, ModRefInfo MR) const { + MemoryEffectsBase ME = *this; ME.setModRef(Loc, MR); return ME; } - /// Get new MemoryEffects with NoModRef on the given Loc. - MemoryEffects getWithoutLoc(Location Loc) const { - MemoryEffects ME = *this; + /// Get new MemoryEffectsBase with NoModRef on the given Loc. + MemoryEffectsBase getWithoutLoc(Location Loc) const { + MemoryEffectsBase ME = *this; ME.setModRef(Loc, ModRefInfo::NoModRef); return ME; } @@ -198,58 +199,74 @@ /// Whether this function only (at most) accesses argument memory. bool onlyAccessesArgPointees() const { - return getWithoutLoc(ArgMem).doesNotAccessMemory(); + return getWithoutLoc(Location::ArgMem).doesNotAccessMemory(); } /// Whether this function may access argument memory. bool doesAccessArgPointees() const { - return isModOrRefSet(getModRef(ArgMem)); + return isModOrRefSet(getModRef(Location::ArgMem)); } /// Whether this function only (at most) accesses inaccessible memory. bool onlyAccessesInaccessibleMem() const { - return getWithoutLoc(InaccessibleMem).doesNotAccessMemory(); + return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory(); } /// Whether this function only (at most) accesses argument and inaccessible /// memory. bool onlyAccessesInaccessibleOrArgMem() const { - return isNoModRef(getModRef(Other)); + return getWithoutLoc(Location::InaccessibleMem) + .getWithoutLoc(Location::ArgMem) + .doesNotAccessMemory(); } - /// Intersect with other MemoryEffects. - MemoryEffects operator&(MemoryEffects Other) const { - return MemoryEffects(Data & Other.Data); + /// Intersect with other MemoryEffectsBase. + MemoryEffectsBase operator&(MemoryEffectsBase Other) const { + return MemoryEffectsBase(Data & Other.Data); } - /// Intersect (in-place) with other MemoryEffects. - MemoryEffects &operator&=(MemoryEffects Other) { + /// Intersect (in-place) with other MemoryEffectsBase. + MemoryEffectsBase &operator&=(MemoryEffectsBase Other) { Data &= Other.Data; return *this; } - /// Union with other MemoryEffects. - MemoryEffects operator|(MemoryEffects Other) const { - return MemoryEffects(Data | Other.Data); + /// Union with other MemoryEffectsBase. + MemoryEffectsBase operator|(MemoryEffectsBase Other) const { + return MemoryEffectsBase(Data | Other.Data); } - /// Union (in-place) with other MemoryEffects. - MemoryEffects &operator|=(MemoryEffects Other) { + /// Union (in-place) with other MemoryEffectsBase. + MemoryEffectsBase &operator|=(MemoryEffectsBase Other) { Data |= Other.Data; return *this; } - /// Check whether this is the same as other MemoryEffects. - bool operator==(MemoryEffects Other) const { - return Data == Other.Data; + /// Subtract other MemoryEffectsBase. + MemoryEffectsBase operator-(MemoryEffectsBase Other) const { + return MemoryEffectsBase(Data & ~Other.Data); } - /// Check whether this is different from other MemoryEffects. - bool operator!=(MemoryEffects Other) const { - return !operator==(Other); + /// Subtract (in-place) with other MemoryEffectsBase. + MemoryEffectsBase &operator-=(MemoryEffectsBase Other) { + Data &= ~Other.Data; + return *this; } + + /// Check whether this is the same as other MemoryEffectsBase. + bool operator==(MemoryEffectsBase Other) const { return Data == Other.Data; } + + /// Check whether this is different from other MemoryEffectsBase. + bool operator!=(MemoryEffectsBase Other) const { return !operator==(Other); } }; +/// Summary of how a function affects memory in the program. +/// +/// Loads from constant globals are not considered memory accesses for this +/// interface. Also, functions may freely modify stack space local to their +/// invocation without having to report it through these interfaces. +using MemoryEffects = MemoryEffectsBase; + /// Debug print MemoryEffects. raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB); diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp --- a/llvm/lib/Analysis/AliasAnalysis.cpp +++ b/llvm/lib/Analysis/AliasAnalysis.cpp @@ -227,12 +227,12 @@ // We can completely ignore inaccessible memory here, because MemoryLocations // can only reference accessible memory. auto ME = getMemoryEffects(Call, AAQI) - .getWithoutLoc(MemoryEffects::InaccessibleMem); + .getWithoutLoc(IRMemLocation::InaccessibleMem); if (ME.doesNotAccessMemory()) return ModRefInfo::NoModRef; - ModRefInfo ArgMR = ME.getModRef(MemoryEffects::ArgMem); - ModRefInfo OtherMR = ME.getWithoutLoc(MemoryEffects::ArgMem).getModRef(); + ModRefInfo ArgMR = ME.getModRef(IRMemLocation::ArgMem); + ModRefInfo OtherMR = ME.getWithoutLoc(IRMemLocation::ArgMem).getModRef(); if ((ArgMR | OtherMR) != OtherMR) { // Refine the modref info for argument memory. We only bother to do this // if ArgMR is not a subset of OtherMR, otherwise this won't have an impact @@ -442,15 +442,15 @@ } raw_ostream &llvm::operator<<(raw_ostream &OS, MemoryEffects ME) { - for (MemoryEffects::Location Loc : MemoryEffects::locations()) { + for (IRMemLocation Loc : MemoryEffects::locations()) { switch (Loc) { - case MemoryEffects::ArgMem: + case IRMemLocation::ArgMem: OS << "ArgMem: "; break; - case MemoryEffects::InaccessibleMem: + case IRMemLocation::InaccessibleMem: OS << "InaccessibleMem: "; break; - case MemoryEffects::Other: + case IRMemLocation::Other: OS << "Other: "; break; } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2279,9 +2279,9 @@ static std::optional keywordToLoc(lltok::Kind Tok) { switch (Tok) { case lltok::kw_argmem: - return MemoryEffects::ArgMem; + return IRMemLocation::ArgMem; case lltok::kw_inaccessiblemem: - return MemoryEffects::InaccessibleMem; + return IRMemLocation::InaccessibleMem; default: return std::nullopt; } @@ -2318,7 +2318,7 @@ bool SeenLoc = false; do { - std::optional Loc = keywordToLoc(Lex.getKind()); + std::optional Loc = keywordToLoc(Lex.getKind()); if (Loc) { Lex.Lex(); if (!EatIfPresent(lltok::colon)) { diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -523,7 +523,7 @@ // Print access kind for "other" as the default access kind. This way it // will apply to any new location kinds that get split out of "other". - ModRefInfo OtherMR = ME.getModRef(MemoryEffects::Other); + ModRefInfo OtherMR = ME.getModRef(IRMemLocation::Other); if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) { First = false; OS << getModRefStr(OtherMR); @@ -539,13 +539,13 @@ First = false; switch (Loc) { - case MemoryEffects::ArgMem: + case IRMemLocation::ArgMem: OS << "argmem: "; break; - case MemoryEffects::InaccessibleMem: + case IRMemLocation::InaccessibleMem: OS << "inaccessiblemem: "; break; - case MemoryEffects::Other: + case IRMemLocation::Other: llvm_unreachable("This is represented as the default access kind"); } OS << getModRefStr(MR); diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -152,7 +152,7 @@ // If it's not an identified object, it might be an argument. if (!isIdentifiedObject(UO)) ME |= MemoryEffects::argMemOnly(MR); - ME |= MemoryEffects(MemoryEffects::Other, MR); + ME |= MemoryEffects(IRMemLocation::Other, MR); }; // Scan the function body for instructions that may read or write memory. for (Instruction &I : instructions(F)) { @@ -179,17 +179,17 @@ if (isa(I)) continue; - ME |= CallME.getWithoutLoc(MemoryEffects::ArgMem); + ME |= CallME.getWithoutLoc(IRMemLocation::ArgMem); // If the call accesses captured memory (currently part of "other") and // an argument is captured (currently not tracked), then it may also // access argument memory. - ModRefInfo OtherMR = CallME.getModRef(MemoryEffects::Other); + ModRefInfo OtherMR = CallME.getModRef(IRMemLocation::Other); ME |= MemoryEffects::argMemOnly(OtherMR); // Check whether all pointer arguments point to local memory, and // ignore calls that only access local memory. - ModRefInfo ArgMR = CallME.getModRef(MemoryEffects::ArgMem); + ModRefInfo ArgMR = CallME.getModRef(IRMemLocation::ArgMem); if (ArgMR != ModRefInfo::NoModRef) { for (const Use &U : Call->args()) { const Value *Arg = U; diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp --- a/llvm/lib/Transforms/IPO/SCCP.cpp +++ b/llvm/lib/Transforms/IPO/SCCP.cpp @@ -191,8 +191,8 @@ if (ME == MemoryEffects::unknown()) return AL; - ME |= MemoryEffects(MemoryEffects::Other, - ME.getModRef(MemoryEffects::ArgMem)); + ME |= MemoryEffects(IRMemLocation::Other, + ME.getModRef(IRMemLocation::ArgMem)); return AL.addFnAttribute( F.getContext(), Attribute::getWithMemoryEffects(F.getContext(), ME));