Index: docs/WritingAnLLVMPass.rst =================================================================== --- docs/WritingAnLLVMPass.rst +++ docs/WritingAnLLVMPass.rst @@ -1353,6 +1353,14 @@ Here the command option is "``mypass``", with ``createDefaultMyPass`` as the default creator. +Out-of-tree MachineIR passes +---------------------------- + +MachineIR passes can be implemented out-of-tree and loaded using the ``--load`` +flag of ``llc``, or ``clang`` thanks to ``-Xclang -load -Xclang Pass.so``. +Examples of such passes are provided in the ``examples/OutOfTreeMIR`` +directory. + Using GDB with dynamically loaded passes ---------------------------------------- Index: examples/CMakeLists.txt =================================================================== --- examples/CMakeLists.txt +++ examples/CMakeLists.txt @@ -7,6 +7,10 @@ add_subdirectory(ModuleMaker) add_subdirectory(SpeculativeJIT) +if (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB) + add_subdirectory(OutOfTreeMIR) +endif() + if(LLVM_ENABLE_EH AND (NOT WIN32) AND (NOT "${LLVM_NATIVE_ARCH}" STREQUAL "ARM")) add_subdirectory(ExceptionDemo) endif() Index: examples/OutOfTreeMIR/CMakeLists.txt =================================================================== --- /dev/null +++ examples/OutOfTreeMIR/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(FunctionPass) +add_subdirectory(ModulePass) Index: examples/OutOfTreeMIR/FunctionPass/CMakeLists.txt =================================================================== --- /dev/null +++ examples/OutOfTreeMIR/FunctionPass/CMakeLists.txt @@ -0,0 +1,5 @@ +add_llvm_library(MIRFunctionPass MODULE + FunctionPass.cpp + BUILDTREE_ONLY + LINK_COMPONENTS Core +) Index: examples/OutOfTreeMIR/FunctionPass/FunctionPass.cpp =================================================================== --- /dev/null +++ examples/OutOfTreeMIR/FunctionPass/FunctionPass.cpp @@ -0,0 +1,39 @@ +//===-- FunctionPass.cpp - Out-of-tree MachineIR pass example -------------===// +// +// 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 +#include +#include +#include +#include +#include + +using namespace llvm; + +namespace { +struct MIRPrinter : public MachineFunctionPass { + static char ID; + + MIRPrinter() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + printMIR(errs(), MF); + return true; + } +}; + +char MIRPrinter::ID = 0; +} // namespace + +MachineFunctionPass *createMIRPrinterPass() { return new MIRPrinter{}; } + +static void callback(TargetPassConfig const &, legacy::PassManagerBase &PM) { + PM.add(createMIRPrinterPass()); +} + +static RegisterMIRPasses Register(TargetPassConfig::EP_OptimizerLast, callback); Index: examples/OutOfTreeMIR/ModulePass/CMakeLists.txt =================================================================== --- /dev/null +++ examples/OutOfTreeMIR/ModulePass/CMakeLists.txt @@ -0,0 +1,5 @@ +add_llvm_library(MIRModulePass MODULE + ModulePass.cpp + BUILDTREE_ONLY + LINK_COMPONENTS Core +) Index: examples/OutOfTreeMIR/ModulePass/ModulePass.cpp =================================================================== --- /dev/null +++ examples/OutOfTreeMIR/ModulePass/ModulePass.cpp @@ -0,0 +1,53 @@ +//===-- ModulePass.cpp - Out-of-tree MachineIR pass example ---------------===// +// +// 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 +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +namespace { +struct MIRPrinter : public ModulePass { + static char ID; + + MIRPrinter() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + AU.setPreservesAll(); + ModulePass::getAnalysisUsage(AU); + } + + bool runOnModule(Module &M) override { + MachineModuleInfo &MMI = getAnalysis(); + + for (Function &F : M) { + if (MachineFunction *MF = MMI.getMachineFunction(F)) { + printMIR(errs(), *MF); + } + } + return true; + } +}; + +char MIRPrinter::ID = 0; +} // namespace + +ModulePass *createMIRPrinterPass() { return new MIRPrinter{}; } + +static void callback(TargetPassConfig const &, legacy::PassManagerBase &PM) { + PM.add(createMIRPrinterPass()); +} + +static RegisterMIRPasses Register(TargetPassConfig::EP_OptimizerLast, callback); Index: include/llvm/CodeGen/TargetPassConfig.h =================================================================== --- include/llvm/CodeGen/TargetPassConfig.h +++ include/llvm/CodeGen/TargetPassConfig.h @@ -15,6 +15,7 @@ #include "llvm/Pass.h" #include "llvm/Support/CodeGen.h" +#include "llvm/ADT/DenseMap.h" #include #include @@ -81,7 +82,32 @@ /// This is an ImmutablePass solely for the purpose of exposing CodeGen options /// to the internals of other CodeGen passes. class TargetPassConfig : public ImmutablePass { +public: + typedef void(*ExtensionFn)(const TargetPassConfig& Builder, + legacy::PassManagerBase &PM); + + enum ExtensionPointTy { + /// This extension point allows adding passes before + /// any other transformations. + EP_EarlyAsPossible, + + /// This extension point allows adding passes before register allocation. + EP_BeforeRA, + /// This extension point allows adding passes after register allocation. + EP_AfterRA, + /// This extension point allows adding passes that / run after everything + //else. + EP_OptimizerLast, + }; + static constexpr size_t EP_EnumSize = EP_OptimizerLast+1; + + static void addGlobalExtension(ExtensionPointTy Ty, ExtensionFn Fn); + void addExtension(ExtensionPointTy Ty, ExtensionFn Fn); + void addExtensionsToPM(ExtensionPointTy ETy) const; + private: + SmallVector Extensions[EP_EnumSize]; + PassManagerBase *PM = nullptr; AnalysisID StartBefore = nullptr; AnalysisID StartAfter = nullptr; Index: lib/CodeGen/TargetPassConfig.cpp =================================================================== --- lib/CodeGen/TargetPassConfig.cpp +++ lib/CodeGen/TargetPassConfig.cpp @@ -203,6 +203,31 @@ cl::desc("Stop compilation before a specific pass"), cl::value_desc("pass-name"), cl::init(""), cl::Hidden); +static ManagedStatic, + TargetPassConfig::EP_EnumSize>> GlobalExtensions; + +void TargetPassConfig::addGlobalExtension( + TargetPassConfig::ExtensionPointTy Ty, + TargetPassConfig::ExtensionFn Fn) { + (*GlobalExtensions)[Ty].push_back(Fn); +} + +void TargetPassConfig::addExtension(ExtensionPointTy Ty, ExtensionFn Fn) { + Extensions[Ty].push_back(Fn); +} + +void TargetPassConfig::addExtensionsToPM(ExtensionPointTy ETy) const { + if (GlobalExtensions.isConstructed()) { + for (auto Fn: (*GlobalExtensions)[ETy]) { + Fn(*this, *PM); + } + } + for (auto Fn: Extensions[ETy]) { + Fn(*this, *PM); + } +} + + /// Allow standard passes to be disabled by command line options. This supports /// simple binary flags that either suppress the pass or do nothing. /// i.e. -disable-mypass=false has no effect. @@ -884,6 +909,8 @@ } } + addExtensionsToPM(EP_EarlyAsPossible); + // Add passes that optimize machine instructions in SSA form. if (getOptLevel() != CodeGenOpt::None) { addMachineSSAOptimization(); @@ -896,6 +923,8 @@ if (TM->Options.EnableIPRA) addPass(createRegUsageInfoPropPass()); + addExtensionsToPM(EP_BeforeRA); + // Run pre-ra passes. addPreRegAlloc(); @@ -909,6 +938,8 @@ // Run post-ra passes. addPostRegAlloc(); + addExtensionsToPM(EP_AfterRA); + // Insert prolog/epilog code. Eliminate abstract frame index references... if (getOptLevel() != CodeGenOpt::None) { addPass(&PostRAMachineSinkingID); @@ -984,6 +1015,8 @@ // Add passes that directly emit MI after all other MI passes. addPreEmitPass2(); + addExtensionsToPM(EP_OptimizerLast); + AddingMachinePasses = false; } Index: test/Examples/OutOfTreeMIR/llc.test =================================================================== --- /dev/null +++ test/Examples/OutOfTreeMIR/llc.test @@ -0,0 +1,12 @@ +; REQUIRES: !static-libs +; RUN: llc %s --load=%llvmshlibdir/MIRFunctionPass%shlibext -o /dev/null |& FileCheck %s +; RUN: llc %s --load=%llvmshlibdir/MIRModulePass%shlibext -o /dev/null |& FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define dso_local i32 @foo() { +entry: + ; CHECK: MOV32ri 42 + ret i32 42 +}