Index: llvm/include/llvm/Analysis/AliasAnalysis.h
===================================================================
--- llvm/include/llvm/Analysis/AliasAnalysis.h
+++ llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -39,6 +39,7 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Analysis/MemoryLocation.h"
 #include "llvm/IR/PassManager.h"
@@ -198,145 +199,181 @@
   return MRI1 & MRI2;
 }
 
-/// The locations at which a function might access memory.
-///
-/// These are primarily used in conjunction with the \c AccessKind bits to
-/// describe both the nature of access and the locations of access for a
-/// function call.
-enum FunctionModRefLocation {
-  /// Base case is no access to memory.
-  FMRL_Nowhere = 0,
-  /// Access to memory via argument pointers.
-  FMRL_ArgumentPointees = 8,
-  /// Memory that is inaccessible via LLVM IR.
-  FMRL_InaccessibleMem = 16,
-  /// Access to any memory.
-  FMRL_Anywhere = 32 | FMRL_InaccessibleMem | FMRL_ArgumentPointees
-};
+/// 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.
-enum FunctionModRefBehavior {
-  /// This function does not perform any non-local loads or stores to memory.
-  ///
-  /// This property corresponds to the GCC 'const' attribute.
-  /// This property corresponds to the LLVM IR 'readnone' attribute.
-  /// This property corresponds to the IntrNoMem LLVM intrinsic flag.
-  FMRB_DoesNotAccessMemory =
-      FMRL_Nowhere | static_cast<int>(ModRefInfo::NoModRef),
-
-  /// The only memory references in this function (if it has any) are
-  /// non-volatile loads from objects pointed to by its pointer-typed
-  /// arguments, with arbitrary offsets.
-  ///
-  /// This property corresponds to the combination of the IntrReadMem
-  /// and IntrArgMemOnly LLVM intrinsic flags.
-  FMRB_OnlyReadsArgumentPointees =
-      FMRL_ArgumentPointees | static_cast<int>(ModRefInfo::Ref),
-
-  /// The only memory references in this function (if it has any) are
-  /// non-volatile stores from objects pointed to by its pointer-typed
-  /// arguments, with arbitrary offsets.
-  ///
-  /// This property corresponds to the combination of the IntrWriteMem
-  /// and IntrArgMemOnly LLVM intrinsic flags.
-  FMRB_OnlyWritesArgumentPointees =
-      FMRL_ArgumentPointees | static_cast<int>(ModRefInfo::Mod),
-
-  /// The only memory references in this function (if it has any) are
-  /// non-volatile loads and stores from objects pointed to by its
-  /// pointer-typed arguments, with arbitrary offsets.
-  ///
-  /// This property corresponds to the IntrArgMemOnly LLVM intrinsic flag.
-  FMRB_OnlyAccessesArgumentPointees =
-      FMRL_ArgumentPointees | static_cast<int>(ModRefInfo::ModRef),
+class FunctionModRefBehavior {
+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,
+  };
 
-  /// The only memory references in this function (if it has any) are
-  /// reads of memory that is otherwise inaccessible via LLVM IR.
-  ///
-  /// This property corresponds to the LLVM IR inaccessiblememonly attribute.
-  FMRB_OnlyReadsInaccessibleMem =
-      FMRL_InaccessibleMem | static_cast<int>(ModRefInfo::Ref),
+private:
+  uint32_t Data;
 
-  /// The only memory references in this function (if it has any) are
-  /// writes to memory that is otherwise inaccessible via LLVM IR.
-  ///
-  /// This property corresponds to the LLVM IR inaccessiblememonly attribute.
-  FMRB_OnlyWritesInaccessibleMem =
-      FMRL_InaccessibleMem | static_cast<int>(ModRefInfo::Mod),
+  static constexpr uint32_t BitsPerLoc = 2;
+  static constexpr uint32_t LocMask = (1 << BitsPerLoc) - 1;
 
-  /// The only memory references in this function (if it has any) are
-  /// references of memory that is otherwise inaccessible via LLVM IR.
-  ///
-  /// This property corresponds to the LLVM IR inaccessiblememonly attribute.
-  FMRB_OnlyAccessesInaccessibleMem =
-      FMRL_InaccessibleMem | static_cast<int>(ModRefInfo::ModRef),
-
-  /// The function may perform non-volatile loads from objects pointed
-  /// to by its pointer-typed arguments, with arbitrary offsets, and
-  /// it may also perform loads of memory that is otherwise
-  /// inaccessible via LLVM IR.
-  ///
-  /// This property corresponds to the LLVM IR
-  /// inaccessiblemem_or_argmemonly attribute.
-  FMRB_OnlyReadsInaccessibleOrArgMem = FMRL_InaccessibleMem |
-                                       FMRL_ArgumentPointees |
-                                       static_cast<int>(ModRefInfo::Ref),
-
-  /// The function may perform non-volatile stores to objects pointed
-  /// to by its pointer-typed arguments, with arbitrary offsets, and
-  /// it may also perform stores of memory that is otherwise
-  /// inaccessible via LLVM IR.
-  ///
-  /// This property corresponds to the LLVM IR
-  /// inaccessiblemem_or_argmemonly attribute.
-  FMRB_OnlyWritesInaccessibleOrArgMem = FMRL_InaccessibleMem |
-                                        FMRL_ArgumentPointees |
-                                        static_cast<int>(ModRefInfo::Mod),
-
-  /// The function may perform non-volatile loads and stores of objects
-  /// pointed to by its pointer-typed arguments, with arbitrary offsets, and
-  /// it may also perform loads and stores of memory that is otherwise
-  /// inaccessible via LLVM IR.
-  ///
-  /// This property corresponds to the LLVM IR
-  /// inaccessiblemem_or_argmemonly attribute.
-  FMRB_OnlyAccessesInaccessibleOrArgMem = FMRL_InaccessibleMem |
-                                          FMRL_ArgumentPointees |
-                                          static_cast<int>(ModRefInfo::ModRef),
-
-  /// This function does not perform any non-local stores or volatile loads,
-  /// but may read from any memory location.
-  ///
-  /// This property corresponds to the GCC 'pure' attribute.
-  /// This property corresponds to the LLVM IR 'readonly' attribute.
-  /// This property corresponds to the IntrReadMem LLVM intrinsic flag.
-  FMRB_OnlyReadsMemory = FMRL_Anywhere | static_cast<int>(ModRefInfo::Ref),
-
-  // This function does not read from memory anywhere, but may write to any
-  // memory location.
-  //
-  // This property corresponds to the LLVM IR 'writeonly' attribute.
-  // This property corresponds to the IntrWriteMem LLVM intrinsic flag.
-  FMRB_OnlyWritesMemory = FMRL_Anywhere | static_cast<int>(ModRefInfo::Mod),
-
-  /// This indicates that the function could not be classified into one of the
-  /// behaviors above.
-  FMRB_UnknownModRefBehavior =
-      FMRL_Anywhere | static_cast<int>(ModRefInfo::ModRef)
+  static uint32_t getLocationPos(Location Loc) {
+    return (uint32_t)Loc * BitsPerLoc;
+  }
+
+  static auto locations() {
+    return enum_seq_inclusive(Location::ArgMem, Location::Other,
+                              force_iteration_on_noniterable_enum);
+  }
+
+  FunctionModRefBehavior(uint32_t Data = 0) : Data(Data) {}
+
+  friend raw_ostream &operator<<(raw_ostream &OS, FunctionModRefBehavior RMRB);
+
+public:
+  FunctionModRefBehavior(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); }
+
+  /// Create FunctionModRefBehavior that can access any location with the
+  /// given ModRefInfo.
+  static FunctionModRefBehavior anyLoc(ModRefInfo MR) {
+    FunctionModRefBehavior FRMB;
+    for (Location Loc : locations())
+      FRMB.setModRef(Loc, MR);
+    return FRMB;
+  }
+
+  /// Create FunctionModRefBehavior that can read and write any memory.
+  static FunctionModRefBehavior unknown() {
+    return anyLoc(ModRefInfo::ModRef);
+  }
+
+  /// Create FunctionModRefBehavior that cannot read or write any memory.
+  static FunctionModRefBehavior none() {
+    return FunctionModRefBehavior();
+  }
+
+  /// Create FunctionModRefBehavior that can read any memory.
+  static FunctionModRefBehavior readOnly() {
+    return anyLoc(ModRefInfo::Ref);
+  }
+
+  /// Create FunctionModRefBehavior that can only access argument memory.
+  static FunctionModRefBehavior argMemOnly(ModRefInfo MR) {
+    return FunctionModRefBehavior(ArgMem, MR);
+  }
+
+  /// Create FunctionModRefBehavior that can only access inaccessible memory.
+  static FunctionModRefBehavior inaccessibleMemOnly(ModRefInfo MR) {
+    return FunctionModRefBehavior(InaccessibleMem, MR);
+  }
+
+  /// Create FunctionModRefBehavior that can only access inaccessible or
+  /// argument memory.
+  static FunctionModRefBehavior inaccessibleOrArgMemOnly(ModRefInfo MR) {
+    FunctionModRefBehavior FRMB;
+    FRMB.setModRef(ArgMem, MR);
+    FRMB.setModRef(InaccessibleMem, MR);
+    return FRMB;
+  }
+
+  /// Get ModRefInfo for the given Location.
+  ModRefInfo getModRef(Location Loc) const {
+    return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask);
+  }
+
+  /// Set ModRefInfo for the given Location.
+  void setModRef(Location Loc, ModRefInfo MR) {
+    Data &= ~(LocMask << getLocationPos(Loc));
+    Data |= static_cast<uint32_t>(MR) << getLocationPos(Loc);
+  }
+
+  /// Get new FunctionModRefBehavior with modified ModRefInfo for Loc.
+  FunctionModRefBehavior withModRef(Location Loc, ModRefInfo MR) const {
+    FunctionModRefBehavior FMRB = *this;
+    FMRB.setModRef(Loc, MR);
+    return FMRB;
+  }
+
+  /// Get new FunctionModRefBehavior with NoModRef on the given Loc.
+  FunctionModRefBehavior withoutLoc(Location Loc) const {
+    return withModRef(Loc, ModRefInfo::NoModRef);
+  }
+
+  /// Get ModRefInfo for any location.
+  ModRefInfo getModRef() const {
+    ModRefInfo MR = ModRefInfo::NoModRef;
+    for (Location Loc : locations())
+      MR |= getModRef(Loc);
+    return MR;
+  }
+
+  /// Whether this function accesses no memory.
+  bool doesNotAccessMemory() const { return Data == 0; }
+
+  /// Whether this function only (at most) reads memory.
+  bool onlyReadsMemory() const { return !isModSet(getModRef()); }
+
+  /// Whether this function only (at most) writes memory.
+  bool onlyWritesMemory() const { return !isRefSet(getModRef()); }
+
+  /// Whether this function only (at most) accesses argument memory.
+  bool onlyAccessesArgPointees() const {
+    return withoutLoc(ArgMem).doesNotAccessMemory();
+  }
+
+  /// Whether this function may access argument memory.
+  bool doesAccessArgPointees() const {
+    return isModOrRefSet(getModRef(ArgMem));
+  }
+
+  /// Whether this function only (at most) accesses inaccessible memory.
+  bool onlyAccessesInaccessibleMem() const {
+    return withoutLoc(InaccessibleMem).doesNotAccessMemory();
+  }
+
+  /// Whether this function may access inaccessible memory.
+  bool doesAccessInaccessibleMem() const {
+    return isModOrRefSet(getModRef(InaccessibleMem));
+  }
+
+  /// Whether this function only (at most) accesses argument and inaccessible
+  /// memory.
+  bool onlyAccessesInaccessibleOrArgMem() const {
+    return withoutLoc(ArgMem).withoutLoc(InaccessibleMem).doesNotAccessMemory();
+  }
+
+  /// Intersect (in-place) with another FunctionModRefBehavior.
+  FunctionModRefBehavior operator&(FunctionModRefBehavior Other) const {
+    return FunctionModRefBehavior(Data & Other.Data);
+  }
+
+  /// Intersect with another FunctionModRefBehavior.
+  FunctionModRefBehavior &operator&=(FunctionModRefBehavior Other) {
+    Data &= Other.Data;
+    return *this;
+  }
+
+  /// Check whether this is the same as another FunctionModRefBehavior.
+  bool operator==(FunctionModRefBehavior Other) const {
+    return Data == Other.Data;
+  }
+
+  /// Check whether this is different from another FunctionModRefBehavior.
+  bool operator!=(FunctionModRefBehavior Other) const {
+    return !operator==(Other);
+  }
 };
 
