[BasicAA] Clean up calculation of FMRB from attributes
authorNikita Popov <npopov@redhat.com>
Thu, 22 Sep 2022 15:16:48 +0000 (17:16 +0200)
committerNikita Popov <npopov@redhat.com>
Fri, 23 Sep 2022 10:05:35 +0000 (12:05 +0200)
The current implementation for call sites is pretty convoluted
when you take the underlying implementation of the used APIs
into account. We will query the call site attributes, and then
fall back to the function attributes while taking into account
operand bundles. However, getModRefBehavior() already has it's
own (more accurate) logic for combining call-site FMRB with
function FMRB.

Clean this up by extracting a function that only fetches FMRB
from attributes, which can be directly used in getModRefBehavior()
for functions, and needs to be combined with an operand-bundle
respecting fallback in the call site case.

One caveat (that makes this non-NFC) is that CallBase function
attribute lookups allow using attributes from functions with
mismatching signature. To ensure we don't regress quality, do
the same for the function FMRB fallback.

llvm/lib/Analysis/BasicAliasAnalysis.cpp

index 0641342..bb5a23b 100644 (file)
@@ -747,29 +747,31 @@ static bool isIntrinsicCall(const CallBase *Call, Intrinsic::ID IID) {
   return II && II->getIntrinsicID() == IID;
 }
 
-/// Returns the behavior when calling the given call site.
-FunctionModRefBehavior BasicAAResult::getModRefBehavior(const CallBase *Call) {
-  if (Call->doesNotAccessMemory())
-    // Can't do better than this.
+static FunctionModRefBehavior getModRefBehaviorFromAttrs(AttributeSet Attrs) {
+  if (Attrs.hasAttribute(Attribute::ReadNone))
     return FunctionModRefBehavior::none();
 
-  // If the callsite knows it only reads memory, don't return worse
-  // than that.
   ModRefInfo MR = ModRefInfo::ModRef;
-  if (Call->onlyReadsMemory())
+  if (Attrs.hasAttribute(Attribute::ReadOnly))
     MR = ModRefInfo::Ref;
-  else if (Call->onlyWritesMemory())
+  else if (Attrs.hasAttribute(Attribute::WriteOnly))
     MR = ModRefInfo::Mod;
 
-  FunctionModRefBehavior Min(MR);
-  if (Call->onlyAccessesArgMemory())
-    Min = FunctionModRefBehavior::argMemOnly(MR);
-  else if (Call->onlyAccessesInaccessibleMemory())
-    Min = FunctionModRefBehavior::inaccessibleMemOnly(MR);
-  else if (Call->onlyAccessesInaccessibleMemOrArgMem())
-    Min = FunctionModRefBehavior::inaccessibleOrArgMemOnly(MR);
+  if (Attrs.hasAttribute(Attribute::ArgMemOnly))
+    return FunctionModRefBehavior::argMemOnly(MR);
+  if (Attrs.hasAttribute(Attribute::InaccessibleMemOnly))
+    return FunctionModRefBehavior::inaccessibleMemOnly(MR);
+  if (Attrs.hasAttribute(Attribute::InaccessibleMemOrArgMemOnly))
+    return FunctionModRefBehavior::inaccessibleOrArgMemOnly(MR);
+  return FunctionModRefBehavior(MR);
+}
+
+/// Returns the behavior when calling the given call site.
+FunctionModRefBehavior BasicAAResult::getModRefBehavior(const CallBase *Call) {
+  FunctionModRefBehavior Min =
+      getModRefBehaviorFromAttrs(Call->getAttributes().getFnAttrs());
 
-  if (const Function *F = Call->getCalledFunction()) {
+  if (const Function *F = dyn_cast<Function>(Call->getCalledOperand())) {
     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.
@@ -786,10 +788,6 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const CallBase *Call) {
 /// Returns the behavior when calling the given function. For use when the call
 /// site is not known.
 FunctionModRefBehavior BasicAAResult::getModRefBehavior(const Function *F) {
-  // If the function declares it doesn't access memory, we can't do better.
-  if (F->doesNotAccessMemory())
-    return FunctionModRefBehavior::none();
-
   switch (F->getIntrinsicID()) {
   case Intrinsic::experimental_guard:
   case Intrinsic::experimental_deoptimize:
@@ -799,20 +797,7 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const Function *F) {
            FunctionModRefBehavior::inaccessibleMemOnly(ModRefInfo::ModRef);
   }
 
-  // If the function declares it only reads memory, go with that.
-  ModRefInfo MR = ModRefInfo::ModRef;
-  if (F->onlyReadsMemory())
-    MR = ModRefInfo::Ref;
-  else if (F->onlyWritesMemory())
-    MR = ModRefInfo::Mod;
-
-  if (F->onlyAccessesArgMemory())
-    return FunctionModRefBehavior::argMemOnly(MR);
-  if (F->onlyAccessesInaccessibleMemory())
-    return FunctionModRefBehavior::inaccessibleMemOnly(MR);
-  if (F->onlyAccessesInaccessibleMemOrArgMem())
-    return FunctionModRefBehavior::inaccessibleOrArgMemOnly(MR);
-  return FunctionModRefBehavior(MR);
+  return getModRefBehaviorFromAttrs(F->getAttributes().getFnAttrs());
 }
 
 /// Returns true if this is a writeonly (i.e Mod only) parameter.