Search code examples
c++clangllvmllvm-c++-api

How to write and run a LLVM X86 Machine Function Pass 2022


I've been trying to write a machineFunctionPass in LLVM to emit the assembly corresponding to each LLVM IR instruction.

I've tried to follow this mailing list thread, but I haven't been able to get it to work, and nothing is outputted. I've also tried to follow this tutorial, but nothing gets outputted, and some header files had to be changed for it to even compile.

I've written a test pass that prints hello in X86EmitMap.cpp

#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Target/TargetIntrinsicInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"

using namespace llvm;

namespace llvm {
  FunctionPass *createX86EmitMap();
  void initializeX86EmitMapPass(PassRegistry &);
} // namespace llvm

namespace {
  struct X86EmitMap : public MachineFunctionPass {
    static char ID; // Pass identification, replacement for typeid

    X86EmitMap() : MachineFunctionPass(ID) {
      initializeX86EmitMapPass(*PassRegistry::getPassRegistry());
    }
    StringRef getPassName() const override { return "emit map pass"; }

    virtual bool runOnMachineFunction(MachineFunction &MF) override;
  };
} // namespace

char X86EmitMap::ID = 0;
INITIALIZE_PASS_BEGIN(X86EmitMap, "emit map", "emit map pass", false, false)
INITIALIZE_PASS_END(X86EmitMap, "emit map", "emit map pass", false, false)

FunctionPass *llvm::createX86EmitMap() { return new X86EmitMap(); }

bool X86EmitMap::runOnMachineFunction(MachineFunction &MF) {
  errs() << "\n\nhello\n\n ";
  return false;
}

My understanding of the process is:

  1. Create file and add code to llvm/lib/Target/X86/X86EmitMap.cpp
  2. Add addPass(createX86EmitMap()); to void X86PassConfig::addPreEmitPass()
  3. add X86EmitMap.cpp to the CMakeLists.txt in lib/Target/X86
  4. add FunctionPass *createX86EmitMap() to X86.h
  5. Build and run llc, which should print "hello"

Can anyone tell me where I'm going wrong here? Or can you point me to a guide on how to write a backend pass that is up to date? I havent been able to figure it out from these links either:

https://llvm.org/docs/WritingAnLLVMBackend.html
https://llvm.org/docs/CodeGenerator.html

Thanks so much for your help!


Solution

  • I checked a similar pass in X86TargetMachine.cpp, e.g. X86ReturnThunks pass. Use grep to find all usages, it includes:

    • ./lib/Target/X86/CMakeLists.txt, add into cmake compilation
    • pass source file in X86 folder
    • X86.h, 2 parts:
      1. declare function pass: FunctionPass *createX86ReturnThunksPass();
      2. declare init with registry: void initializeX86ReturnThunksPass(PassRegistry &);
    • X86TargetMachine.cpp, 2 parts:
      1. initialize to registry: initializeX86ReturnThunksPass(PR);
      2. use it in backend compilation: addPass(createX86ReturnThunksPass());

    Looks like you add the pass but you also need to registry it.