-// Wrapper method strips bits significant only in FunctionModRefBehavior,
-// to obtain a valid ModRefInfo. The benefit of using the wrapper is that if
-// ModRefInfo enum changes, the wrapper can be updated to & with the new enum
-// entry with all bits set to 1.
-LLVM_NODISCARD inline ModRefInfo
-createModRefInfo(const FunctionModRefBehavior FMRB) {
-  return ModRefInfo(FMRB & static_cast<int>(ModRefInfo::ModRef));
-}
+/// Debug print FunctionModRefBehavior.
+raw_ostream &operator<<(raw_ostream &OS, FunctionModRefBehavior RMRB);
 
 /// Virtual base class for providers of capture information.
 struct CaptureInfo {
@@ -590,7 +627,7 @@
   ///
   /// This property corresponds to the GCC 'const' attribute.
   bool doesNotAccessMemory(const CallBase *Call) {
-    return getModRefBehavior(Call) == FMRB_DoesNotAccessMemory;
+    return getModRefBehavior(Call).doesNotAccessMemory();
   }
 
   /// Checks if the specified function is known to never read or write memory.
@@ -605,7 +642,7 @@
   ///
   /// This property corresponds to the GCC 'const' attribute.
   bool doesNotAccessMemory(const Function *F) {
-    return getModRefBehavior(F) == FMRB_DoesNotAccessMemory;
+    return getModRefBehavior(F).doesNotAccessMemory();
   }
 
   /// Checks if the specified call is known to only read from non-volatile
@@ -618,7 +655,7 @@
   ///
   /// This property corresponds to the GCC 'pure' attribute.
   bool onlyReadsMemory(const CallBase *Call) {
-    return onlyReadsMemory(getModRefBehavior(Call));
+    return getModRefBehavior(Call).onlyReadsMemory();
   }
 
   /// Checks if the specified function is known to only read from non-volatile
@@ -631,55 +668,7 @@
   ///
   /// This property corresponds to the GCC 'pure' attribute.
   bool onlyReadsMemory(const Function *F) {
-    return onlyReadsMemory(getModRefBehavior(F));
-  }
-
-  /// Checks if functions with the specified behavior are known to only read
-  /// from non-volatile memory (or not access memory at all).
-  static bool onlyReadsMemory(FunctionModRefBehavior MRB) {
-    return !isModSet(createModRefInfo(MRB));
-  }
-
-  /// Checks if functions with the specified behavior are known to only write
-  /// memory (or not access memory at all).
-  static bool onlyWritesMemory(FunctionModRefBehavior MRB) {
-    return !isRefSet(createModRefInfo(MRB));
-  }
-
-  /// Checks if functions with the specified behavior are known to read and
-  /// write at most from objects pointed to by their pointer-typed arguments
-  /// (with arbitrary offsets).
-  static bool onlyAccessesArgPointees(FunctionModRefBehavior MRB) {
-    return !((unsigned)MRB & FMRL_Anywhere & ~FMRL_ArgumentPointees);
-  }
-
-  /// Checks if functions with the specified behavior are known to potentially
-  /// read or write from objects pointed to be their pointer-typed arguments
-  /// (with arbitrary offsets).
-  static bool doesAccessArgPointees(FunctionModRefBehavior MRB) {
-    return isModOrRefSet(createModRefInfo(MRB)) &&
-           ((unsigned)MRB & FMRL_ArgumentPointees);
-  }
-
-  /// Checks if functions with the specified behavior are known to read and
-  /// write at most from memory that is inaccessible from LLVM IR.
-  static bool onlyAccessesInaccessibleMem(FunctionModRefBehavior MRB) {
-    return !((unsigned)MRB & FMRL_Anywhere & ~FMRL_InaccessibleMem);
-  }
-
-  /// Checks if functions with the specified behavior are known to potentially
-  /// read or write from memory that is inaccessible from LLVM IR.
-  static bool doesAccessInaccessibleMem(FunctionModRefBehavior MRB) {
-    return isModOrRefSet(createModRefInfo(MRB)) &&
-             ((unsigned)MRB & FMRL_InaccessibleMem);
-  }
-
-  /// Checks if functions with the specified behavior are known to read and
-  /// write at most from memory that is inaccessible from LLVM IR or objects
-  /// pointed to by their pointer-typed arguments (with arbitrary offsets).
-  static bool onlyAccessesInaccessibleOrArgMem(FunctionModRefBehavior MRB) {
-    return !((unsigned)MRB & FMRL_Anywhere &
-             ~(FMRL_InaccessibleMem | FMRL_ArgumentPointees));
+    return getModRefBehavior(F).onlyReadsMemory();
   }
 
   /// getModRefInfo (for call sites) - Return information about whether
@@ -1192,11 +1181,11 @@
   }
 
   FunctionModRefBehavior getModRefBehavior(const CallBase *Call) {
-    return FMRB_UnknownModRefBehavior;
+    return FunctionModRefBehavior::unknown();
   }
 
   FunctionModRefBehavior getModRefBehavior(const Function *F) {
-    return FMRB_UnknownModRefBehavior;
+    return FunctionModRefBehavior::unknown();
   }
 
   ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc,
