================
@@ -0,0 +1,251 @@
+//===------ WindowsHotPatch.cpp - Support for Windows hotpatching 
---------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Marks functions with the `marked_for_windows_hot_patching` attribute.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "windows-hot-patch"
+
+// A file containing list of mangled function names to mark for hot patching.
+static cl::opt<std::string> LLVMMSHotPatchFunctionsFile(
+    "ms-hotpatch-functions-file", cl::value_desc("filename"),
+    cl::desc("A file containing list of mangled function names to mark for hot 
"
+             "patching"));
+
+// A list of mangled function names to mark for hot patching.
+static cl::list<std::string> LLVMMSHotPatchFunctionsList(
+    "ms-hotpatch-functions-list", cl::value_desc("list"),
+    cl::desc("A list of mangled function names to mark for hot patching"),
+    cl::CommaSeparated);
+
+namespace {
+
+class WindowsHotPatch : public ModulePass {
+  struct GlobalVariableUse {
+    GlobalVariable *GV;
+    Instruction *User;
+    unsigned Op;
+  };
+
+public:
+  static char ID;
+
+  WindowsHotPatch() : ModulePass(ID) {
+    initializeWindowsHotPatchPass(*PassRegistry::getPassRegistry());
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+  }
+
+  bool runOnModule(Module &M) override;
+
+private:
+  bool
+  runOnFunction(Function &F,
+                SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping);
+  void replaceGlobalVariableUses(
+      Function &F, SmallVectorImpl<GlobalVariableUse> &GVUses,
+      SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping,
+      DIBuilder &DebugInfo);
+};
+
+} // end anonymous namespace
+
+char WindowsHotPatch::ID = 0;
+
+INITIALIZE_PASS(WindowsHotPatch, "windows-hot-patch",
+                "Mark functions for Windows hot patch support", false, false)
+ModulePass *llvm::createWindowsHotPatch() { return new WindowsHotPatch(); }
+
+// Find functions marked with Attribute::MarkedForWindowsHotPatching and modify
+// their code (if necessary) to account for accesses to global variables.
+bool WindowsHotPatch::runOnModule(Module &M) {
+  // The front end may have already marked functions for hot-patching. However,
+  // we also allow marking functions by passing -ms-hotpatch-functions-file or
+  // -ms-hotpatch-functions-list directly to LLVM. This allows hot-patching to
+  // work with languages that have not yet updated their front-ends.
+  if (!LLVMMSHotPatchFunctionsFile.empty() ||
+      !LLVMMSHotPatchFunctionsList.empty()) {
+    std::vector<std::string> HotPatchFunctionsList;
+
+    if (!LLVMMSHotPatchFunctionsFile.empty()) {
+      auto BufOrErr = llvm::MemoryBuffer::getFile(LLVMMSHotPatchFunctionsFile);
+      if (BufOrErr) {
+        const llvm::MemoryBuffer &FileBuffer = **BufOrErr;
+        for (llvm::line_iterator I(FileBuffer.getMemBufferRef(), true), E;
+             I != E; ++I) {
+          HotPatchFunctionsList.push_back(std::string{*I});
+        }
+      } else {
+        M.getContext().diagnose(llvm::DiagnosticInfoGeneric{
+            llvm::Twine("failed to open hotpatch functions file "
+                        "(--ms-hotpatch-functions-file): ") +
+            LLVMMSHotPatchFunctionsFile + llvm::Twine(" : ") +
+            BufOrErr.getError().message()});
+      }
+    }
+
+    if (!LLVMMSHotPatchFunctionsList.empty()) {
+      for (const auto &FuncName : LLVMMSHotPatchFunctionsList) {
+        HotPatchFunctionsList.push_back(FuncName);
+      }
+    }
+
+    // Build a set for quick lookups. This points into HotPatchFunctionsList, 
so
+    // HotPatchFunctionsList must live longer than HotPatchFunctionsSet.
+    llvm::SmallSet<llvm::StringRef, 16> HotPatchFunctionsSet;
+    for (const auto &FuncName : HotPatchFunctionsList) {
+      HotPatchFunctionsSet.insert(llvm::StringRef{FuncName});
+    }
+
+    // Iterate through all of the functions and check whether they need to be
+    // marked for hotpatching using the list provided directly to LLVM.
+    for (auto &F : M.functions()) {
+      // Ignore declarations that are not definitions.
+      if (F.isDeclarationForLinker()) {
----------------
sivadeilra wrote:

"We" in this context is Microsoft, specifically the Windows organization.  We 
have in-house tools that generate our hot-patches.  Currently, these tools only 
work with MSVC.  The aim of this PR (and others, in the future) is to allow 
these tools to work with LLVM, specifically with Clang and Rust.

Our tools currently do not handle static functions.  However, I don't want to 
exclude the possibility of supporting static functions in the future, which is 
why I responded to @efriedma-quic 's comment by saying that I don't want to 
restrict this code to handle only public functions.

https://github.com/llvm/llvm-project/pull/138972
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to