Menguasai New Pass Manager di LLVM: arsitektur pipeline, analysis pass vs transform pass, registrasi pass, extension point, dan praktik menulis pass pertama (penghitung fungsi/instruksi) sebagai out-of-tree plugin yang dijalankan dengan opt -load-pass-plugin.

Setelah di episode 6 kita menguasai seluruh CLI tools inti LLVM — clang, opt, llc, lli, llvm-mca — pada episode ini kita mulai menulis kode LLVM yang sesungguhnya: custom pass.
Pass adalah unit eksekusi dalam optimizer LLVM. Setiap pass melakukan satu tugas spesifik: menghitung sesuatu (analysis), mengubah IR (transform), atau mencetak informasi (printer). Memahami arsitektur pass manager adalah kunci untuk membangun tooling LLVM sendiri, dari custom optimizer hingga analyzer kode.
LLVM beralih dari Legacy Pass Manager ke New Pass Manager (New PM) mulai LLVM 13, dan sejak LLVM 17 New PM menjadi default. New PM dirancang lebih modular, lebih mudah dikombinasikan, dan lebih cepat.
| Tipe | Scope | Contoh |
|---|---|---|
| Module Pass | Seluruh module | ForceFunctionAttrsPass |
| Function Pass | Per function | SimplifyCFGPass, InstCombinePass |
| Loop Pass | Per loop | LoopRotatePass, LICMPass |
| BasicBlock Pass | Per basic block | SimplifyCFG (detail) |
DominatorTreeAnalysis, LoopInfoAnalysis.Mem2RegPass, InstCombinePass.my-pass/
├── CMakeLists.txt
└── MyFirstPass.cppcmake_minimum_required(VERSION 3.20)
project(MyFirstPass)
find_package(LLVM REQUIRED CONFIG)
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
add_library(MyFirstPass MODULE MyFirstPass.cpp)
target_link_libraries(MyFirstPass PRIVATE LLVMCore)#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
class FunctionCounter : public PassInfoMixin<FunctionCounter> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
unsigned bbCount = 0, instCount = 0;
for (auto &BB : F) {
++bbCount;
instCount += BB.size();
}
errs() << "Function: " << F.getName() << "\n";
errs() << " Basic Blocks: " << bbCount << "\n";
errs() << " Instructions: " << instCount << "\n";
return PreservedAnalyses::all();
}
};
extern "C" ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "FunctionCounter", LLVM_VERSION_STRING,
[](PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](StringRef Name, FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>) {
if (Name == "function-counter") {
FPM.addPass(FunctionCounter());
return true;
}
return false;
});
}};
}
} // namespace llvmcmake -S . -B build -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm
cmake --build build
# Jalankan pass
opt -load-pass-plugin=build/libMyFirstPass.so \
-passes=function-counter -disable-output program.bcNote
PreservedAnalyses::all() memberitahu pass manager bahwa pass ini tidak mengubah IR, sehingga analisis cache tidak perlu di-invalidate. Jika pass kalian mengubah IR, gunakan PreservedAnalyses::none() atau tentukan analisis mana yang masih valid.
Inti yang harus dibawa pulang:
PassPluginLibraryInfo, jalankan dengan opt -load-pass-plugin.Di episode 8 selanjutnya kita akan membahas optimasi & optimization levels — level -O0 hingga -O3, pass populer (mem2reg, inlining, GVN, loop unroll, vectorizer), dan praktik membangun pipeline optimasi kustom. Sampai jumpa di episode 8!