Index: llvm/lib/Analysis/AliasAnalysis.cpp
===================================================================
--- llvm/lib/Analysis/AliasAnalysis.cpp
+++ llvm/lib/Analysis/AliasAnalysis.cpp
@@ -236,17 +236,15 @@
   // Try to refine the mod-ref info further using other API entry points to the
   // aggregate set of AA results.
   auto MRB = getModRefBehavior(Call);
-  if (onlyAccessesInaccessibleMem(MRB))
+  if (MRB.onlyAccessesInaccessibleMem())
     return ModRefInfo::NoModRef;
 
-  if (onlyReadsMemory(MRB))
-    Result &= ModRefInfo::Ref;
-  else if (onlyWritesMemory(MRB))
-    Result &= ModRefInfo::Mod;
+  // TODO: Exclude inaccessible memory location here.
+  Result &= MRB.getModRef();
 
-  if (onlyAccessesArgPointees(MRB) || onlyAccessesInaccessibleOrArgMem(MRB)) {
+  if (MRB.onlyAccessesArgPointees() || MRB.onlyAccessesInaccessibleOrArgMem()) {
     ModRefInfo AllArgsMask = ModRefInfo::NoModRef;
-    if (doesAccessArgPointees(MRB)) {
+    if (MRB.doesAccessArgPointees()) {
       for (const auto &I : llvm::enumerate(Call->args())) {
         const Value *Arg = I.value();
         if (!Arg->getType()->isPointerTy())
@@ -297,29 +295,29 @@
 
   // If Call1 or Call2 are readnone, they don't interact.
   auto Call1B = getModRefBehavior(Call1);
-  if (Call1B == FMRB_DoesNotAccessMemory)
+  if (Call1B.doesNotAccessMemory())
     return ModRefInfo::NoModRef;
 
   auto Call2B = getModRefBehavior(Call2);
-  if (Call2B == FMRB_DoesNotAccessMemory)
+  if (Call2B.doesNotAccessMemory())
     return ModRefInfo::NoModRef;
 
   // If they both only read from memory, there is no dependence.
-  if (onlyReadsMemory(Call1B) && onlyReadsMemory(Call2B))
+  if (Call1B.onlyReadsMemory() && Call2B.onlyReadsMemory())
     return ModRefInfo::NoModRef;
 
   // If Call1 only reads memory, the only dependence on Call2 can be
   // from Call1 reading memory written by Call2.
-  if (onlyReadsMemory(Call1B))
+  if (Call1B.onlyReadsMemory())
     Result &= ModRefInfo::Ref;
-  else if (onlyWritesMemory(Call1B))
+  else if (Call1B.onlyWritesMemory())
     Result &= ModRefInfo::Mod;
 
   // If Call2 only access memory through arguments, accumulate the mod/ref
   // information from Call1's references to the memory referenced by
   // Call2's arguments.
-  if (onlyAccessesArgPointees(Call2B)) {
-    if (!doesAccessArgPointees(Call2B))
+  if (Call2B.onlyAccessesArgPointees()) {
+    if (!Call2B.doesAccessArgPointees())
       return ModRefInfo::NoModRef;
     ModRefInfo R = ModRefInfo::NoModRef;
     for (auto I = Call2->arg_begin(), E = Call2->arg_end(); I != E; ++I) {
@@ -356,8 +354,8 @@
 
   // If Call1 only accesses memory through arguments, check if Call2 references
   // any of the memory referenced by Call1's arguments. If not, return NoModRef.
-  if (onlyAccessesArgPointees(Call1B)) {
-    if (!doesAccessArgPointees(Call1B))
+  if (Call1B.onlyAccessesArgPointees()) {
+    if (!Call1B.doesAccessArgPointees())
       return ModRefInfo::NoModRef;
     ModRefInfo R = ModRefInfo::NoModRef;
     for (auto I = Call1->arg_begin(), E = Call1->arg_end(); I != E; ++I) {
@@ -388,13 +386,13 @@
 }
 
 FunctionModRefBehavior AAResults::getModRefBehavior(const CallBase *Call) {
-  FunctionModRefBehavior Result = FMRB_UnknownModRefBehavior;
+  FunctionModRefBehavior Result = FunctionModRefBehavior::unknown();
 
   for (const auto &AA : AAs) {
-    Result = FunctionModRefBehavior(Result & AA->getModRefBehavior(Call));
+    Result &= AA->getModRefBehavior(Call);
 
     // Early-exit the moment we reach the bottom of the lattice.
-    if (Result == FMRB_DoesNotAccessMemory)
+    if (Result.doesNotAccessMemory())
       return Result;
   }
 
@@ -402,13 +400,13 @@
 }
 
 FunctionModRefBehavior AAResults::getModRefBehavior(const Function *F) {
-  FunctionModRefBehavior Result = FMRB_UnknownModRefBehavior;
+  FunctionModRefBehavior Result = FunctionModRefBehavior::unknown();
 
   for (const auto &AA : AAs) {
-    Result = FunctionModRefBehavior(Result & AA->getModRefBehavior(F));
+    Result &= AA->getModRefBehavior(F);
 
     // Early-exit the moment we reach the bottom of the lattice.
-    if (Result == FMRB_DoesNotAccessMemory)
+    if (Result.doesNotAccessMemory())
       return Result;
   }
 
@@ -435,6 +433,43 @@
   return OS;
 }
 
+raw_ostream &llvm::operator<<(raw_ostream &OS, ModRefInfo MR) {
+  switch (MR) {
+  case ModRefInfo::NoModRef:
+    OS << "NoModRef";
+    break;
+  case ModRefInfo::Ref:
+    OS << "Ref";
+    break;
+  case ModRefInfo::Mod:
+    OS << "Mod";
+    break;
+  case ModRefInfo::ModRef:
+    OS << "ModRef";
+    break;
+  }
+  return OS;
+}
+
+raw_ostream &llvm::operator<<(raw_ostream &OS, FunctionModRefBehavior FMRB) {
+  for (FunctionModRefBehavior::Location Loc :
+       FunctionModRefBehavior::locations()) {
+    switch (Loc) {
+    case FunctionModRefBehavior::ArgMem:
+      OS << "ArgMem: ";
+      break;
+    case FunctionModRefBehavior::InaccessibleMem:
+      OS << "InaccessibleMem: ";
+      break;
+    case FunctionModRefBehavior::Other:
+      OS << "Other: ";
+      break;
+    }
+    OS << FMRB.getModRef(Loc) << ", ";
+  }
+  return OS;
+}
+
 //===----------------------------------------------------------------------===//
 // Helper method implementation
 //===----------------------------------------------------------------------===//
@@ -624,9 +659,8 @@
                                     const Optional<MemoryLocation> &OptLoc,
                                     AAQueryInfo &AAQIP) {
   if (OptLoc == None) {
-    if (const auto *Call = dyn_cast<CallBase>(I)) {
-      return createModRefInfo(getModRefBehavior(Call));
-    }
+    if (const auto *Call = dyn_cast<CallBase>(I))
+      return getModRefBehavior(Call).getModRef();
   }
 
   const MemoryLocation &Loc = OptLoc.value_or(MemoryLocation());
Index: llvm/lib/Analysis/AliasSetTracker.cpp
===================================================================
--- llvm/lib/Analysis/AliasSetTracker.cpp
+++ llvm/lib/Analysis/AliasSetTracker.cpp
@@ -451,7 +451,7 @@
           return AliasSet::NoAccess;
       };
 
-      ModRefInfo CallMask = createModRefInfo(AA.getModRefBehavior(Call));
+      ModRefInfo CallMask = AA.getModRefBehavior(Call).getModRef();
 
       // Some intrinsics are marked as modifying memory for control flow
       // modelling purposes, but don't actually modify any specific memory
Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp
===================================================================
--- llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -746,31 +746,30 @@
 FunctionModRefBehavior BasicAAResult::getModRefBehavior(const CallBase *Call) {
   if (Call->doesNotAccessMemory())
     // Can't do better than this.
-    return FMRB_DoesNotAccessMemory;
-
-  FunctionModRefBehavior Min = FMRB_UnknownModRefBehavior;
+    return FunctionModRefBehavior::none();
 
   // If the callsite knows it only reads memory, don't return worse
   // than that.
+  ModRefInfo MR = ModRefInfo::ModRef;
   if (Call->onlyReadsMemory())
-    Min = FMRB_OnlyReadsMemory;
+    MR = ModRefInfo::Ref;
   else if (Call->onlyWritesMemory())
-    Min = FMRB_OnlyWritesMemory;
+    MR = ModRefInfo::Mod;
 
+  FunctionModRefBehavior Min = FunctionModRefBehavior::anyLoc(MR);
   if (Call->onlyAccessesArgMemory())
-    Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees);
+    Min = FunctionModRefBehavior::argMemOnly(MR);
   else if (Call->onlyAccessesInaccessibleMemory())
-    Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleMem);
+    Min = FunctionModRefBehavior::inaccessibleMemOnly(MR);
   else if (Call->onlyAccessesInaccessibleMemOrArgMem())
-    Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleOrArgMem);
+    Min = FunctionModRefBehavior::inaccessibleOrArgMemOnly(MR);
 
   // If the call has operand bundles then aliasing attributes from the function
   // it calls do not directly apply to the call.  This can be made more precise
   // in the future.
   if (!Call->hasOperandBundles())
     if (const Function *F = Call->getCalledFunction())
-      Min =
-          FunctionModRefBehavior(Min & getBestAAResults().getModRefBehavior(F));
+      Min &= getBestAAResults().getModRefBehavior(F);
 
   return Min;
 }
@@ -780,24 +779,22 @@
 FunctionModRefBehavior BasicAAResult::getModRefBehavior(const Function *F) {
   // If the function declares it doesn't access memory, we can't do better.
   if (F->doesNotAccessMemory())
-    return FMRB_DoesNotAccessMemory;
-
-  FunctionModRefBehavior Min = FMRB_UnknownModRefBehavior;
+    return FunctionModRefBehavior::none();
 
   // If the function declares it only reads memory, go with that.
+  ModRefInfo MR = ModRefInfo::ModRef;
   if (F->onlyReadsMemory())
-    Min = FMRB_OnlyReadsMemory;
+    MR = ModRefInfo::Ref;
   else if (F->onlyWritesMemory())
-    Min = FMRB_OnlyWritesMemory;
+    MR = ModRefInfo::Mod;
 
   if (F->onlyAccessesArgMemory())
-    Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees);
-  else if (F->onlyAccessesInaccessibleMemory())
-    Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleMem);
-  else if (F->onlyAccessesInaccessibleMemOrArgMem())
-    Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleOrArgMem);
-
-  return Min;
+    return FunctionModRefBehavior::argMemOnly(MR);
+  if (F->onlyAccessesInaccessibleMemory())
+    return FunctionModRefBehavior::inaccessibleMemOnly(MR);
+  if (F->onlyAccessesInaccessibleMemOrArgMem())
+    return FunctionModRefBehavior::inaccessibleOrArgMemOnly(MR);
+  return FunctionModRefBehavior::anyLoc(MR);
 }
 
 /// Returns true if this is a writeonly (i.e Mod only) parameter.
@@ -1052,12 +1049,12 @@
   // possibilities for guard intrinsics.
 
   if (isIntrinsicCall(Call1, Intrinsic::experimental_guard))
-    return isModSet(createModRefInfo(getModRefBehavior(Call2)))
+    return isModSet(getModRefBehavior(Call2).getModRef())
                ? ModRefInfo::Ref
                : ModRefInfo::NoModRef;
 
   if (isIntrinsicCall(Call2, Intrinsic::experimental_guard))
-    return isModSet(createModRefInfo(getModRefBehavior(Call1)))
+    return isModSet(getModRefBehavior(Call1).getModRef())
                ? ModRefInfo::Mod
                : ModRefInfo::NoModRef;
 
Index: llvm/lib/Analysis/GlobalsModRef.cpp
===================================================================
--- llvm/lib/Analysis/GlobalsModRef.cpp
+++ llvm/lib/Analysis/GlobalsModRef.cpp
@@ -239,16 +239,10 @@
 }
 
 FunctionModRefBehavior GlobalsAAResult::getModRefBehavior(const Function *F) {
-  FunctionModRefBehavior Min = FMRB_UnknownModRefBehavior;
+  if (FunctionInfo *FI = getFunctionInfo(F))
+    return FunctionModRefBehavior::anyLoc(FI->getModRefInfo());
 
-  if (FunctionInfo *FI = getFunctionInfo(F)) {
-    if (!isModOrRefSet(FI->getModRefInfo()))
-      Min = FMRB_DoesNotAccessMemory;
-    else if (!isModSet(FI->getModRefInfo()))
-      Min = FMRB_OnlyReadsMemory;
-  }
-
-  return FunctionModRefBehavior(AAResultBase::getModRefBehavior(F) & Min);
+  return AAResultBase::getModRefBehavior(F);
 }
 
 /// Returns the function info for the function, or null if we don't have
@@ -585,7 +579,7 @@
 
               FunctionModRefBehavior Behaviour =
                   AAResultBase::getModRefBehavior(Callee);
-              FI.addModRefInfo(createModRefInfo(Behaviour));
+              FI.addModRefInfo(Behaviour.getModRef());
             }
           }
           continue;
