Implementing a new pass – Optimizing IR-1
A pass can perform arbitrary complex transformations on the LLVM IR. To illustrate the mechanics of adding a new pass, we add a pass that performs a simple instrumentation.
To investigate the performance of a program, it is interesting to know how often functions are called, and how long they run. One way to collect this data is to insert counters into each function. This process is called instrumentation. We will write a simple instrumentation pass that inserts a special function call at the entry of each function and each exit point. These functions collect the timing information and write it into a file. As a result, we can create a very basic profiler that we’ll name the poor person’s profiler, or in short, ppprofiler. We will develop the new pass so that it can be used as a standalone plugin or added as a plugin to the LLVM source tree. After that, we’ll look at how the passes that come with LLVM are integrated into the framework.
Developing the ppprofiler pass as a plugin
In this section, we’ll look at creating a new pass as a plugin out of the LLVM tree. The goal of the new pass is to insert a call to the __ppp_enter() function at the entry of a function, and a call to the __ppp_exit() function before each return instruction. Only the name of the current function is passed as a parameter. The implementation of these functions can then count the number of calls and measure the elapsed time. We will implement this runtime support at the end of this chapter. We’ll examine how to develop the pass.
We’ll store the source in the PPProfiler.cpp file. Follow these steps:
- First, let’s include some files:
include “llvm/ADT/Statistic.h”
include “llvm/IR/Function.h”
include “llvm/IR/PassManager.h”
include “llvm/Passes/PassBuilder.h”
include “llvm/Passes/PassPlugin.h”
include “llvm/Support/Debug.h”
- To shorten the source, we’ll tell the compiler that we’re using the llvm namespace:
using namespace llvm;
- The built-in debug infrastructure of LLVM requires that we define a debug type, which is a string. This string is later shown in the printed statistic:
define DEBUG_TYPE “ppprofiler”
- Next, we’ll define one counter variable with the ALWAYS_ENABLED_STATISTIC macro. The first parameter is the name of the counter variable, while the second parameter is the text that will be printed in the statistic:
ALWAYS_ENABLED_STATISTIC(
NumOfFunc, “Number of instrumented functions.”);