[PATCH v2 15/50] helper-to-tcg: PrepareForOptPass, cull unused functions

Anton Johansson via qemu development <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
Make an early pass over all functions in the input module and filter out
functions with:

  1. Invalid return type, or;
  2. No helper-to-tcg annotation and not called by a function with such
     a annotation.

A commandline option is also added to force translation of all functions
starting with "helper_".

Signed-off-by: Anton Johansson <[email protected]>
---
 .../helper-to-tcg/include/CmdLineOptions.hpp  |  2 +
 .../include/PrepareForOptPass.hpp             |  7 +-
 subprojects/helper-to-tcg/src/Pipeline.cpp    |  5 ++
 .../PrepareForOptPass/PrepareForOptPass.cpp   | 86 +++++++++++++++++++
 4 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp b/subprojects/helper-to-tcg/include/CmdLineOptions.hpp
index 93706b78c5..ca1cb59835 100644
--- a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp
+++ b/subprojects/helper-to-tcg/include/CmdLineOptions.hpp
@@ -21,3 +21,5 @@
 
 // Options for pipeline
 extern llvm::cl::list<std::string> InputFiles;
+// Options for PrepareForOptPass
+extern llvm::cl::opt<bool> TranslateAllHelpers;
diff --git a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp
index e007243578..08ca9a43bb 100644
--- a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp
+++ b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp
@@ -29,11 +29,10 @@
 
 class PrepareForOptPass : public llvm::PassInfoMixin<PrepareForOptPass> {
     AnnotationMapTy &ResultAnnotations;
-public:
+
+  public:
     PrepareForOptPass(AnnotationMapTy &ResultAnnotations)
-        : ResultAnnotations(ResultAnnotations)
-    {
-    }
+        : ResultAnnotations(ResultAnnotations) {}
     llvm::PreservedAnalyses run(llvm::Module &M,
                                 llvm::ModuleAnalysisManager &MAM);
 };
diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helper-to-tcg/src/Pipeline.cpp
index 051611b0f3..89637eaec6 100644
--- a/subprojects/helper-to-tcg/src/Pipeline.cpp
+++ b/subprojects/helper-to-tcg/src/Pipeline.cpp
@@ -65,6 +65,11 @@ static cl::opt<std::string>
               cl::init(""), cl::cat(Cat));
 #endif
 
+// Options for PrepareForOptPass
+cl::opt<bool> TranslateAllHelpers(
+    "translate-all-helpers", cl::init(false),
+    cl::desc("Translate all functions starting with helper_*"), cl::cat(Cat));
+
 // Define a TargetTransformInfo (TTI) subclass, this allows for overriding
 // common per-llvm-target information expected by other LLVM passes, such
 // as the width of the largest scalar/vector registers.  Needed for consistent
diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp
index 1228ac952f..df6d9eeec8 100644
--- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp
+++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp
@@ -16,17 +16,25 @@
 //
 
 #include "PrepareForOptPass.hpp"
+#include "CmdLineOptions.hpp"
 #include "Error.hpp"
+#include "FunctionAnnotation.hpp"
+#include "LlvmCompat.hpp"
 
+#include <llvm/ADT/SmallPtrSet.h>
 #include <llvm/ADT/StringRef.h>
 #include <llvm/ADT/StringSet.h>
 #include <llvm/Demangle/Demangle.h>
 #include <llvm/IR/Constants.h>
 #include <llvm/IR/Function.h>
 #include <llvm/IR/Instruction.h>
+#include <llvm/IR/Instructions.h>
 #include <llvm/IR/Module.h>
 #include <llvm/Support/Debug.h>
 
+#include <queue>
+#include <set>
+
 #define DEBUG_TYPE "prepare-for-opt"
 
 using namespace llvm;
@@ -156,9 +164,87 @@ static void collectAnnotations(Module &M, AnnotationMapTy &ResultAnnotations) {
     });
 }
 
+inline bool hasValidReturnTy(const Module &M, const Function *F) {
+    Type *RetTy = F->getReturnType();
+    return RetTy->isStructTy() || RetTy == Type::getVoidTy(F->getContext()) ||
+           RetTy == Type::getInt8Ty(M.getContext()) ||
+           RetTy == Type::getInt16Ty(M.getContext()) ||
+           RetTy == Type::getInt32Ty(M.getContext()) ||
+           RetTy == Type::getInt64Ty(M.getContext());
+}
+
+// Functions that should be removed:
+//   - No helper-to-tcg annotation (if TranslateAllHelpers == false);
+//   - Invalid (non-integer/void) return type
+static bool shouldRemoveFunction(const Module &M, const Function &F,
+                                 const AnnotationMapTy &AnnotationMap) {
+    if (F.isDeclaration()) {
+        return false;
+    }
+
+    if (!hasValidReturnTy(M, &F)) {
+        return true;
+    }
+
+    std::queue<const Function *> Worklist;
+    std::set<const Function *> Visited;
+    Worklist.push(&F);
+    while (!Worklist.empty()) {
+        const Function *F = Worklist.front();
+        Worklist.pop();
+        if (F->isDeclaration() or Visited.find(F) != Visited.end()) {
+            continue;
+        }
+        Visited.insert(F);
+
+        if (TranslateAllHelpers and
+            compat::isFunctionQemuHelper(F->getName())) {
+            // If --translate-all-helpers is provided and `F` starts with
+            // "helper_*", then don't skip it.
+            return false;
+        } else if (auto It = AnnotationMap.find(F); It != AnnotationMap.end()) {
+            // Otherwise check "helper-to-tcg" annotation.
+            const Annotations &Ann = It->second;
+            if (Ann.isSet(FunctionAnnotation::HelperToTcg)) {
+                return false;
+            }
+        }
+
+        // Push functions that call `F` to the worklist, this way we retain
+        // functions that are being called by functions with the "helper-to-tcg"
+        // annotation.
+        for (const User *U : F->users()) {
+            auto Call = dyn_cast<CallInst>(U);
+            if (!Call) {
+                continue;
+            }
+            const Function *ParentF = Call->getParent()->getParent();
+            Worklist.push(ParentF);
+        }
+    }
+
+    return true;
+}
+
+static void cullUnusedFunctions(Module &M, AnnotationMapTy &Annotations) {
+    SmallPtrSet<Function *, 16> FunctionsToRemove;
+    for (auto &F : M) {
+        if (shouldRemoveFunction(M, F, Annotations)) {
+            FunctionsToRemove.insert(&F);
+        }
+    }
+
+    for (Function *F : FunctionsToRemove) {
+        Annotations.erase(F);
+        F->setComdat(nullptr);
+        F->deleteBody();
+    }
+}
+
 PreservedAnalyses PrepareForOptPass::run(Module &M,
                                          ModuleAnalysisManager &MAM) {
     demangleFunctionNames(M);
     collectAnnotations(M, ResultAnnotations);
+    cullUnusedFunctions(M, ResultAnnotations);
     return PreservedAnalyses::none();
 }
-- 
2.52.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.