Index: llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
===================================================================
--- llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
+++ llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
@@ -98,7 +98,7 @@
 
   switch (GetFunctionClass(F)) {
   case ARCInstKind::NoopCast:
-    return FMRB_DoesNotAccessMemory;
+    return FunctionModRefBehavior::none();
   default:
     break;
   }
Index: llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
===================================================================
--- llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -409,16 +409,14 @@
   if (!EnableTBAA)
     return AAResultBase::getModRefBehavior(Call);
 
-  FunctionModRefBehavior Min = FMRB_UnknownModRefBehavior;
-
   // If this is an "immutable" type, we can assume the call doesn't write
   // to memory.
   if (const MDNode *M = Call->getMetadata(LLVMContext::MD_tbaa))
     if ((!isStructPathTBAA(M) && TBAANode(M).isTypeImmutable()) ||
         (isStructPathTBAA(M) && TBAAStructTagNode(M).isTypeImmutable()))
-      Min = FMRB_OnlyReadsMemory;
+      return FunctionModRefBehavior::readOnly();
 
-  return FunctionModRefBehavior(AAResultBase::getModRefBehavior(Call) & Min);
+  return AAResultBase::getModRefBehavior(Call);
 }
 
 FunctionModRefBehavior TypeBasedAAResult::getModRefBehavior(const Function *F) {
Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp
===================================================================
--- llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -126,16 +126,16 @@
 checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
                           const SCCNodeSet &SCCNodes) {
   FunctionModRefBehavior MRB = AAR.getModRefBehavior(&F);
-  if (MRB == FMRB_DoesNotAccessMemory)
+  if (MRB.doesNotAccessMemory())
     // Already perfect!
     return MRB;
 
   if (!ThisBody)
     return MRB;
 
+  // TODO: We should directly populate a FunctionModRefBehavior here.
   // Scan the function body for instructions that may read or write memory.
-  bool ReadsMemory = false;
-  bool WritesMemory = false;
+  ModRefInfo MR = ModRefInfo::NoModRef;
   // Track if the function accesses memory not based on pointer arguments or
   // allocas.
   bool AccessesNonArgsOrAlloca = false;
@@ -156,7 +156,7 @@
           SCCNodes.count(Call->getCalledFunction()))
         continue;
       FunctionModRefBehavior MRB = AAR.getModRefBehavior(Call);
