[llvm] ab25ea6 - [AA] Model operand bundles more precisely

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 22 02:15:33 PDT 2022


Author: Nikita Popov
Date: 2022-09-22T11:15:20+02:00
New Revision: ab25ea6d357e0446bc53cbc6a7372fc79f24740d

URL: https://github.com/llvm/llvm-project/commit/ab25ea6d357e0446bc53cbc6a7372fc79f24740d
DIFF: https://github.com/llvm/llvm-project/commit/ab25ea6d357e0446bc53cbc6a7372fc79f24740d.diff

LOG: [AA] Model operand bundles more precisely

Based on D130896, we can model operand bundles more precisely. In
addition to the baseline ModRefBehavior, a reading/clobbering operand
bundle may also read/write all locations. For example, a memcpy with
deopt bundle can read any memory, but only write argument memory.

This means that getModRefInfo() for memcpy with a pointer that does
not alias the arguments results in Ref, rather than ModRef, without
the need to implement any special handling.

Differential Revision: https://reviews.llvm.org/D130980

Added: 
    

Modified: 
    llvm/lib/Analysis/AliasAnalysis.cpp
    llvm/lib/Analysis/BasicAliasAnalysis.cpp
    llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index 85d17d0ba3a67..2a2b49fdf7e42 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -235,35 +235,37 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call,
 
   // 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 (MRB.onlyAccessesInaccessibleMem())
-    return ModRefInfo::NoModRef;
 
-  // TODO: Exclude inaccessible memory location here.
-  Result &= MRB.getModRef();
+  // We can completely ignore inaccessible memory here, because MemoryLocations
+  // can only reference accessible memory.
+  auto MRB = getModRefBehavior(Call).getWithoutLoc(
+      FunctionModRefBehavior::InaccessibleMem);
+  if (MRB.doesNotAccessMemory())
+    return ModRefInfo::NoModRef;
 
-  if (MRB.onlyAccessesArgPointees() || MRB.onlyAccessesInaccessibleOrArgMem()) {
+  ModRefInfo ArgMR = MRB.getModRef(FunctionModRefBehavior::ArgMem);
+  ModRefInfo OtherMR =
+      MRB.getWithoutLoc(FunctionModRefBehavior::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
+    // on the final result.
     ModRefInfo AllArgsMask = ModRefInfo::NoModRef;
-    if (MRB.doesAccessArgPointees()) {
-      for (const auto &I : llvm::enumerate(Call->args())) {
-        const Value *Arg = I.value();
-        if (!Arg->getType()->isPointerTy())
-          continue;
-        unsigned ArgIdx = I.index();
-        MemoryLocation ArgLoc =
-            MemoryLocation::getForArgument(Call, ArgIdx, TLI);
-        AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI);
-        if (ArgAlias != AliasResult::NoAlias)
-          AllArgsMask |= getArgModRefInfo(Call, ArgIdx);
-      }
+    for (const auto &I : llvm::enumerate(Call->args())) {
+      const Value *Arg = I.value();
+      if (!Arg->getType()->isPointerTy())
+        continue;
+      unsigned ArgIdx = I.index();
+      MemoryLocation ArgLoc = MemoryLocation::getForArgument(Call, ArgIdx, TLI);
+      AliasResult ArgAlias = alias(ArgLoc, Loc, AAQI);
+      if (ArgAlias != AliasResult::NoAlias)
+        AllArgsMask |= getArgModRefInfo(Call, ArgIdx);
     }
-    // Return NoModRef if no alias found with any argument.
-    if (isNoModRef(AllArgsMask))
-      return ModRefInfo::NoModRef;
-    // Logical & between other AA analyses and argument analysis.
-    Result &= AllArgsMask;
+    ArgMR &= AllArgsMask;
   }
 
+  Result &= ArgMR | OtherMR;
+
   // If Loc is a constant memory location, the call definitely could not
   // modify the memory location.
   if (isModSet(Result) && pointsToConstantMemory(Loc, AAQI, /*OrLocal*/ false))

diff  --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 965a1faf85be2..c0e373f38b429 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -769,12 +769,16 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const CallBase *Call) {
   else if (Call->onlyAccessesInaccessibleMemOrArgMem())
     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 &= getBestAAResults().getModRefBehavior(F);
+  if (const Function *F = Call->getCalledFunction()) {
+    FunctionModRefBehavior FMRB = getBestAAResults().getModRefBehavior(F);
+    // Operand bundles on the call may also read or write memory, in addition
+    // to the behavior of the called function.
+    if (Call->hasReadingOperandBundles())
+      FMRB |= FunctionModRefBehavior::readOnly();
+    if (Call->hasClobberingOperandBundles())
+      FMRB |= FunctionModRefBehavior::writeOnly();
+    Min &= FMRB;
+  }
 
   return Min;
 }
@@ -976,26 +980,6 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
       return ModRefInfo::NoModRef;
   }
 
-  // Ideally, there should be no need to special case for memcpy/memove
-  // intrinsics here since general machinery (based on memory attributes) should
-  // already handle it just fine. Unfortunately, it doesn't due to deficiency in
-  // operand bundles support. At the moment it's not clear if complexity behind
-  // enhancing general mechanism worths it.
-  // TODO: Consider improving operand bundles support in general mechanism.
-  if (auto *Inst = dyn_cast<AnyMemTransferInst>(Call)) {
-    AliasResult SrcAA =
-        getBestAAResults().alias(MemoryLocation::getForSource(Inst), Loc, AAQI);
-    AliasResult DestAA =
-        getBestAAResults().alias(MemoryLocation::getForDest(Inst), Loc, AAQI);
-    // It's also possible for Loc to alias both src and dest, or neither.
-    ModRefInfo rv = ModRefInfo::NoModRef;
-    if (SrcAA != AliasResult::NoAlias || Call->hasReadingOperandBundles())
-      rv |= ModRefInfo::Ref;
-    if (DestAA != AliasResult::NoAlias || Call->hasClobberingOperandBundles())
-      rv |= ModRefInfo::Mod;
-    return rv;
-  }
-
   // Guard intrinsics are marked as arbitrarily writing so that proper control
   // dependencies are maintained but they never mods any particular memory
   // location.

diff  --git a/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll b/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll
index 7b1ba1fd79c75..1c58838ade33e 100644
--- a/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll
+++ b/llvm/test/Feature/OperandBundles/basic-aa-argmemonly.ll
@@ -33,19 +33,14 @@ define i32 @test2(i32* %P, i32* noalias %P2) {
 ; heap, but they don't write to any location in the heap if the callee does not
 ; deoptimize the caller.  This fact, combined with the fact that
 ; @argmemonly_function is, well, an argmemonly function, can be used to conclude
-; that %P is not written to at the callsite.  However LLVM currently cannot
-; describe the "does not write to non-args, and reads the entire heap" effect on
-; a callsite.
+; that %P is not written to at the callsite.
 
 ; CHECK-LABEL: @test2(
   %v1 = load i32, i32* %P
-; CHECK: %v1 = load i32, i32* %P
   call void @argmemonly_function(i32* %P2) [ "deopt"() ]
 ; CHECK: call void @argmemonly_function(
   %v2 = load i32, i32* %P
-; CHECK: %v2 = load i32, i32* %P
   %
diff  = sub i32 %v1, %v2
-; CHECK: %
diff  = sub i32 %v1, %v2
   ret i32 %
diff 
-; CHECK: ret i32 %
diff 
+; CHECK: ret i32 0
 }


        


More information about the llvm-commits mailing list