================ @@ -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