-      ModRefInfo MRI = createModRefInfo(MRB);
+      ModRefInfo MRI = MRB.getModRef();
 
       // If the call doesn't access memory, we're done.
       if (isNoModRef(MRI))
@@ -169,13 +169,9 @@
       if (isa<PseudoProbeInst>(I))
         continue;
 
-      if (!AliasAnalysis::onlyAccessesArgPointees(MRB)) {
-        // The call could access any memory. If that includes writes, note it.
-        if (isModSet(MRI))
-          WritesMemory = true;
-        // If it reads, note it.
-        if (isRefSet(MRI))
-          ReadsMemory = true;
+      if (!MRB.onlyAccessesArgPointees()) {
+        // The call could access any memory.
+        MR |= MRI;
         AccessesNonArgsOrAlloca = true;
         continue;
       }
@@ -195,13 +191,7 @@
           continue;
 
         AccessesNonArgsOrAlloca |= !IsArgumentOrAlloca(Loc.Ptr);
-
-        if (isModSet(MRI))
-          // Writes non-local memory.
-          WritesMemory = true;
-        if (isRefSet(MRI))
-          // Ok, it reads non-local memory.
-          ReadsMemory = true;
+        MR |= MRI;
       }
       continue;
     } else if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
@@ -234,23 +224,17 @@
     // read or write memory.
     //
     // Writes memory, remember that.
