[llvm] 7cfd267 - [OpenMPOPT][NFC] Introducing OMPInformationCache.

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 17 07:57:45 PDT 2020


Author: sstefan1
Date: 2020-06-17T16:56:45+02:00
New Revision: 7cfd267c518aba226b34b7fbfe8db70000b22053

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

LOG: [OpenMPOPT][NFC] Introducing OMPInformationCache.

Summary:
Introduction of OpenMP-specific information cache based on Attributor's `InformationCache`. This should make it easier to share information between them.

Reviewers: jdoerfert, JonChesterfield, hamax97, jhuber6, uenoku

Subscribers: yaxunl, hiraditya, guansong, uenoku, llvm-commits

Tags: #llvm

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

Added: 
    

Modified: 
    llvm/lib/Transforms/IPO/OpenMPOpt.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
index c05a9c6f3e28..9a0e0851822c 100644
--- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
+++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp
@@ -24,6 +24,7 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/Attributor.h"
 #include "llvm/Transforms/Utils/CallGraphUpdater.h"
 
 using namespace llvm;
@@ -51,18 +52,18 @@ static constexpr auto TAG = "[" DEBUG_TYPE "]";
 #endif
 
 namespace {
-struct OpenMPOpt {
-
-  using OptimizationRemarkGetter =
-      function_ref<OptimizationRemarkEmitter &(Function *)>;
 
-  OpenMPOpt(SmallVectorImpl<Function *> &SCC,
-            SmallPtrSetImpl<Function *> &ModuleSlice,
-            CallGraphUpdater &CGUpdater, OptimizationRemarkGetter OREGetter)
-      : M(*(*SCC.begin())->getParent()), SCC(SCC), ModuleSlice(ModuleSlice),
-        OMPBuilder(M), CGUpdater(CGUpdater), OREGetter(OREGetter) {
+/// OpenMP specific information. For now, stores RFIs and ICVs also needed for
+/// Attributor runs.
+struct OMPInformationCache : public InformationCache {
+  OMPInformationCache(Module &M, AnalysisGetter &AG,
+                      BumpPtrAllocator &Allocator, SetVector<Function *> *CGSCC,
+                      SmallPtrSetImpl<Function *> &ModuleSlice)
+      : InformationCache(M, AG, Allocator, CGSCC), ModuleSlice(ModuleSlice),
+        OMPBuilder(M) {
     initializeTypes(M);
     initializeRuntimeFunctions();
+
     OMPBuilder.initialize();
   }
 
@@ -153,6 +154,115 @@ struct OpenMPOpt {
     DenseMap<Function *, std::unique_ptr<UseVector>> UsesMap;
   };
 
+  /// The slice of the module we are allowed to look at.
+  SmallPtrSetImpl<Function *> &ModuleSlice;
+
+  /// An OpenMP-IR-Builder instance
+  OpenMPIRBuilder OMPBuilder;
+
+  /// Map from runtime function kind to the runtime function description.
+  EnumeratedArray<RuntimeFunctionInfo, RuntimeFunction,
+                  RuntimeFunction::OMPRTL___last>
+      RFIs;
+
+  /// Returns true if the function declaration \p F matches the runtime
+  /// function types, that is, return type \p RTFRetType, and argument types
+  /// \p RTFArgTypes.
+  static bool declMatchesRTFTypes(Function *F, Type *RTFRetType,
+                                  SmallVector<Type *, 8> &RTFArgTypes) {
+    // TODO: We should output information to the user (under debug output
+    //       and via remarks).
+
+    if (!F)
+      return false;
+    if (F->getReturnType() != RTFRetType)
+      return false;
+    if (F->arg_size() != RTFArgTypes.size())
+      return false;
+
+    auto RTFTyIt = RTFArgTypes.begin();
+    for (Argument &Arg : F->args()) {
+      if (Arg.getType() != *RTFTyIt)
+        return false;
+
+      ++RTFTyIt;
+    }
+
+    return true;
+  }
+
+  /// Helper to initialize all runtime function information for those defined
+  /// in OpenMPKinds.def.
+  void initializeRuntimeFunctions() {
+    // Helper to collect all uses of the decleration in the UsesMap.
+    auto CollectUses = [&](RuntimeFunctionInfo &RFI) {
+      unsigned NumUses = 0;
+      if (!RFI.Declaration)
+        return NumUses;
+      OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
+
+      NumOpenMPRuntimeFunctionsIdentified += 1;
+      NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
+
+      // TODO: We directly convert uses into proper calls and unknown uses.
+      for (Use &U : RFI.Declaration->uses()) {
+        if (Instruction *UserI = dyn_cast<Instruction>(U.getUser())) {
+          if (ModuleSlice.count(UserI->getFunction())) {
+            RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
+            ++NumUses;
+          }
+        } else {
+          RFI.getOrCreateUseVector(nullptr).push_back(&U);
+          ++NumUses;
+        }
+      }
+      return NumUses;
+    };
+
+    Module &M = *((*ModuleSlice.begin())->getParent());
+
+#define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...)                     \
+  {                                                                            \
+    SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__});                           \
+    Function *F = M.getFunction(_Name);                                        \
+    if (declMatchesRTFTypes(F, _ReturnType, ArgsTypes)) {                      \
+      auto &RFI = RFIs[_Enum];                                                 \
+      RFI.Kind = _Enum;                                                        \
+      RFI.Name = _Name;                                                        \
+      RFI.IsVarArg = _IsVarArg;                                                \
+      RFI.ReturnType = _ReturnType;                                            \
+      RFI.ArgumentTypes = std::move(ArgsTypes);                                \
+      RFI.Declaration = F;                                                     \
+      unsigned NumUses = CollectUses(RFI);                                     \
+      (void)NumUses;                                                           \
+      LLVM_DEBUG({                                                             \
+        dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not")           \
+               << " found\n";                                                  \
+        if (RFI.Declaration)                                                   \
+          dbgs() << TAG << "-> got " << NumUses << " uses in "                 \
+                 << RFI.getNumFunctionsWithUses()                              \
+                 << " 
diff erent functions.\n";                                 \
+      });                                                                      \
+    }                                                                          \
+  }
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
+
+    // TODO: We should attach the attributes defined in OMPKinds.def.
+  }
+};
+
+struct OpenMPOpt {
+
+  using OptimizationRemarkGetter =
+      function_ref<OptimizationRemarkEmitter &(Function *)>;
+
+  OpenMPOpt(SmallVectorImpl<Function *> &SCC, CallGraphUpdater &CGUpdater,
+            OptimizationRemarkGetter OREGetter,
+            OMPInformationCache &OMPInfoCache)
+      : M(*(*SCC.begin())->getParent()), SCC(SCC),
+        ModuleSlice(OMPInfoCache.ModuleSlice), CGUpdater(CGUpdater),
+        OREGetter(OREGetter), OMPInfoCache(OMPInfoCache) {}
+
   /// Run all OpenMP optimizations on the underlying SCC/ModuleSlice.
   bool run() {
     bool Changed = false;
@@ -167,12 +277,36 @@ struct OpenMPOpt {
     return Changed;
   }
 
+  /// Return the call if \p U is a callee use in a regular call. If \p RFI is
+  /// given it has to be the callee or a nullptr is returned.
+  static CallInst *getCallIfRegularCall(
+      Use &U, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
+    CallInst *CI = dyn_cast<CallInst>(U.getUser());
+    if (CI && CI->isCallee(&U) && !CI->hasOperandBundles() &&
+        (!RFI || CI->getCalledFunction() == RFI->Declaration))
+      return CI;
+    return nullptr;
+  }
+
+  /// Return the call if \p V is a regular call. If \p RFI is given it has to be
+  /// the callee or a nullptr is returned.
+  static CallInst *getCallIfRegularCall(
+      Value &V, OMPInformationCache::RuntimeFunctionInfo *RFI = nullptr) {
+    CallInst *CI = dyn_cast<CallInst>(&V);
+    if (CI && !CI->hasOperandBundles() &&
+        (!RFI || CI->getCalledFunction() == RFI->Declaration))
+      return CI;
+    return nullptr;
+  }
+
 private:
   /// Try to delete parallel regions if possible.
   bool deleteParallelRegions() {
     const unsigned CallbackCalleeOperand = 2;
 
-    RuntimeFunctionInfo &RFI = RFIs[OMPRTL___kmpc_fork_call];
+    OMPInformationCache::RuntimeFunctionInfo &RFI =
+        OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call];
+
     if (!RFI.Declaration)
       return false;
 
@@ -243,7 +377,8 @@ struct OpenMPOpt {
 
     for (Function *F : SCC) {
       for (auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs)
-        deduplicateRuntimeCalls(*F, RFIs[DeduplicableRuntimeCallID]);
+        deduplicateRuntimeCalls(*F,
+                                OMPInfoCache.RFIs[DeduplicableRuntimeCallID]);
 
       // __kmpc_global_thread_num is special as we can replace it with an
       // argument in enough cases to make it worth trying.
@@ -254,7 +389,7 @@ struct OpenMPOpt {
           break;
         }
       Changed |= deduplicateRuntimeCalls(
-          *F, RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
+          *F, OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num], GTIdArg);
     }
 
     return Changed;
@@ -279,8 +414,9 @@ struct OpenMPOpt {
   /// return a local `struct ident_t*`. For now, if we cannot find a suitable
   /// return value we create one from scratch. We also do not yet combine
   /// information, e.g., the source locations, see combinedIdentStruct.
-  Value *getCombinedIdentFromCallUsesIn(RuntimeFunctionInfo &RFI, Function &F,
-                                        bool GlobalOnly) {
+  Value *
+  getCombinedIdentFromCallUsesIn(OMPInformationCache::RuntimeFunctionInfo &RFI,
+                                 Function &F, bool GlobalOnly) {
     bool SingleChoice = true;
     Value *Ident = nullptr;
     auto CombineIdentStruct = [&](Use &U, Function &Caller) {
@@ -296,29 +432,30 @@ struct OpenMPOpt {
     if (!Ident || !SingleChoice) {
       // The IRBuilder uses the insertion block to get to the module, this is
       // unfortunate but we work around it for now.
-      if (!OMPBuilder.getInsertionPoint().getBlock())
-        OMPBuilder.updateToLocation(OpenMPIRBuilder::InsertPointTy(
+      if (!OMPInfoCache.OMPBuilder.getInsertionPoint().getBlock())
+        OMPInfoCache.OMPBuilder.updateToLocation(OpenMPIRBuilder::InsertPointTy(
             &F.getEntryBlock(), F.getEntryBlock().begin()));
       // Create a fallback location if non was found.
       // TODO: Use the debug locations of the calls instead.
-      Constant *Loc = OMPBuilder.getOrCreateDefaultSrcLocStr();
-      Ident = OMPBuilder.getOrCreateIdent(Loc);
+      Constant *Loc = OMPInfoCache.OMPBuilder.getOrCreateDefaultSrcLocStr();
+      Ident = OMPInfoCache.OMPBuilder.getOrCreateIdent(Loc);
     }
     return Ident;
   }
 
   /// Try to eliminiate calls of \p RFI in \p F by reusing an existing one or
   /// \p ReplVal if given.
-  bool deduplicateRuntimeCalls(Function &F, RuntimeFunctionInfo &RFI,
+  bool deduplicateRuntimeCalls(Function &F,
+                               OMPInformationCache::RuntimeFunctionInfo &RFI,
                                Value *ReplVal = nullptr) {
     auto *UV = RFI.getUseVector(F);
     if (!UV || UV->size() + (ReplVal != nullptr) < 2)
       return false;
 
-    LLVM_DEBUG(dbgs() << TAG << "Deduplicate " << UV->size() << " uses of "
-                      << RFI.Name
-                      << (ReplVal ? " with an existing value\n" : "\n")
-                      << "\n");
+    LLVM_DEBUG(
+        dbgs() << TAG << "Deduplicate " << UV->size() << " uses of " << RFI.Name
+               << (ReplVal ? " with an existing value\n" : "\n") << "\n");
+
     assert((!ReplVal || (isa<Argument>(ReplVal) &&
                          cast<Argument>(ReplVal)->getParent() == &F)) &&
            "Unexpected replacement value!");
@@ -410,8 +547,8 @@ struct OpenMPOpt {
         if (CallInst *CI = getCallIfRegularCall(U)) {
           Value *ArgOp = CI->getArgOperand(ArgNo);
           if (CI == &RefCI || GTIdArgs.count(ArgOp) ||
-              getCallIfRegularCall(*ArgOp,
-                                   &RFIs[OMPRTL___kmpc_global_thread_num]))
+              getCallIfRegularCall(
+                  *ArgOp, &OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num]))
             continue;
         }
         return false;
@@ -430,8 +567,9 @@ struct OpenMPOpt {
     };
 
     // The argument users of __kmpc_global_thread_num calls are GTIds.
-    RuntimeFunctionInfo &GlobThreadNumRFI =
-        RFIs[OMPRTL___kmpc_global_thread_num];
+    OMPInformationCache::RuntimeFunctionInfo &GlobThreadNumRFI =
+        OMPInfoCache.RFIs[OMPRTL___kmpc_global_thread_num];
+
     GlobThreadNumRFI.foreachUse([&](Use &U, Function &F) {
       if (CallInst *CI = getCallIfRegularCall(U, &GlobThreadNumRFI))
         AddUserArgs(*CI);
@@ -445,109 +583,6 @@ struct OpenMPOpt {
       AddUserArgs(*GTIdArgs[u]);
   }
 
-  /// Return the call if \p U is a callee use in a regular call. If \p RFI is
-  /// given it has to be the callee or a nullptr is returned.
-  CallInst *getCallIfRegularCall(Use &U, RuntimeFunctionInfo *RFI = nullptr) {
-    CallInst *CI = dyn_cast<CallInst>(U.getUser());
-    if (CI && CI->isCallee(&U) && !CI->hasOperandBundles() &&
-        (!RFI || CI->getCalledFunction() == RFI->Declaration))
-      return CI;
-    return nullptr;
-  }
-
-  /// Return the call if \p V is a regular call. If \p RFI is given it has to be
-  /// the callee or a nullptr is returned.
-  CallInst *getCallIfRegularCall(Value &V, RuntimeFunctionInfo *RFI = nullptr) {
-    CallInst *CI = dyn_cast<CallInst>(&V);
-    if (CI && !CI->hasOperandBundles() &&
-        (!RFI || CI->getCalledFunction() == RFI->Declaration))
-      return CI;
-    return nullptr;
-  }
-
-  /// Returns true if the function declaration \p F matches the runtime
-  /// function types, that is, return type \p RTFRetType, and argument types
-  /// \p RTFArgTypes.
-  static bool declMatchesRTFTypes(Function *F, Type *RTFRetType,
-                                  SmallVector<Type *, 8> &RTFArgTypes) {
-    // TODO: We should output information to the user (under debug output
-    //       and via remarks).
-
-    if (!F)
-      return false;
-    if (F->getReturnType() != RTFRetType)
-      return false;
-    if (F->arg_size() != RTFArgTypes.size())
-      return false;
-
-    auto RTFTyIt = RTFArgTypes.begin();
-    for (Argument &Arg : F->args()) {
-      if (Arg.getType() != *RTFTyIt)
-        return false;
-
-      ++RTFTyIt;
-    }
-
-    return true;
-  }
-
-  /// Helper to initialize all runtime function information for those defined in
-  /// OpenMPKinds.def.
-  void initializeRuntimeFunctions() {
-    // Helper to collect all uses of the decleration in the UsesMap.
-    auto CollectUses = [&](RuntimeFunctionInfo &RFI) {
-      unsigned NumUses = 0;
-      if (!RFI.Declaration)
-        return NumUses;
-      OMPBuilder.addAttributes(RFI.Kind, *RFI.Declaration);
-
-      NumOpenMPRuntimeFunctionsIdentified += 1;
-      NumOpenMPRuntimeFunctionUsesIdentified += RFI.Declaration->getNumUses();
-
-      // TODO: We directly convert uses into proper calls and unknown uses.
-      for (Use &U : RFI.Declaration->uses()) {
-        if (Instruction *UserI = dyn_cast<Instruction>(U.getUser())) {
-          if (ModuleSlice.count(UserI->getFunction())) {
-            RFI.getOrCreateUseVector(UserI->getFunction()).push_back(&U);
-            ++NumUses;
-          }
-        } else {
-          RFI.getOrCreateUseVector(nullptr).push_back(&U);
-          ++NumUses;
-        }
-      }
-      return NumUses;
-    };
-
-#define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...)                     \
-  {                                                                            \
-    SmallVector<Type *, 8> ArgsTypes({__VA_ARGS__});                           \
-    Function *F = M.getFunction(_Name);                                        \
-    if (declMatchesRTFTypes(F, _ReturnType, ArgsTypes)) {                      \
-      auto &RFI = RFIs[_Enum];                                                 \
-      RFI.Kind = _Enum;                                                        \
-      RFI.Name = _Name;                                                        \
-      RFI.IsVarArg = _IsVarArg;                                                \
-      RFI.ReturnType = _ReturnType;                                            \
-      RFI.ArgumentTypes = std::move(ArgsTypes);                                \
-      RFI.Declaration = F;                                                     \
-      unsigned NumUses = CollectUses(RFI);                                     \
-      (void)NumUses;                                                           \
-      LLVM_DEBUG({                                                             \
-        dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not")           \
-               << " found\n";                                                  \
-        if (RFI.Declaration)                                                   \
-          dbgs() << TAG << "-> got " << NumUses << " uses in "                 \
-                 << RFI.getNumFunctionsWithUses()                              \
-                 << " 
diff erent functions.\n";                                 \
-      });                                                                      \
-    }                                                                          \
-  }
-#include "llvm/Frontend/OpenMP/OMPKinds.def"
-
-    // TODO: We should attach the attributes defined in OMPKinds.def.
-  }
-
   /// Emit a remark generically
   ///
   /// This template function can be used to generically emit a remark. The
@@ -566,9 +601,8 @@ struct OpenMPOpt {
     Function *F = Inst->getParent()->getParent();
     auto &ORE = OREGetter(F);
 
-    ORE.emit([&]() {
-      return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, Inst));
-    });
+    ORE.emit(
+        [&]() { return RemarkCB(RemarkKind(DEBUG_TYPE, RemarkName, Inst)); });
   }
 
   /// The underyling module.
@@ -580,9 +614,6 @@ struct OpenMPOpt {
   /// The slice of the module we are allowed to look at.
   SmallPtrSetImpl<Function *> &ModuleSlice;
 
-  /// An OpenMP-IR-Builder instance
-  OpenMPIRBuilder OMPBuilder;
-
   /// Callback to update the call graph, the first argument is a removed call,
   /// the second an optional replacement call.
   CallGraphUpdater &CGUpdater;
@@ -590,10 +621,8 @@ struct OpenMPOpt {
   /// Callback to get an OptimizationRemarkEmitter from a Function *
   OptimizationRemarkGetter OREGetter;
 
-  /// Map from runtime function kind to the runtime function description.
-  EnumeratedArray<RuntimeFunctionInfo, RuntimeFunction,
-                  RuntimeFunction::OMPRTL___last>
-      RFIs;
+  /// OpenMP-specific information cache. Also Used for Attributor runs.
+  OMPInformationCache &OMPInfoCache;
 };
 } // namespace
 
@@ -616,16 +645,25 @@ PreservedAnalyses OpenMPOptPass::run(LazyCallGraph::SCC &C,
   if (SCC.empty())
     return PreservedAnalyses::all();
 
-  auto OREGetter = [&C, &CG, &AM](Function *F) -> OptimizationRemarkEmitter & {
-    FunctionAnalysisManager &FAM =
-        AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
+  FunctionAnalysisManager &FAM =
+      AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
+
+  AnalysisGetter AG(FAM);
+
+  auto OREGetter = [&FAM](Function *F) -> OptimizationRemarkEmitter & {
     return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
   };
 
   CallGraphUpdater CGUpdater;
   CGUpdater.initialize(CG, C, AM, UR);
+
+  SetVector<Function *> Functions(SCC.begin(), SCC.end());
+  BumpPtrAllocator Allocator;
+  OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator,
+                                /*CGSCC*/ &Functions, ModuleSlice);
+
   // TODO: Compute the module slice we are allowed to look at.
-  OpenMPOpt OMPOpt(SCC, ModuleSlice, CGUpdater, OREGetter);
+  OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache);
   bool Changed = OMPOpt.run();
   (void)Changed;
   return PreservedAnalyses::all();
@@ -682,8 +720,15 @@ struct OpenMPOptLegacyPass : public CallGraphSCCPass {
       return *ORE;
     };
 
+    AnalysisGetter AG;
+    SetVector<Function *> Functions(SCC.begin(), SCC.end());
+    BumpPtrAllocator Allocator;
+    OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG,
+                                  Allocator,
+                                  /*CGSCC*/ &Functions, ModuleSlice);
+
     // TODO: Compute the module slice we are allowed to look at.
-    OpenMPOpt OMPOpt(SCC, ModuleSlice, CGUpdater, OREGetter);
+    OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache);
     return OMPOpt.run();
   }
 


        


More information about the llvm-commits mailing list