目录LLVM中所有的Pass都继承自llvm::Pass类或其子类。Ubuntu22.04.5
CLion2026.1
clang22在llvm-project\llvm\lib\Transforms路径下新建一个目录,名称任意,如下: 然后在新建的目录下创建一个cpp文件和CMakeLists.txt文件如下: 在CMakeLists.txt中写入下面这些内容:其中LLVMEncodeFunction就是生成的插件文件的名称。EncodeFunction.cpp是Pass实现的源文件。这是 LLVM 自定义 CMake 宏,定义在:llvm/cmake/modules/AddLLVM.cmake,它是专门为 Pass 插件设计的宏它会自动帮你做:如果没有clang和clang++,那么需要下载clang/clang++。在LLVM源码中编译Pass时,CLion的CMake会根据CMakeLists.txt文件生成对应的 Makefile / build.ninja文件,用于指导编译。而一个项目中有多个CMakeLists.txt,就需要建立CMake连接。这里新建了一个CMakeLists.txt文件,但是并没有与原来项目的CMake连接起来,构建时不会自动寻找新建目录下的CMakeLists.txt进行加载,但是llvm-project\llvm\lib\Transforms路径下的CMakeLists.txt文件与LLVM的CMake是连接的,所以我们可以将新建目录添加到这个CMakeLists.txt文件中。在llvm-project\llvm\lib\Transforms路径下的CMakeLists.txt文件中添加一行add_subdirectory(<新建的目录>),如下: add_subdirectory(EncodeFunction)的作用是:让 CMake 在处理当前 CMakeLists.txt时,进入 EncodeFunction/这个子目录,并加载该目录下的 CMakeLists.txt。Pass的源码分成两部分:Pass功能源码和插件注册源码。在新 Pass 管理器中:下面的源码都要在同一个cpp源文件中。这段代码就是一个Function Pass的功能源码,它的功能就是打印出函数名。static bool isRequired() { return true; }在 LLVM 新 Pass 管理器(New PM) 里是一个强制策略声明,它的作用是告诉 LLVM:这个 Pass 是“必需 Pass”,在任何情况下都不允许被跳过。即使出现以下情况:其中optnone函数是最常见的,**在 **-O0**(Debug 模式)下编译的函数,就有 ****optnone**。-O0的语义是:不要做任何优化或变换,方便调试。而使用clang/clang++将C/C++转换成ll文件时,如果不指定其它的优化等级,那么就会默认是-O0。而LLVM自带的Pass,比如llvm/lib/Transforms/Utils中的HelloWorld.cpp,它就没有static bool isRequired() { return true; },这就导致使用opt -passes=helloworld test.ll -o test.bc不会报错,但是也不和预期一样打印出test.ll文件中的函数名。它是**插件入口函数,**由 llvmGetPassPluginInfo()调用,在 opt/ clang加载 .so时执行这是一个 PassPluginLibraryInfo结构体,包含:当插件被加载后:它是 Lambda 表达式,在 C++中是 匿名函数对象。registerPipelineStartEPCallback主要是为 clang(或任何构建默认优化管线的驱动)准备的。只有clang才能触发这个Pass,如果要通过opt加载Pass,可以删除。回调函数内容:MPM:当前正在构建的模块级 Pass 管理器Level:-O0 ~ -O3FunctionPassManager FPM;的作用是创建一个 Function Pass 管理器FPM.addPass(HelloWorldPass());的作用是把你的 Pass 加入 Function Pass 管线它的作用是把 ModuleToFunctionPassAdaptor对象存入 MPM 的内部容器在 LLVM 新 PM 中:这里的Pass 是 Function Pass 只能被FunctionPassManager FPM;管理。但这里的Pass要放到MPM 层面 ,也就是MPM.addPass(),这里的 MPM是ModulePassManager, 不能直接往 MPM 里塞 Function Pass。createModuleToFunctionPassAdaptor的作用是把一个 FunctionPassManager适配成一个“看起来像 Module Pass 的东西”,也就是ModuleToFunctionPassAdaptor。ModuleToFunctionPassAdaptor的声明:class ModuleToFunctionPassAdaptor : public ModulePass。ModuleToFunctionPassAdaptor是 ModulePass,所以可以放进 ModulePassManagerFPM的声明:FunctionPassManager FPM;,它是 LLVM 的新 Pass 管理器。而LLVM的新Pass管理器都具有如下特点:所以不能createModuleToFunctionPassAdaptor(FPM);,即使是其它函数也不能直接将FPM作为参数传递给函数,因为在C++中直接以对象为参数时会触发拷贝构造函数,对对象进行拷贝,所以不能直接将FPM作为参数传递给函数。createModuleToFunctionPassAdaptor(std::move(FPM));本质上是:std::move的作用是将FunctionPassManager类型转换成FunctionPassManager&&类型,这时候不会新创建任何对象,FunctionPassManager&&还是原来的对象FunctionPassManager&是“左值引用”,表示“我借用你,不动你”,通过它可以引用对象,来修改或读取对象数据FunctionPassManager&&是“右值引用”,表示“我不仅可以借,还可以直接拿走你的资源”,通过它也可以引用对象,来修改或读取对象数据。但是它也可以移动对象。在以它为参数调用构造函数时,就会触发移动构造函数,比如FunctionPassManager newFPM(std::move(oldFPM));这样,使用FunctionPassManager&&创建一个新的FunctionPassManager对象,它会将普通成员(int/bool等类型的成员)的值拷贝给新对象,并将指针成员所指的数据复制到新对象的指针成员所指的内存中,然后将旧对象的成员指针变成nullp
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-291234.htm
[原创]使用LLVM的New Pass Manager编写和使用Pass
100 浏览
4 回复
学习一下
有空还要再复习下,很久没用了
表哥牛逼
mark