-    WritesMemory |= I.mayWriteToMemory();
+    if (I.mayWriteToMemory())
+      MR |= ModRefInfo::Mod;
 
     // If this instruction may read memory, remember that.
-    ReadsMemory |= I.mayReadFromMemory();
+    if (I.mayReadFromMemory())
+      MR |= ModRefInfo::Ref;
   }
 
-  if (!WritesMemory && !ReadsMemory)
-    return FMRB_DoesNotAccessMemory;
-
-  FunctionModRefBehavior Result = FunctionModRefBehavior(FMRL_Anywhere);
   if (!AccessesNonArgsOrAlloca)
-    Result = FunctionModRefBehavior(FMRL_ArgumentPointees);
-  if (WritesMemory)
-    Result = FunctionModRefBehavior(Result | static_cast<int>(ModRefInfo::Mod));
-  if (ReadsMemory)
-    Result = FunctionModRefBehavior(Result | static_cast<int>(ModRefInfo::Ref));
-  return Result;
+    return FunctionModRefBehavior::argMemOnly(MR);
+  return FunctionModRefBehavior::anyLoc(MR);
 }
 
 FunctionModRefBehavior llvm::computeFunctionBodyMemoryAccess(Function &F,
@@ -276,12 +260,12 @@
     // comment on GlobalValue::isDefinitionExact for more details.
     FunctionModRefBehavior FMRB =
         checkFunctionMemoryAccess(*F, F->hasExactDefinition(), AAR, SCCNodes);
-    if (FMRB == FMRB_DoesNotAccessMemory)
+    if (FMRB.doesNotAccessMemory())
       continue;
-    ModRefInfo MR = createModRefInfo(FMRB);
+    ModRefInfo MR = FMRB.getModRef();
     ReadsMemory |= isRefSet(MR);
     WritesMemory |= isModSet(MR);
-    ArgMemOnly &= AliasAnalysis::onlyAccessesArgPointees(FMRB);
+    ArgMemOnly &= FMRB.onlyAccessesArgPointees();
     // Reached neither readnone, readonly, writeonly nor argmemonly can be
     // inferred. Exit.
     if (ReadsMemory && WritesMemory && !ArgMemOnly)
Index: llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
===================================================================
--- llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
+++ llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
@@ -318,8 +318,8 @@
             return;
         }
         if (!F->isDeclaration() &&
-            computeFunctionBodyMemoryAccess(*F, AARGetter(*F)) ==
-                FMRB_DoesNotAccessMemory)
+            computeFunctionBodyMemoryAccess(*F, AARGetter(*F))
+                .doesNotAccessMemory())
           EligibleVirtualFns.insert(F);
       });
     }
