[llvm] [SimplifyCFG] Supporting hoisting/sinking callbases with differing attrs (PR #109472)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 23 07:30:45 PDT 2024


================
@@ -1591,10 +1591,150 @@ static void hoistLockstepIdenticalDbgVariableRecords(
   }
 }
 
+// See if we can intersect the attributes for two callbases (used for
+// hoisting/sinking).
+static std::optional<AttributeList> tryIntersectAttrs(const CallBase *CB0,
+                                                      const CallBase *CB1) {
+  assert(CB0->getCalledFunction() == CB1->getCalledFunction() &&
+         "Merging attrs for different functions!");
+
+  AttributeList AL0 = CB0->getAttributes();
+  AttributeList AL1 = CB1->getAttributes();
+
+  // Trivial case if attributes match
+  if (AL0 == AL1)
+    return AL0;
+
+  // Otherwise go through all attributes present and make sure they either match
+  // or that dropping them is okay.
+  // Note: At the moment the logic is only concerned with correctness (i.e we
+  // can't sink a callbase with a `ByVal` attr on a param with one that doesn't
+  // have the attr). But there may be some attributes that are not preferable to
+  // drop i.e a certain Range attr might trivialize inlining so intersecting it
+  // with a callbase without the attr might not be profitable.
+  LLVMContext &Ctx = CB0->getContext();
+  auto IntersectAttrs = [&Ctx](AttributeSet AS0,
+                               AttributeSet AS1) -> std::optional<AttrBuilder> {
+    AttrBuilder Intersected(Ctx);
+
+    AttributeSet AllAttrs = AS0.addAttributes(Ctx, AS1);
+    for (Attribute Attr : AllAttrs) {
+      if (!Attr.isValid())
+        return std::nullopt;
+
+      // Only supporting enum attrs for now.
+      if (!Attr.hasKindAsEnum())
+        return std::nullopt;
+
+      Attribute::AttrKind Kind = Attr.getKindAsEnum();
+      bool BothContain = AS0.hasAttribute(Kind) && AS1.hasAttribute(Kind);
+      switch (Kind) {
+      default:
+        // Except for the below attrs we know we can intersect safely, fail if
+        // the attributes don't match.
+        if (!BothContain)
+          return std::nullopt;
+        if (AS0.getAttribute(Kind) != AS1.getAttribute(Kind))
+          return std::nullopt;
+        Intersected.addAttribute(Attr);
+        break;
+        // Attributes that can safely be intersected and can safely be thrown
+        // away.
+      case Attribute::Cold:
+      case Attribute::Hot:
+      case Attribute::MustProgress:
+      case Attribute::NoAlias:
+      case Attribute::NoCallback:
+      case Attribute::NoCapture:
+      case Attribute::NoFree:
+      case Attribute::NoRecurse:
+      case Attribute::NoReturn:
+      case Attribute::NoSync:
+      case Attribute::NoUndef:
+      case Attribute::NoUnwind:
+      case Attribute::NonNull:
+      case Attribute::OptimizeForSize:
+        // TODO: We could merge ReadNone + Readonly -> ReadOnly
+      case Attribute::ReadNone:
+      case Attribute::ReadOnly:
+      case Attribute::Returned:
+      case Attribute::Speculatable:
+      case Attribute::WillReturn:
+      case Attribute::Writable:
+      case Attribute::WriteOnly:
----------------
goldsteinn wrote:

I was looking at doing that originally, decided with the lazy approach. Will do.

https://github.com/llvm/llvm-project/pull/109472


More information about the llvm-commits mailing list