diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -94,6 +94,9 @@ /// from meta data in the file. void discoverFileObjects(); + /// Create and initializer metadata rewriters for this instance. + void initializeRewriters(); + /// Process fragments, locate parent functions. void registerFragments(); @@ -188,6 +191,9 @@ /// Link additional runtime code to support instrumentation. void linkRuntime(); + /// Process metadata in special sections before CFG is built for functions. + void processMetadataPreCFG(); + /// Update debug and other auxiliary information in the file. void updateMetadata(); diff --git a/bolt/include/bolt/Rewrite/RewriteManager.h b/bolt/include/bolt/Rewrite/RewriteManager.h new file mode 100644 --- /dev/null +++ b/bolt/include/bolt/Rewrite/RewriteManager.h @@ -0,0 +1,55 @@ +//===- bolt/Rewrite/RewriteManager.h ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef BOLT_REWRITE_REWRITE_MANAGER_H +#define BOLT_REWRITE_REWRITE_MANAGER_H + +#include "bolt/Core/BinaryContext.h" +#include "bolt/Rewrite/RewriterBase.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace bolt { + +class BinaryContext; + +/// This class manages a collection of metadata handlers/rewriters. +/// It is responsible for registering new rewriters and invoking them at +/// certain stages of the binary processing pipeline. +class RewriteManager { + using RewritersListType = SmallVector, 1>; + RewritersListType Rewriters; + + friend class RewriteInstance; + + /// Initialize rewriters based on \p BC context. + void initRewriters(BinaryContext &BC); + + /// Execute initialization of rewriters while functions are disassembled, but + /// CFG is not yet built. + void runInitializersPreCFG(); + + /// Run finalization step of rewriters after code has been emitted. + void runFinalizersAfterEmit(); + + /// Register a new \p Rewriter. + void registerRewriter(std::unique_ptr Rewriter); + +public: + RewriteManager() = default; + ~RewriteManager(); + + /// Use this static method to access global RewriteManager instance. + static RewriteManager *getManager(); +}; + +} // namespace bolt +} // namespace llvm + +#endif // BOLT_REWRITE_REWRITE_MANAGER_H diff --git a/bolt/include/bolt/Rewrite/RewriterBase.h b/bolt/include/bolt/Rewrite/RewriterBase.h new file mode 100644 --- /dev/null +++ b/bolt/include/bolt/Rewrite/RewriterBase.h @@ -0,0 +1,51 @@ +//===- bolt/Rewrite/RewriterBase.h ------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Interface for updating file sections. +// +//===----------------------------------------------------------------------===// + +#ifndef BOLT_REWRITE_REWRITER_BASE_H +#define BOLT_REWRITE_REWRITER_BASE_H + +#include "bolt/Core/BinaryContext.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace bolt { + +/// Base class for updating sections containing metadata. +class RewriterBase { + StringRef Name; + +protected: + BinaryContext *BC = nullptr; + +public: + explicit RewriterBase(StringRef Name) : Name(Name) {} + virtual ~RewriterBase() = default; + + /// Return name for the rewriter. + StringRef getName() const { return Name; } + + /// Initialize the rewriter based on the context \p BC. + virtual void init(BinaryContext &Ctx) { BC = &Ctx; } + + /// Interface for modifying/annotating functions in the binary based on the + /// contents of the section. Functions are in pre-cfg state. + virtual Error preCFGInitializer() { return Error::success(); } + + /// Finalize section contents based on the new Context after the new code is + /// emitted. + virtual Error postEmitFinalizer() { return Error::success(); } +}; + +} // namespace bolt +} // namespace llvm + +#endif // BOLT_REWRITE_REWRITER_BASE_H diff --git a/bolt/include/bolt/Rewrite/Rewriters.h b/bolt/include/bolt/Rewrite/Rewriters.h new file mode 100644 --- /dev/null +++ b/bolt/include/bolt/Rewrite/Rewriters.h @@ -0,0 +1,24 @@ +//===- bolt/Rewrite/Rewriters.h ---------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef BOLT_REWRITE_REWRITERS_H +#define BOLT_REWRITE_REWRITERS_H + +#include + +namespace llvm { +namespace bolt { + +class RewriterBase; + +/// The list of rewriter build functions (e.g. createNewRewriter()). + +} // namespace bolt +} // namespace llvm + +#endif // BOLT_REWRITE_REWRITERS_H diff --git a/bolt/lib/Rewrite/CMakeLists.txt b/bolt/lib/Rewrite/CMakeLists.txt --- a/bolt/lib/Rewrite/CMakeLists.txt +++ b/bolt/lib/Rewrite/CMakeLists.txt @@ -16,6 +16,7 @@ JITLinkLinker.cpp MachORewriteInstance.cpp RewriteInstance.cpp + RewriteManager.cpp DISABLE_LLVM_LINK_LLVM_DYLIB diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -27,6 +27,8 @@ #include "bolt/Rewrite/DWARFRewriter.h" #include "bolt/Rewrite/ExecutableFileMemoryManager.h" #include "bolt/Rewrite/JITLinkLinker.h" +#include "bolt/Rewrite/RewriteManager.h" +#include "bolt/Rewrite/Rewriters.h" #include "bolt/RuntimeLibs/HugifyRuntimeLibrary.h" #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h" #include "bolt/Utils/CommandLineOpts.h" @@ -369,6 +371,8 @@ BC->initializeTarget(std::unique_ptr(createMCPlusBuilder( BC->TheTriple->getArch(), BC->MIA.get(), BC->MII.get(), BC->MRI.get()))); + initializeRewriters(); + BAT = std::make_unique(); if (opts::UpdateDebugSections) @@ -382,6 +386,10 @@ RewriteInstance::~RewriteInstance() {} +void RewriteInstance::initializeRewriters() { + RewriteManager::getManager()->initRewriters(*BC); +} + Error RewriteInstance::setProfile(StringRef Filename) { if (!sys::fs::exists(Filename)) return errorCodeToError(make_error_code(errc::no_such_file_or_directory)); @@ -840,7 +848,7 @@ disassembleFunctions(); - processProfileDataPreCFG(); + processMetadataPreCFG(); buildFunctionsCFG(); @@ -3239,6 +3247,12 @@ } } +void RewriteInstance::processMetadataPreCFG() { + RewriteManager::getManager()->runInitializersPreCFG(); + + processProfileDataPreCFG(); +} + void RewriteInstance::processProfileDataPreCFG() { if (!ProfileReader) return; @@ -3591,6 +3605,9 @@ } void RewriteInstance::updateMetadata() { + RewriteManager::getManager()->runFinalizersAfterEmit(); + + // TODO: use RewriteManager for updates. updateSDTMarkers(); updateLKMarkers(); parsePseudoProbe(); diff --git a/bolt/lib/Rewrite/RewriteManager.cpp b/bolt/lib/Rewrite/RewriteManager.cpp new file mode 100644 --- /dev/null +++ b/bolt/lib/Rewrite/RewriteManager.cpp @@ -0,0 +1,60 @@ +//===- bolt/Rewrite/RewriteManager.cpp ------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "bolt/Rewrite/RewriteManager.h" +#include "bolt/Core/BinaryContext.h" +#include "llvm/Support/Debug.h" + +#undef DEBUG_TYPE +#define DEBUG_TYPE "bolt-rewriter" + +using namespace llvm; +using namespace bolt; + +RewriteManager *RewriteManager::getManager() { + static RewriteManager Obj; + return &Obj; +} + +RewriteManager::~RewriteManager() = default; + +void RewriteManager::registerRewriter(std::unique_ptr Rewriter) { + Rewriters.emplace_back(std::move(Rewriter)); +} + +void RewriteManager::initRewriters(BinaryContext &BC) { + for (auto &Rewriter : Rewriters) { + LLVM_DEBUG(dbgs() << "BOLT-DEBUG: initializing " << Rewriter->getName() + << "\n"); + Rewriter->init(BC); + } +} + +void RewriteManager::runInitializersPreCFG() { + for (auto &Rewriter : Rewriters) { + LLVM_DEBUG(dbgs() << "BOLT-DEBUG: invoking " << Rewriter->getName() + << " before CFG construction\n"); + if (Error E = Rewriter->preCFGInitializer()) { + errs() << "BOLT-ERROR: while running " << Rewriter->getName() + << " in pre-CFG state: " << toString(std::move(E)) << '\n'; + exit(1); + } + } +} + +void RewriteManager::runFinalizersAfterEmit() { + for (auto &Rewriter : Rewriters) { + LLVM_DEBUG(dbgs() << "BOLT-DEBUG: invoking " << Rewriter->getName() + << " after emit\n"); + if (Error E = Rewriter->postEmitFinalizer()) { + errs() << "BOLT-ERROR: while running " << Rewriter->getName() + << " after emit: " << toString(std::move(E)) << '\n'; + exit(1); + } + } +}