[llvm] [IR] Memory effects for floating-point operations (PR #226826)

Serge Pavlov via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 27 12:11:35 PDT 2026


https://github.com/spavloff created https://github.com/llvm/llvm-project/pull/226826

Floating-point operations in a strictfp function have side effects, which are modeled using memory effects in the form of a read-write access to "inaccessible memory". This helps maintain strictfp semantics but may hinder optimizations. Floating-point operations may depend on rounding mode or not - this fact may be used to reorder them in a more optimal way. Similarly, functions that control floating-point environment (like `set_rounding`, `set_fpmode` etc.) also have more specific access than generic read-write. Also, "inaccessible memory" is used in cases other than FP operation, this results in unnecessary restrictions.

This change implements two new memory location to use instead of the access to "inaccessible memory". The "fpcontrol" location is used to represent access to floating-point control modes, of which only rounding mode is currently supported. The other location, "fpstatus", represents access to floating-point exceptions. Together they replace the use of "inaccessible memory".

The new memory locations are not supported in all cases. The Attributor does not support them now, as these locations do not exactly represent memory. Writing to a floating-point control register inside a function does not mean that the function itself changes some floating-point control mode. Supporting these locations in the Attributor requires additional considerations and, probably, new attributes.

The meaning of `MemoryEffects::onlyAccessesInaccessibleMem` is changed in this commit. Now this method checks not only the "inaccessible memory" but also floating-point environment. This change agrees with the current usage of the method in the compiler sources and will hopefully reduce the risk on misuse.

This change only introduces the new memory locations. Their use in the functions that access the floating-point environment will be implemented in another commit.

This MR was obtained from
https://github.com/llvm/llvm-project/pull/221754 by keeping only the changes required to introduce the new memory locations only.

>From 43f30af4420b573ab220d2d8d8be22821fd16708 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Fri, 25 Sep 2026 18:55:05 +0700
Subject: [PATCH] [IR] Memory effects for floating-point operations

Floating-point operations in a strictfp function have side effects,
which are modeled using memory effects in the form of a read-write
access to "inaccessible memory". This helps maintain strictfp semantics
but may hinder optimizations. Floating-point operations may depend on
rounding mode or not - this fact may be used to reorder them in a more
optimal way. Similarly, functions that control floating-point
environment (like `set_rounding`, `set_fpmode` etc.) also have more
specific access than generic read-write. Also, "inaccessible memory" is
used in cases other than FP operation, this results in unnecessary
restrictions.

This change implements two new memory location to use instead of the
access to "inaccessible memory". The "fpcontrol" location is used to
represent access to floating-point control modes, of which only rounding
mode is currently supported. The other location, "fpstatus", represents
access to floating-point exceptions. Together they replace the use of
"inaccessible memory".

The new memory locations are not supported in all cases. The Attributor
does not support them now, as these locations do not exactly represent
memory. Writing to a floating-point control register inside a function
does not mean that the function itself changes some floating-point
control mode. Supporting these locations in the Attributor requires
additional considerations and, probably, new attributes.

The meaning of `MemoryEffects::onlyAccessesInaccessibleMem` is changed
in this commit. Now this method checks not only the "inaccessible
memory" but also floating-point environment. This change agrees with the
current usage of the method in the compiler sources and will hopefully
reduce the risk on misuse.

This change only introduces the new memory locations. Their use in the
functions that access the floating-point environment will be implemented
in another commit.

This MR was obtained from
https://github.com/llvm/llvm-project/pull/221754 by keeping only the
changes required to introduce the new memory locations only.
---
 llvm/include/llvm/AsmParser/LLToken.h         |  2 +
 llvm/include/llvm/Support/ModRef.h            | 76 +++++++++++++++++--
 llvm/include/llvm/Transforms/IPO/Attributor.h |  4 +-
 llvm/lib/Analysis/AliasAnalysis.cpp           |  2 +
 llvm/lib/Analysis/BasicAliasAnalysis.cpp      |  7 +-
 llvm/lib/Analysis/GlobalsModRef.cpp           |  2 +-
 llvm/lib/AsmParser/LLLexer.cpp                |  2 +
 llvm/lib/AsmParser/LLParser.cpp               |  9 ++-
 llvm/lib/IR/Attributes.cpp                    | 40 +++++++---
 llvm/lib/Support/ModRef.cpp                   |  6 ++
 llvm/lib/Transforms/IPO/Attributor.cpp        |  4 +-
 .../Transforms/IPO/AttributorAttributes.cpp   |  8 +-
 llvm/lib/Transforms/IPO/FunctionAttrs.cpp     |  2 +-
 .../Instrumentation/AddressSanitizer.cpp      |  2 +
 .../test/Assembler/memory-attribute-errors.ll |  6 +-
 llvm/test/Assembler/memory-attribute.ll       | 30 ++++++++
 llvm/unittests/Support/ModRefTest.cpp         |  3 +-
 17 files changed, 172 insertions(+), 33 deletions(-)

diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index 5624410497ac8..7ce7004e39df1 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -212,6 +212,8 @@ enum Kind {
   kw_target_mem0,
   kw_target_mem1,
   kw_errnomem,
+  kw_fpcontrol,
+  kw_fpstatus,
 
   // Legacy attributes:
   kw_argmemonly,
diff --git a/llvm/include/llvm/Support/ModRef.h b/llvm/include/llvm/Support/ModRef.h
index 83091c617f629..91bcebff7ee08 100644
--- a/llvm/include/llvm/Support/ModRef.h
+++ b/llvm/include/llvm/Support/ModRef.h
@@ -69,10 +69,15 @@ enum class IRMemLocation {
   /// Represents target specific state.
   TargetMem0 = 4,
   TargetMem1 = 5,
+  /// Floating-point control modes.
+  FPControl = 6,
+  /// Floating-point status bits.
+  FPStatus = 7,
 
   /// Helpers to iterate all locations in the MemoryEffectsBase class.
   First = ArgMem,
-  Last = TargetMem1,
+  LastMem = TargetMem1,
+  Last = FPStatus,
 };
 
 template <typename LocationEnum> class MemoryEffectsBase {
@@ -102,11 +107,22 @@ template <typename LocationEnum> class MemoryEffectsBase {
     return enum_seq_inclusive(Location::First, Location::Last,
                               force_iteration_on_noniterable_enum);
   }
+  /// Returns iterator over all supported memory location kinds, without
+  /// floating-point registers.
+  static auto mem_locations() {
+    return enum_seq_inclusive(Location::First, Location::LastMem,
+                              force_iteration_on_noniterable_enum);
+  }
   /// Returns iterator over all target location kinds
   static auto targetMemLocations() {
     return enum_seq_inclusive(Location::TargetMem0, Location::TargetMem1,
                               force_iteration_on_noniterable_enum);
   }
+  /// Returns iterator over floating-point state locations.
+  static auto fpenvLocations() {
+    return enum_seq_inclusive(Location::FPControl, Location::FPStatus,
+                              force_iteration_on_noniterable_enum);
+  }
 
   /// Create MemoryEffectsBase that can access only the given location with the
   /// given ModRefInfo.
@@ -119,24 +135,42 @@ template <typename LocationEnum> class MemoryEffectsBase {
       setModRef(Loc, MR);
   }
 
+  /// Create MemoryEffectsBase that can access any location with the given
+  /// ModRefInfo, excluding floating-point locations.
+  /// The boolean argument value is not used, it only allows to distinguish
+  /// between constructors.
+  MemoryEffectsBase(ModRefInfo MR, bool NoFPEnvMarker) {
+    (void)NoFPEnvMarker;
+    for (Location Loc : mem_locations())
+      setModRef(Loc, MR);
+  }
+
   /// Create MemoryEffectsBase that can read and write any memory.
   static MemoryEffectsBase unknown() {
     return MemoryEffectsBase(ModRefInfo::ModRef);
   }
 
+  /// Create MemoryEffectsBase that can read and write any memory except
+  /// floating-point registers.
+  static MemoryEffectsBase unknown_mem() {
+    return MemoryEffectsBase(ModRefInfo::ModRef, /*NoFPEnvMarker*/ true);
+  }
+
   /// Create MemoryEffectsBase that cannot read or write any memory.
   static MemoryEffectsBase none() {
     return MemoryEffectsBase(ModRefInfo::NoModRef);
   }
 
-  /// Create MemoryEffectsBase that can read any memory.
+  /// Create MemoryEffectsBase that can read any memory excluding floating-point
+  /// registers.
   static MemoryEffectsBase readOnly() {
-    return MemoryEffectsBase(ModRefInfo::Ref);
+    return MemoryEffectsBase(ModRefInfo::Ref, /*NoFPEnvMarker*/ true);
   }
 
-  /// Create MemoryEffectsBase that can write any memory.
+  /// Create MemoryEffectsBase that can write any memory excluding
+  /// floating-point registers.
   static MemoryEffectsBase writeOnly() {
-    return MemoryEffectsBase(ModRefInfo::Mod);
+    return MemoryEffectsBase(ModRefInfo::Mod, /*NoFPEnvMarker*/ true);
   }
 
   /// Create MemoryEffectsBase that can only access argument memory.
@@ -160,6 +194,14 @@ template <typename LocationEnum> class MemoryEffectsBase {
     return MemoryEffectsBase(Location::Other, MR);
   }
 
+  /// Create MemoryEffectsBase that can only access floating-point state
+  /// register.
+  static MemoryEffectsBase
+  fpenvironmentOnly(ModRefInfo MR = ModRefInfo::ModRef) {
+    return MemoryEffectsBase(Location::FPControl, MR) |
+           MemoryEffectsBase(Location::FPStatus, MR);
+  }
+
   /// Create MemoryEffectsBase that can only access inaccessible or argument
   /// memory.
   static MemoryEffectsBase
@@ -261,9 +303,13 @@ template <typename LocationEnum> class MemoryEffectsBase {
     return isModOrRefSet(getModRef(Location::ArgMem));
   }
 
-  /// Whether this function only (at most) accesses inaccessible memory.
+  /// Whether this function only (at most) accesses memory that cannot be
+  /// addressed by any pointer.
   bool onlyAccessesInaccessibleMem() const {
-    return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory();
+    return getWithoutLoc(Location::InaccessibleMem)
+        .getWithoutLoc(Location::FPControl)
+        .getWithoutLoc(Location::FPStatus)
+        .doesNotAccessMemory();
   }
 
   /// Whether this function only (at most) accesses inaccessible or target
@@ -295,6 +341,22 @@ template <typename LocationEnum> class MemoryEffectsBase {
     return true;
   }
 
+  /// Whether location represents floating-point environment.
+  static bool isFPEnvMemLoc(IRMemLocation Loc) {
+    for (auto L : fpenvLocations())
+      if (Loc == L)
+        return true;
+    return false;
+  }
+
+  /// Whether all floating-point locations are not accessed.
+  bool doesNotAccessFPEnv() const {
+    for (auto L : fpenvLocations())
+      if (getModRef(L) != ModRefInfo::NoModRef)
+        return false;
+    return true;
+  }
+
   /// Whether this function only (at most) accesses errno memory.
   bool onlyAccessesErrnoMem() const {
     return getWithoutLoc(Location::ErrnoMem).doesNotAccessMemory();
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 066883afafb95..300ab39cac410 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -3554,7 +3554,7 @@ struct AANoSync
     SmallVector<Attribute, 2> Attrs;
     A.getAttrs(IRP, {Attribute::Memory}, Attrs, IgnoreSubsumingPositions);
 
-    MemoryEffects ME = MemoryEffects::unknown();
+    MemoryEffects ME = MemoryEffects::unknown_mem();
     for (const Attribute &Attr : Attrs)
       ME &= Attr.getMemoryEffects();
 
@@ -3771,7 +3771,7 @@ struct AAWillReturn
     A.getAttrs(IRP, {Attribute::Memory}, Attrs,
                /* IgnoreSubsumingPositions */ false);
 
-    MemoryEffects ME = MemoryEffects::unknown();
+    MemoryEffects ME = MemoryEffects::unknown_mem();
     for (const Attribute &Attr : Attrs)
       ME &= Attr.getMemoryEffects();
     return ME.onlyReadsMemory();
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index f2b73c974a35c..05b784482d8ed 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -263,6 +263,8 @@ getModRefInfoInaccessibleAndTargetMemLoc(const MemoryEffects CallUse,
   };
 
   addModRefInfoForLoc(IRMemLocation::InaccessibleMem);
+  for (auto Loc : MemoryEffects::fpenvLocations())
+    addModRefInfoForLoc(Loc);
   for (auto Loc : MemoryEffects::targetMemLocations())
     addModRefInfoForLoc(Loc);
   return Result;
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index fd9a7bb935170..72cf1ac8dfb80 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -971,9 +971,12 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
       return ModRefInfo::Mod;
 
   // We can completely ignore inaccessible memory here, because MemoryLocations
-  // can only reference accessible memory.
+  // can only reference accessible memory. The same is true for floating-point
+  // registers.
   auto ME = AAQI.AAR.getMemoryEffects(Call, AAQI)
-                .getWithoutLoc(IRMemLocation::InaccessibleMem);
+                .getWithoutLoc(IRMemLocation::InaccessibleMem)
+                .getWithoutLoc(IRMemLocation::FPControl)
+                .getWithoutLoc(IRMemLocation::FPStatus);
   if (ME.doesNotAccessMemory())
     return ModRefInfo::NoModRef;
 
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp
index 059ebed787c6b..eb2ba3eba80e6 100644
--- a/llvm/lib/Analysis/GlobalsModRef.cpp
+++ b/llvm/lib/Analysis/GlobalsModRef.cpp
@@ -237,7 +237,7 @@ void GlobalsAAResult::DeletionCallbackHandle::deleted() {
 
 MemoryEffects GlobalsAAResult::getMemoryEffects(const Function *F) {
   if (FunctionInfo *FI = getFunctionInfo(F))
-    return MemoryEffects(FI->getModRefInfo());
+    return MemoryEffects(FI->getModRefInfo(), /*NoFPEnvMarker*/ true);
 
   return MemoryEffects::unknown();
 }
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 97362c614091c..0c36736e248ec 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -727,6 +727,8 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(target_mem);
   KEYWORD(inaccessiblemem);
   KEYWORD(errnomem);
+  KEYWORD(fpcontrol);
+  KEYWORD(fpstatus);
   KEYWORD(argmemonly);
   KEYWORD(inaccessiblememonly);
   KEYWORD(inaccessiblemem_or_argmemonly);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 408d79fe3402f..02d523d783044 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -2760,6 +2760,10 @@ static SmallVector<MemoryEffects::Location, 2> keywordToLoc(lltok::Kind Tok) {
     return {Loc::InaccessibleMem};
   case lltok::kw_errnomem:
     return {Loc::ErrnoMem};
+  case lltok::kw_fpcontrol:
+    return {Loc::FPControl};
+  case lltok::kw_fpstatus:
+    return {Loc::FPStatus};
   case lltok::kw_target_mem0:
     return {Loc::TargetMem0};
   case lltok::kw_target_mem1:
@@ -2835,7 +2839,8 @@ std::optional<MemoryEffects> LLParser::parseMemoryAttr() {
     std::optional<ModRefInfo> MR = keywordToModRef(Lex.getKind());
     if (!MR) {
       if (Locs.empty())
-        tokError("expected memory location (argmem, inaccessiblemem, errnomem) "
+        tokError("expected memory location (argmem, inaccessiblemem, errnomem, "
+                 "fpcontrol, fpstatus) "
                  "or access kind (none, read, write, readwrite)");
       else
         tokError("expected access kind (none, read, write, readwrite)");
@@ -2860,7 +2865,7 @@ std::optional<MemoryEffects> LLParser::parseMemoryAttr() {
         tokError("default access kind must be specified first");
         return std::nullopt;
       }
-      ME = MemoryEffects(*MR);
+      ME = MemoryEffects(*MR, /*NoFPEnvMarker*/ false);
     }
 
     if (EatIfPresent(lltok::rparen))
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 7f5f5f34af389..313d38afe3989 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -644,13 +644,31 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
       OS << getModRefStr(OtherMR);
     }
 
-    bool TargetPrintedForAll = false;
+    bool SkipLocGroup = false;
+    IRMemLocation LastToSkip;
     for (auto Loc : MemoryEffects::locations()) {
       ModRefInfo MR = ME.getModRef(Loc);
-      if (MR == OtherMR)
+      if (MR == OtherMR && !MemoryEffects::isFPEnvMemLoc(Loc))
         continue;
 
-      if (!First && !TargetPrintedForAll)
+      if (SkipLocGroup) {
+        if (Loc == LastToSkip)
+          SkipLocGroup = false;
+        continue;
+      }
+
+      if (MemoryEffects::isFPEnvMemLoc(Loc)) {
+        // If access to a floating-point location is absent, do not print it.
+        if (ME.doesNotAccessFPEnv()) {
+          SkipLocGroup = true;
+          LastToSkip = IRMemLocation::FPStatus;
+          continue;
+        }
+        if (ME.getModRef(Loc) == ModRefInfo::NoModRef)
+          continue;
+      }
+
+      if (!First && !SkipLocGroup)
         OS << ", ";
       First = false;
 
@@ -658,12 +676,10 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
       // If more targets are added it should do something like:
       // memory(target_mem:read, target_mem3:none, target_mem5:write).
       if (ME.isTargetMemLoc(Loc) && ME.isTargetMemLocSameForAll()) {
-        if (!TargetPrintedForAll) {
-          OS << "target_mem: ";
-          OS << getModRefStr(MR);
-          TargetPrintedForAll = true;
-        }
-        // Only works when target memories are last to be listed in Location.
+        OS << "target_mem: ";
+        OS << getModRefStr(MR);
+        SkipLocGroup = true;
+        LastToSkip = IRMemLocation::TargetMem1;
         continue;
       }
 
@@ -685,6 +701,12 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
       case IRMemLocation::TargetMem1:
         OS << "target_mem1: ";
         break;
+      case IRMemLocation::FPControl:
+        OS << "fpcontrol: ";
+        break;
+      case IRMemLocation::FPStatus:
+        OS << "fpstatus: ";
+        break;
       }
       OS << getModRefStr(MR);
     }
diff --git a/llvm/lib/Support/ModRef.cpp b/llvm/lib/Support/ModRef.cpp
index 1083c72902c0b..43dbe9d068df0 100644
--- a/llvm/lib/Support/ModRef.cpp
+++ b/llvm/lib/Support/ModRef.cpp
@@ -55,6 +55,12 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, MemoryEffects ME) {
     case IRMemLocation::TargetMem1:
       OS << "TargetMem1: ";
       break;
+    case IRMemLocation::FPControl:
+      OS << "FPControl: ";
+      break;
+    case IRMemLocation::FPStatus:
+      OS << "FPStatus: ";
+      break;
     }
     OS << ME.getModRef(Loc);
   });
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 338240b2f8087..f89e00398c297 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -3116,7 +3116,9 @@ ChangeStatus Attributor::rewriteFunctionSignatures(
           return !T->isPtrOrPtrVectorTy() ||
                  NewFn->hasParamAttribute(ArgNo, Attribute::ReadNone);
         })) {
-      NewFn->setMemoryEffects(ME - MemoryEffects::argMemOnly());
+      ME -= MemoryEffects::argMemOnly();
+      ME -= MemoryEffects::fpenvironmentOnly();
+      NewFn->setMemoryEffects(ME);
     }
 
     // Since we have now created the new function, splice the body of the old
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index c2a896be0064d..6e181603318cc 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -8196,7 +8196,7 @@ struct AAMemoryBehaviorFunction final : public AAMemoryBehaviorImpl {
     // we could determine read/write per location. This would also have the
     // benefit of only one place trying to manifest the memory attribute.
     Function &F = cast<Function>(getAnchorValue());
-    MemoryEffects ME = MemoryEffects::unknown();
+    MemoryEffects ME = MemoryEffects::unknown_mem();
     if (isAssumedReadNone())
       ME = MemoryEffects::none();
     else if (isAssumedReadOnly())
@@ -8234,7 +8234,7 @@ struct AAMemoryBehaviorCallSite final
   ChangeStatus manifest(Attributor &A) override {
     // TODO: Deduplicate this with AAMemoryBehaviorFunction.
     CallBase &CB = cast<CallBase>(getAnchorValue());
-    MemoryEffects ME = MemoryEffects::unknown();
+    MemoryEffects ME = MemoryEffects::unknown_mem();
     if (isAssumedReadNone())
       ME = MemoryEffects::none();
     else if (isAssumedReadOnly())
@@ -8558,7 +8558,7 @@ struct AAMemoryLocationImpl : public AAMemoryLocation {
           State.addKnownBits(inverseLocation(NO_ARGUMENT_MEM, true, true));
         else {
           // Remove location information, only keep read/write info.
-          ME = MemoryEffects(ME.getModRef());
+          ME = MemoryEffects(ME.getModRef(), /*NoFPEnvMarker*/ true);
           A.manifestAttrs(IRP,
                           Attribute::getWithMemoryEffects(
                               IRP.getAnchorValue().getContext(), ME),
@@ -8572,7 +8572,7 @@ struct AAMemoryLocationImpl : public AAMemoryLocation {
               NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM, true, true));
         else {
           // Remove location information, only keep read/write info.
-          ME = MemoryEffects(ME.getModRef());
+          ME = MemoryEffects(ME.getModRef(), /*NoFPEnvMarker*/ true);
           A.manifestAttrs(IRP,
                           Attribute::getWithMemoryEffects(
                               IRP.getAnchorValue().getContext(), ME),
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index a713ead683476..cb7e9e32a0bc6 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -285,7 +285,7 @@ static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
     ME |= FnME;
     RecursiveArgME |= FnRecursiveArgME;
     // Reached bottom of the lattice, we will not be able to improve the result.
-    if (ME == MemoryEffects::unknown())
+    if (ME == MemoryEffects::unknown_mem())
       return;
   }
 
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 3e9b0b3d39c47..d9b143676e163 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -655,6 +655,8 @@ void llvm::removeASanIncompatibleFnAttributes(Function &F, bool ReadsArgMem) {
   // memory.
   if (!F.getMemoryEffects()
            .getWithoutLoc(IRMemLocation::InaccessibleMem)
+           .getWithoutLoc(IRMemLocation::FPControl)
+           .getWithoutLoc(IRMemLocation::FPStatus)
            .doesNotAccessMemory() &&
       !isModAndRefSet(F.getMemoryEffects().getModRef(IRMemLocation::Other))) {
     F.setMemoryEffects(F.getMemoryEffects() |
diff --git a/llvm/test/Assembler/memory-attribute-errors.ll b/llvm/test/Assembler/memory-attribute-errors.ll
index cf8690e07678e..f581247be185a 100644
--- a/llvm/test/Assembler/memory-attribute-errors.ll
+++ b/llvm/test/Assembler/memory-attribute-errors.ll
@@ -13,16 +13,16 @@
 ; MISSING-ARGS: error: expected '('
 declare void @fn() memory
 ;--- empty.ll
-; EMPTY: error: expected memory location (argmem, inaccessiblemem, errnomem) or access kind (none, read, write, readwrite)
+; EMPTY: error: expected memory location (argmem, inaccessiblemem, errnomem, fpcontrol, fpstatus) or access kind (none, read, write, readwrite)
 declare void @fn() memory()
 ;--- unterminated.ll
 ; UNTERMINATED: error: unterminated memory attribute
 declare void @fn() memory(read
 ;--- invalid-kind.ll
-; INVALID-KIND: error: expected memory location (argmem, inaccessiblemem, errnomem) or access kind (none, read, write, readwrite)
+; INVALID-KIND: error: expected memory location (argmem, inaccessiblemem, errnomem, fpcontrol, fpstatus) or access kind (none, read, write, readwrite)
 declare void @fn() memory(foo)
 ;--- other.ll
-; OTHER: error: expected memory location (argmem, inaccessiblemem, errnomem) or access kind (none, read, write, readwrite)
+; OTHER: error: expected memory location (argmem, inaccessiblemem, errnomem, fpcontrol, fpstatus) or access kind (none, read, write, readwrite)
 declare void @fn() memory(other: read)
 ;--- missing-colon.ll
 ; MISSING-COLON: error: expected ':' after location
diff --git a/llvm/test/Assembler/memory-attribute.ll b/llvm/test/Assembler/memory-attribute.ll
index fd98384d90405..614ee14d5586d 100644
--- a/llvm/test/Assembler/memory-attribute.ll
+++ b/llvm/test/Assembler/memory-attribute.ll
@@ -148,3 +148,33 @@ declare void @fn_write_target_mem_read_write()
 ; CHECK: @fn_all_readwrite
 declare void @fn_all_readwrite()
     memory(readwrite, target_mem: read)
+
+; CHECK: Function Attrs: memory(fpcontrol: read)
+; CHECK: @fn_read_fpcontrol
+declare void @fn_read_fpcontrol()
+    memory(fpcontrol: read)
+
+; CHECK: Function Attrs: memory(fpcontrol: write)
+; CHECK: @fn_write_fpcontrol
+declare void @fn_write_fpcontrol()
+    memory(fpcontrol: write)
+
+; CHECK: Function Attrs: memory(fpstatus: read)
+; CHECK: @fn_read_fpstatus
+declare void @fn_read_fpstatus()
+    memory(fpstatus: read)
+
+; CHECK: Function Attrs: memory(fpstatus: readwrite)
+; CHECK: @fn_readwrite_fpstatus
+declare void @fn_readwrite_fpstatus()
+    memory(fpstatus: readwrite)
+
+; CHECK: Function Attrs: memory(fpcontrol: read, fpstatus: readwrite)
+; CHECK: @fn_read_fpcontrol_readwrite_fpstatus
+declare void @fn_read_fpcontrol_readwrite_fpstatus()
+    memory(fpcontrol: read, fpstatus: readwrite)
+
+; CHECK: Function Attrs: memory(write, fpcontrol: read)
+; CHECK: @fn_read_fpcontrol_write_mem
+declare void @fn_read_fpcontrol_write_mem()
+    memory(write, fpcontrol: read)
diff --git a/llvm/unittests/Support/ModRefTest.cpp b/llvm/unittests/Support/ModRefTest.cpp
index 128501bf2d957..bbb1048729453 100644
--- a/llvm/unittests/Support/ModRefTest.cpp
+++ b/llvm/unittests/Support/ModRefTest.cpp
@@ -21,7 +21,8 @@ TEST(ModRefTest, PrintMemoryEffects) {
   raw_string_ostream OS(S);
   OS << MemoryEffects::none();
   EXPECT_EQ(S, "ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: "
-               "NoModRef, Other: NoModRef, TargetMem0: NoModRef, TargetMem1: NoModRef");
+               "NoModRef, Other: NoModRef, TargetMem0: NoModRef, "
+               "TargetMem1: NoModRef, FPControl: NoModRef, FPStatus: NoModRef");
 }
 
 } // namespace



More information about the llvm-commits mailing list