Index: llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
===================================================================
--- llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -1709,8 +1709,8 @@
   // rather than using function attributes to perform local optimization.
   for (VirtualCallTarget &Target : TargetsForSlot) {
     if (Target.Fn->isDeclaration() ||
-        computeFunctionBodyMemoryAccess(*Target.Fn, AARGetter(*Target.Fn)) !=
-            FMRB_DoesNotAccessMemory ||
+        !computeFunctionBodyMemoryAccess(*Target.Fn, AARGetter(*Target.Fn))
+             .doesNotAccessMemory() ||
         Target.Fn->arg_empty() || !Target.Fn->arg_begin()->use_empty() ||
         Target.Fn->getReturnType() != RetType)
       return false;
Index: llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
===================================================================
--- llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
+++ llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
@@ -49,9 +49,9 @@
 
   // See if AliasAnalysis can help us with the call.
   FunctionModRefBehavior MRB = PA.getAA()->getModRefBehavior(Call);
-  if (AliasAnalysis::onlyReadsMemory(MRB))
+  if (MRB.onlyReadsMemory())
     return false;
-  if (AliasAnalysis::onlyAccessesArgPointees(MRB)) {
+  if (MRB.onlyAccessesArgPointees()) {
     for (const Value *Op : Call->args()) {
       if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op))
         return true;
Index: llvm/lib/Transforms/Scalar/LICM.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/LICM.cpp
+++ llvm/lib/Transforms/Scalar/LICM.cpp
@@ -1203,13 +1203,13 @@
 
     // Handle simple cases by querying alias analysis.
     FunctionModRefBehavior Behavior = AA->getModRefBehavior(CI);
-    if (Behavior == FMRB_DoesNotAccessMemory)
+    if (Behavior.doesNotAccessMemory())
       return true;
-    if (AAResults::onlyReadsMemory(Behavior)) {
+    if (Behavior.onlyReadsMemory()) {
       // A readonly argmemonly function only reads from memory pointed to by
       // it's arguments with arbitrary offsets.  If we can prove there are no
       // writes to this memory in the loop, we can hoist or sink.
-      if (AAResults::onlyAccessesArgPointees(Behavior)) {
+      if (Behavior.onlyAccessesArgPointees()) {
         // TODO: expand to writeable arguments
         for (Value *Op : CI->args())
           if (Op->getType()->isPointerTy() &&
Index: llvm/lib/Transforms/Utils/InlineFunction.cpp
===================================================================
--- llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -1064,10 +1064,10 @@
           FunctionModRefBehavior MRB = CalleeAAR->getModRefBehavior(Call);
 
           // We'll retain this knowledge without additional metadata.
-          if (AAResults::onlyAccessesInaccessibleMem(MRB))
+          if (MRB.onlyAccessesInaccessibleMem())
             continue;
 
-          if (AAResults::onlyAccessesArgPointees(MRB))
+          if (MRB.onlyAccessesArgPointees())
             IsArgMemOnlyCall = true;
         }
 
Index: llvm/unittests/Analysis/GlobalsModRefTest.cpp
===================================================================
--- llvm/unittests/Analysis/GlobalsModRefTest.cpp
+++ llvm/unittests/Analysis/GlobalsModRefTest.cpp
@@ -52,7 +52,7 @@
 
   auto AAR = GlobalsAAResult::analyzeModule(*M, GetTLI, CG);
 
-  EXPECT_EQ(FMRB_UnknownModRefBehavior, AAR.getModRefBehavior(&F1));
-  EXPECT_EQ(FMRB_DoesNotAccessMemory, AAR.getModRefBehavior(&F2));
-  EXPECT_EQ(FMRB_OnlyReadsMemory, AAR.getModRefBehavior(&F3));
+  EXPECT_EQ(FunctionModRefBehavior::unknown(), AAR.getModRefBehavior(&F1));
+  EXPECT_EQ(FunctionModRefBehavior::none(), AAR.getModRefBehavior(&F2));
+  EXPECT_EQ(FunctionModRefBehavior::readOnly(), AAR.getModRefBehavior(&F3));
 }
Index: polly/lib/Analysis/ScopBuilder.cpp
===================================================================
--- polly/lib/Analysis/ScopBuilder.cpp
+++ polly/lib/Analysis/ScopBuilder.cpp
@@ -1634,31 +1634,14 @@
   if (CI->doesNotAccessMemory() || isIgnoredIntrinsic(CI) || isDebugCall(CI))
     return true;
 
-  bool ReadOnly = false;
   auto *AF = SE.getConstant(IntegerType::getInt64Ty(CI->getContext()), 0);
   auto *CalledFunction = CI->getCalledFunction();
-  switch (AA.getModRefBehavior(CalledFunction)) {
-  case FMRB_UnknownModRefBehavior:
-    llvm_unreachable("Unknown mod ref behaviour cannot be represented.");
-  case FMRB_DoesNotAccessMemory:
-    return true;
-  case FMRB_OnlyWritesMemory:
-  case FMRB_OnlyWritesInaccessibleMem:
-  case FMRB_OnlyWritesInaccessibleOrArgMem:
-  case FMRB_OnlyAccessesInaccessibleMem:
-  case FMRB_OnlyAccessesInaccessibleOrArgMem:
-    return false;
-  case FMRB_OnlyReadsMemory:
-  case FMRB_OnlyReadsInaccessibleMem:
-  case FMRB_OnlyReadsInaccessibleOrArgMem:
-    GlobalReads.emplace_back(Stmt, CI);
-    return true;
-  case FMRB_OnlyReadsArgumentPointees:
-    ReadOnly = true;
-    LLVM_FALLTHROUGH;
-  case FMRB_OnlyWritesArgumentPointees:
-  case FMRB_OnlyAccessesArgumentPointees: {
-    auto AccType = ReadOnly ? MemoryAccess::READ : MemoryAccess::MAY_WRITE;
+  FunctionModRefBehavior FMRB = AA.getModRefBehavior(CalledFunction);
+
+  if (FMRB.onlyAccessesArgPointees()) {
+    ModRefInfo ArgMR = FMRB.getModRef(FunctionModRefBehavior::ArgMem);
+    auto AccType =
+        !isModSet(ArgMR) ? MemoryAccess::READ : MemoryAccess::MAY_WRITE;
     Loop *L = LI.getLoopFor(Inst->getParent());
     for (const auto &Arg : CI->args()) {
       if (!Arg->getType()->isPointerTy())
@@ -1679,9 +1662,12 @@
     }
     return true;
   }
-  }
 
-  return true;
+  if (FMRB.onlyReadsMemory()) {
+    GlobalReads.emplace_back(Stmt, CI);
+    return true;
+  }
+  return false;
 }
 
 void ScopBuilder::buildAccessSingleDim(MemAccInst Inst, ScopStmt *Stmt) {
Index: polly/lib/Analysis/ScopDetection.cpp
===================================================================
--- polly/lib/Analysis/ScopDetection.cpp
+++ polly/lib/Analysis/ScopDetection.cpp
@@ -708,23 +708,8 @@
   }
 
   if (AllowModrefCall) {
-    switch (AA.getModRefBehavior(CalledFunction)) {
-    case FMRB_UnknownModRefBehavior:
-      return false;
-    case FMRB_DoesNotAccessMemory:
-    case FMRB_OnlyReadsMemory:
-    case FMRB_OnlyReadsInaccessibleMem:
-    case FMRB_OnlyReadsInaccessibleOrArgMem:
-      // Implicitly disable delinearization since we have an unknown
-      // accesses with an unknown access function.
-      Context.HasUnknownAccess = true;
-      // Explicitly use addUnknown so we don't put a loop-variant
-      // pointer into the alias set.
-      Context.AST.addUnknown(&CI);
-      return true;
-    case FMRB_OnlyReadsArgumentPointees:
-    case FMRB_OnlyAccessesArgumentPointees:
-    case FMRB_OnlyWritesArgumentPointees:
+    FunctionModRefBehavior FMRB = AA.getModRefBehavior(CalledFunction);
+    if (FMRB.onlyAccessesArgPointees()) {
       for (const auto &Arg : CI.args()) {
         if (!Arg->getType()->isPointerTy())
           continue;
@@ -748,13 +733,18 @@
       // pointer into the alias set.
       Context.AST.addUnknown(&CI);
       return true;
-    case FMRB_OnlyWritesMemory:
-    case FMRB_OnlyWritesInaccessibleMem:
-    case FMRB_OnlyWritesInaccessibleOrArgMem:
-    case FMRB_OnlyAccessesInaccessibleMem:
-    case FMRB_OnlyAccessesInaccessibleOrArgMem:
-      return false;
     }
+
+    if (FMRB.onlyReadsMemory()) {
+      // Implicitly disable delinearization since we have an unknown
+      // accesses with an unknown access function.
+      Context.HasUnknownAccess = true;
+      // Explicitly use addUnknown so we don't put a loop-variant
+      // pointer into the alias set.
+      Context.AST.addUnknown(&CI);
+      return true;
+    }
+    return false;
   }
 
   return false;