[llvm] Reland: Port Swift's merge function pass to llvm: merging functions that differ in constants (PR #71584)

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 7 12:33:11 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Manman Ren (manman-ren)

<details>
<summary>Changes</summary>

This patch is based on the initial PR: https://github.com/llvm/llvm-project/pull/68235 and the follow-up PR: https://github.com/llvm/llvm-project/pull/71219.

PR68235 was merged and got reverted because folks think it is not adequately reviewed.

See RFC for details:
https://discourse.llvm.org/t/rfc-for-moving-swift-s-merge-function-pass-to-llvm/73778

This pass has been in Swift repo for a while, it has significant size win on C++ and ObjectiveC as well. As a first step, we are porting it over to llvm. We also have plans on supporting global function merging using Hashes.

On top of #<!-- -->68235 and #<!-- -->71219, this patch also addresses review comments:
-- Remove typed pointer usages from test cases
-- Remove pointer authentication support
-- Drop llvm:: prefixes

---

Patch is 73.97 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71584.diff


12 Files Affected:

- (added) llvm/include/llvm/Transforms/IPO/MergeFunctionsIgnoringConst.h (+37) 
- (modified) llvm/include/llvm/Transforms/Utils/FunctionComparator.h (+1) 
- (added) llvm/include/llvm/Transforms/Utils/FunctionComparatorIgnoringConst.h (+58) 
- (added) llvm/include/llvm/Transforms/Utils/MergeFunctionsIgnoringConst.h (+29) 
- (modified) llvm/lib/Passes/PassBuilder.cpp (+1) 
- (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+11) 
- (modified) llvm/lib/Passes/PassRegistry.def (+1) 
- (modified) llvm/lib/Transforms/IPO/CMakeLists.txt (+1) 
- (added) llvm/lib/Transforms/IPO/MergeFunctionsIgnoringConst.cpp (+1187) 
- (modified) llvm/lib/Transforms/Utils/CMakeLists.txt (+1) 
- (added) llvm/lib/Transforms/Utils/FunctionComparatorIgnoringConst.cpp (+164) 
- (added) llvm/test/Transforms/MergeFuncIgnoringConst/merge_func.ll (+532) 


``````````diff
diff --git a/llvm/include/llvm/Transforms/IPO/MergeFunctionsIgnoringConst.h b/llvm/include/llvm/Transforms/IPO/MergeFunctionsIgnoringConst.h
new file mode 100644
index 000000000000000..62cd97db0b84091
--- /dev/null
+++ b/llvm/include/llvm/Transforms/IPO/MergeFunctionsIgnoringConst.h
@@ -0,0 +1,37 @@
+//===- MergeFunctionsIgnoringConst.h - Merge Functions ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass transforms simple global variables that never have their address
+// taken.  If obviously true, it marks read/write globals as constant, deletes
+// variables only stored to, etc.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_IPO_MERGEFUNCTIONSIGNORINGCONST_H
+#define LLVM_TRANSFORMS_IPO_MERGEFUNCTIONSIGNORINGCONST_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class Module;
+
+/// Merge functions that differ by constants.
+class MergeFuncIgnoringConstPass
+    : public PassInfoMixin<MergeFuncIgnoringConstPass> {
+  std::string MergeFuncSuffix = ".Tm";
+
+public:
+  MergeFuncIgnoringConstPass() {}
+  MergeFuncIgnoringConstPass(std::string Suffix) : MergeFuncSuffix(Suffix) {}
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_IPO_MERGEFUNCTIONSIGNORINGCONST_H
diff --git a/llvm/include/llvm/Transforms/Utils/FunctionComparator.h b/llvm/include/llvm/Transforms/Utils/FunctionComparator.h
index c28f868039a1f7b..1a314b481c72c61 100644
--- a/llvm/include/llvm/Transforms/Utils/FunctionComparator.h
+++ b/llvm/include/llvm/Transforms/Utils/FunctionComparator.h
@@ -379,6 +379,7 @@ class FunctionComparator {
   /// But, we are still not able to compare operands of PHI nodes, since those
   /// could be operands from further BBs we didn't scan yet.
   /// So it's impossible to use dominance properties in general.
+protected:
   mutable DenseMap<const Value*, int> sn_mapL, sn_mapR;
 
   // The global state we will use
diff --git a/llvm/include/llvm/Transforms/Utils/FunctionComparatorIgnoringConst.h b/llvm/include/llvm/Transforms/Utils/FunctionComparatorIgnoringConst.h
new file mode 100644
index 000000000000000..9c7fe3baf2fa0db
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/FunctionComparatorIgnoringConst.h
@@ -0,0 +1,58 @@
+//===- FunctionComparatorIgnoringConst.h - Function Comparator --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the FunctionComparatorIgnoringConst class which is used by
+// the MergeFuncIgnoringConst pass for comparing functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_FUNCTIONCOMPARATORIGNORINGCONST_H
+#define LLVM_TRANSFORMS_UTILS_FUNCTIONCOMPARATORIGNORINGCONST_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/ValueMap.h"
+#include "llvm/Support/AtomicOrdering.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Transforms/Utils/FunctionComparator.h"
+#include <set>
+
+namespace llvm {
+
+/// FunctionComparatorIgnoringConst - Compares two functions to determine
+/// whether or not they match when certain constants are ignored.
+class FunctionComparatorIgnoringConst : public FunctionComparator {
+public:
+  FunctionComparatorIgnoringConst(const Function *F1, const Function *F2,
+                                  GlobalNumberState *GN)
+      : FunctionComparator(F1, F2, GN) {}
+
+  int cmpOperandsIgnoringConsts(const Instruction *L, const Instruction *R,
+                                unsigned opIdx);
+
+  int cmpBasicBlocksIgnoringConsts(
+      const BasicBlock *BBL, const BasicBlock *BBR,
+      const std::set<std::pair<int, int>> *InstOpndIndex = nullptr);
+
+  int compareIgnoringConsts(
+      const std::set<std::pair<int, int>> *InstOpndIndex = nullptr);
+
+  int compareConstants(const Constant *L, const Constant *R) const {
+    return cmpConstants(L, R);
+  }
+
+private:
+  /// Scratch index for instruction in order during cmpOperandsIgnoringConsts.
+  int Index = 0;
+};
+
+} // end namespace llvm
+#endif // LLVM_TRANSFORMS_UTILS_FUNCTIONCOMPARATORIGNORINGCONST_H
diff --git a/llvm/include/llvm/Transforms/Utils/MergeFunctionsIgnoringConst.h b/llvm/include/llvm/Transforms/Utils/MergeFunctionsIgnoringConst.h
new file mode 100644
index 000000000000000..e63afbb6bbf1718
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/MergeFunctionsIgnoringConst.h
@@ -0,0 +1,29 @@
+//===- MergeFunctionsIgnoringConst.h - Merge Functions ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines helpers used in the MergeFunctionsIgnoringConst.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_MERGEFUNCTIONSIGNORINGCONST_H
+#define LLVM_TRANSFORMS_UTILS_MERGEFUNCTIONSIGNORINGCONST_H
+
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Operator.h"
+
+using namespace llvm;
+
+bool isEligibleInstrunctionForConstantSharing(const Instruction *I);
+
+bool isEligibleOperandForConstantSharing(const Instruction *I, unsigned OpIdx);
+
+bool isEligibleFunction(Function *F);
+
+Value *createCast(IRBuilder<> &Builder, Value *V, Type *DestTy);
+#endif // LLVM_TRANSFORMS_UTILS_MERGEFUNCTIONSIGNORINGCONST_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index dd9d799f9d55dcc..f0fb6fe5c67d94a 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -123,6 +123,7 @@
 #include "llvm/Transforms/IPO/LowerTypeTests.h"
 #include "llvm/Transforms/IPO/MemProfContextDisambiguation.h"
 #include "llvm/Transforms/IPO/MergeFunctions.h"
+#include "llvm/Transforms/IPO/MergeFunctionsIgnoringConst.h"
 #include "llvm/Transforms/IPO/ModuleInliner.h"
 #include "llvm/Transforms/IPO/OpenMPOpt.h"
 #include "llvm/Transforms/IPO/PartialInlining.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index f4a4802bcb649f3..29ac6213366463b 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -60,6 +60,7 @@
 #include "llvm/Transforms/IPO/LowerTypeTests.h"
 #include "llvm/Transforms/IPO/MemProfContextDisambiguation.h"
 #include "llvm/Transforms/IPO/MergeFunctions.h"
+#include "llvm/Transforms/IPO/MergeFunctionsIgnoringConst.h"
 #include "llvm/Transforms/IPO/ModuleInliner.h"
 #include "llvm/Transforms/IPO/OpenMPOpt.h"
 #include "llvm/Transforms/IPO/PartialInlining.h"
@@ -176,6 +177,10 @@ static cl::opt<bool> EnableMergeFunctions(
     "enable-merge-functions", cl::init(false), cl::Hidden,
     cl::desc("Enable function merging as part of the optimization pipeline"));
 
+static cl::opt<bool> EnableMergeFuncIgnoringConst(
+    "enable-merge-func-ignoring-const", cl::init(false), cl::Hidden,
+    cl::desc("Enable function merger that ignores constants"));
+
 static cl::opt<bool> EnablePostPGOLoopRotation(
     "enable-post-pgo-loop-rotation", cl::init(true), cl::Hidden,
     cl::desc("Run the loop rotation transformation after PGO instrumentation"));
@@ -1644,6 +1649,9 @@ ModulePassManager PassBuilder::buildThinLTODefaultPipeline(
   MPM.addPass(buildModuleOptimizationPipeline(
       Level, ThinOrFullLTOPhase::ThinLTOPostLink));
 
+  if (EnableMergeFuncIgnoringConst)
+    MPM.addPass(MergeFuncIgnoringConstPass());
+
   // Emit annotation remarks.
   addAnnotationRemarksPass(MPM);
 
@@ -1969,6 +1977,9 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
 
   invokeFullLinkTimeOptimizationLastEPCallbacks(MPM, Level);
 
+  if (EnableMergeFuncIgnoringConst)
+    MPM.addPass(MergeFuncIgnoringConstPass());
+
   // Emit annotation remarks.
   addAnnotationRemarksPass(MPM);
 
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 2067fc473b522db..3dae19c0eb66e45 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -87,6 +87,7 @@ MODULE_PASS("lower-ifunc", LowerIFuncPass())
 MODULE_PASS("lowertypetests", LowerTypeTestsPass())
 MODULE_PASS("metarenamer", MetaRenamerPass())
 MODULE_PASS("mergefunc", MergeFunctionsPass())
+MODULE_PASS("mergefunc-ignoring-const", MergeFuncIgnoringConstPass())
 MODULE_PASS("name-anon-globals", NameAnonGlobalPass())
 MODULE_PASS("no-op-module", NoOpModulePass())
 MODULE_PASS("objc-arc-apelim", ObjCARCAPElimPass())
diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt
index 034f1587ae8df44..4dac04d3369950f 100644
--- a/llvm/lib/Transforms/IPO/CMakeLists.txt
+++ b/llvm/lib/Transforms/IPO/CMakeLists.txt
@@ -30,6 +30,7 @@ add_llvm_component_library(LLVMipo
   LowerTypeTests.cpp
   MemProfContextDisambiguation.cpp
   MergeFunctions.cpp
+  MergeFunctionsIgnoringConst.cpp
   ModuleInliner.cpp
   OpenMPOpt.cpp
   PartialInlining.cpp
diff --git a/llvm/lib/Transforms/IPO/MergeFunctionsIgnoringConst.cpp b/llvm/lib/Transforms/IPO/MergeFunctionsIgnoringConst.cpp
new file mode 100644
index 000000000000000..f5ee17ed0c4fc85
--- /dev/null
+++ b/llvm/lib/Transforms/IPO/MergeFunctionsIgnoringConst.cpp
@@ -0,0 +1,1187 @@
+//===--- MergeFunctionsIgnoringConst.cpp - Merge functions ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass looks for similar functions that are mergeable and folds them.
+// The implementation is similar to LLVM's MergeFunctions pass. Instead of
+// merging identical functions, it merges functions which only differ by a few
+// constants in certain instructions.
+// This is copied from Swift's implementation.
+//
+// This pass should run after LLVM's MergeFunctions pass, because it works best
+// if there are no _identical_ functions in the module.
+// Note: it would also work for identical functions but could produce more
+// code overhead than the LLVM pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/IPO/MergeFunctionsIgnoringConst.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StableHashing.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/ObjCARCUtil.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/StructuralHash.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/IR/ValueMap.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Utils/FunctionComparatorIgnoringConst.h"
+#include "llvm/Transforms/Utils/MergeFunctionsIgnoringConst.h"
+#include <vector>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mergefunc-ignoring-const"
+
+STATISTIC(NumFunctionsMergedIgnoringConst, "Number of functions merged");
+STATISTIC(NumThunksWrittenIgnoringConst, "Number of thunks generated");
+
+static cl::opt<unsigned> NumFunctionsIgnoringConstForSanityCheck(
+    "mergefunc-ignoringconst-sanity",
+    cl::desc("How many functions in module could be used for "
+             "MergeFunctionsIgnoringConst pass sanity check. "
+             "'0' disables this check. Works only with '-debug' key."),
+    cl::init(0), cl::Hidden);
+
+static cl::opt<unsigned> IgnoringConstMergeThreshold(
+    "mergefunc-ignoringconst-threshold",
+    cl::desc("Functions larger than the threshold are considered for merging."
+             "'0' disables function merging at all."),
+    cl::init(15), cl::Hidden);
+
+cl::opt<bool> UseLinkOnceODRLinkageMerging(
+    "use-linkonceodr-linkage-merging", cl::init(false), cl::Hidden,
+    cl::desc(
+        "Use LinkeOnceODR linkage to deduplicate the identical merged function "
+        "(default = off)"));
+
+cl::opt<bool> NoInlineForMergedFunction(
+    "no-inline-merged-function", cl::init(false), cl::Hidden,
+    cl::desc("set noinline for merged function (default = off)"));
+
+static cl::opt<bool>
+    CastArrayType("merge-cast-array-type", cl::init(false), cl::Hidden,
+                  cl::desc("support for casting array type (default = off)"));
+
+static cl::opt<bool> IgnoreMusttailFunction(
+    "ignore-musttail-function", cl::init(false), cl::Hidden,
+    cl::desc(
+        "ignore functions containing callsites with musttail (default = off)"));
+
+static cl::opt<bool> AlwaysCallThunk(
+    "merge-always-call-thunk", cl::init(false), cl::Hidden,
+    cl::desc(
+        "do not replace callsites and always emit a thunk (default = off)"));
+
+static cl::list<std::string> MergeBlockRegexFilters(
+    "merge-block-regex", cl::Optional,
+    cl::desc("Block functions from merging if they match the given "
+             "regular expression"),
+    cl::ZeroOrMore);
+
+static cl::list<std::string> MergeAllowRegexFilters(
+    "merge-allow-regex", cl::Optional,
+    cl::desc("Allow functions from merging if they match the given "
+             "regular expression"),
+    cl::ZeroOrMore);
+
+namespace {
+
+/// MergeFuncIgnoringConst finds functions which only differ by constants in
+/// certain instructions, e.g. resulting from specialized functions of layout
+/// compatible types.
+/// Such functions are merged by replacing the differing constants by a
+/// parameter. The original functions are replaced by thunks which call the
+/// merged function with the specific argument constants.
+///
+class MergeFuncIgnoringConstImpl {
+public:
+  MergeFuncIgnoringConstImpl(std::string Suffix)
+      : FnTree(FunctionNodeCmp(&GlobalNumbers)), MergeFuncSuffix(Suffix) {}
+
+  bool runImpl(Module &M);
+
+private:
+  struct FunctionEntry;
+
+  /// Describes the set of functions which are considered as "equivalent" (i.e.
+  /// only differing by some constants).
+  struct EquivalenceClass {
+    /// The single-linked list of all functions which are a member of this
+    /// equivalence class.
+    FunctionEntry *First;
+
+    /// A very cheap hash, used to early exit if functions do not match.
+    IRHash Hash;
+
+  public:
+    // Note the hash is recalculated potentially multiple times, but it is
+    // cheap.
+    EquivalenceClass(FunctionEntry *First)
+        : First(First), Hash(StructuralHash(*First->F)) {
+      assert(!First->Next);
+    }
+  };
+
+  /// The function comparison operator is provided here so that FunctionNodes do
+  /// not need to become larger with another pointer.
+  class FunctionNodeCmp {
+    GlobalNumberState *GlobalNumbers;
+
+  public:
+    FunctionNodeCmp(GlobalNumberState *GN) : GlobalNumbers(GN) {}
+    bool operator()(const EquivalenceClass &LHS,
+                    const EquivalenceClass &RHS) const {
+      // Order first by hashes, then full function comparison.
+      if (LHS.Hash != RHS.Hash)
+        return LHS.Hash < RHS.Hash;
+      FunctionComparatorIgnoringConst FCmp(LHS.First->F, RHS.First->F,
+                                           GlobalNumbers);
+      return FCmp.compareIgnoringConsts() == -1;
+    }
+  };
+  using FnTreeType = std::set<EquivalenceClass, FunctionNodeCmp>;
+
+  ///
+  struct FunctionEntry {
+    FunctionEntry(Function *F, FnTreeType::iterator I)
+        : F(F), Next(nullptr), NumUnhandledCallees(0), TreeIter(I),
+          IsMerged(false) {}
+
+    /// Back-link to the function.
+    AssertingVH<Function> F;
+
+    /// The next function in its equivalence class.
+    FunctionEntry *Next;
+
+    /// The number of not-yet merged callees. Used to process the merging in
+    /// bottom-up call order.
+    /// This is only valid in the first entry of an equivalence class. The
+    /// counts of all functions in an equivalence class are accumulated in the
+    /// first entry.
+    int NumUnhandledCallees;
+
+    /// The iterator of the function's equivalence class in the FnTree.
+    /// It's FnTree.end() if the function is not in an equivalence class.
+    FnTreeType::iterator TreeIter;
+
+    /// True if this function is already a thunk, calling the merged function.
+    bool IsMerged;
+  };
+
+  /// Describes an operator of a specific instruction.
+  struct OpLocation {
+    Instruction *I;
+    unsigned OpIndex;
+  };
+
+  /// Information for a function. Used during merging.
+  struct FunctionInfo {
+
+    FunctionInfo(Function *F)
+        : F(F), CurrentInst(nullptr), NumParamsNeeded(0) {}
+
+    void init() {
+      CurrentInst = &*F->begin()->begin();
+      NumParamsNeeded = 0;
+    }
+
+    /// Advances the current instruction to the next instruction.
+    void nextInst() {
+      assert(CurrentInst);
+      if (CurrentInst->isTerminator()) {
+        auto BlockIter = std::next(CurrentInst->getParent()->getIterator());
+        if (BlockIter == F->end()) {
+          CurrentInst = nullptr;
+          return;
+        }
+        CurrentInst = &*BlockIter->begin();
+        return;
+      }
+      CurrentInst = &*std::next(CurrentInst->getIterator());
+    }
+
+    Function *F;
+
+    /// The current instruction while iterating over all instructions.
+    Instruction *CurrentInst;
+
+    /// Roughly the number of parameters needed if this function would be
+    /// merged with the first function of the equivalence class.
+    int NumParamsNeeded;
+  };
+
+  using FunctionInfos = SmallVector<FunctionInfo, 8>;
+
+  /// Describes a parameter which we create to parameterize the merged function.
+  struct ParamInfo {
+    /// The value of the parameter for all the functions in the equivalence
+    /// class.
+    SmallVector<Constant *, 8> Values;
+
+    /// All uses of the parameter in the merged function.
+    SmallVector<OpLocation, 16> Uses;
+
+    /// Checks if this parameter can be used to describe an operand in all
+    /// functions of the equivalence class. Returns true if all values match
+    /// the specific instruction operands in all functions.
+    bool matches(const FunctionInfos &FInfos, unsigned OpIdx) const {
+      unsigned NumFuncs = FInfos.size();
+      assert(Values.size() == NumFuncs);
+      for (unsigned Idx = 0; Idx < NumFuncs; ++Idx) {
+        const FunctionInfo &FI = FInfos[Idx];
+        Constant *C = cast<Constant>(FI.CurrentInst->getOperand(OpIdx));
+        if (Values[Idx] != C)
+          return false;
+      }
+      return true;
+    }
+  };
+
+  using ParamInfos = SmallVector<ParamInfo, 16>;
+
+  Module *CurrentModule = nullptr;
+
+  GlobalNumberState GlobalNumbers;
+
+  /// A work queue of functions that may have been modified and should be
+  /// analyzed again.
+  std::vector<WeakTrackingVH> Deferred;
+
+  /// The set of all distinct functions. Use the insert() and remove() methods
+  /// to modify it. The map allows efficient lookup and deferring of Functions.
+  FnTreeType FnTree;
+
+  ValueMap<Function *, FunctionEntry *> FuncEntries;
+
+  std::string MergeFuncSuffix = ".Tm";
+
+  FunctionEntry *getEntry(Function *F) const { return FuncEntries.lookup(F); }
+
+  bool isInEquiva...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list