LLVM系列第十八章:写一个简单的IR处理流程Pass

2023-10-31

系列文章目录

LLVM系列第一章:编译LLVM源码
LLVM系列第二章:模块Module
LLVM系列第三章:函数Function
LLVM系列第四章:逻辑代码块Block
LLVM系列第五章:全局变量Global Variable
LLVM系列第六章:函数返回值Return
LLVM系列第七章:函数参数Function Arguments
LLVM系列第八章:算术运算语句Arithmetic Statement
LLVM系列第九章:控制流语句if-else
LLVM系列第十章:控制流语句if-else-phi
LLVM系列第十一章:写一个Hello World
LLVM系列第十二章:写一个简单的词法分析器Lexer
LLVM系列第十三章:写一个简单的语法分析器Parser
LLVM系列第十四章:写一个简单的语义分析器Semantic Analyzer
LLVM系列第十五章:写一个简单的中间代码生成器IR Generator
LLVM系列第十六章:写一个简单的编译器
LLVM系列第十七章:for循环
LLVM系列第十八章:写一个简单的IR处理流程Pass
LLVM系列第十九章:写一个简单的Module Pass
LLVM系列第二十章:写一个简单的Function Pass
LLVM系列第二十一章:写一个简单的Loop Pass
LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)
LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)
LLVM系列第二十四章:用Xcode编译调试LLVM源码
LLVM系列第二十五章:简单统计一下LLVM源码行数
LLVM系列第二十六章:理解LLVMContext
LLVM系列第二十七章:理解IRBuilder
LLVM系列第二十八章:写一个JIT Hello World
LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)

flex&bison系列



前言

在此记录下用LLVM创建一个简单的IR处理流程(Pass)的过程,以备查阅。

开发环境的配置请参考第一章 《LLVM系列第一章:编译LLVM源码》。

Pass是LLVM中很重要的部分。Pass大体上可以理解为一个“处理”,它处理的对象是IR代码。LLVM对代码的分析、转换和优化等处理工作都是由Pass来做的。LLVM以流水线的方式把各个Pass组合起来,让它们成为一个有序的流程。LLVM Pass可以处理的对象有模块(Module)、函数(Function)、循环(Loop),甚至函数调用栈(Function Call Graph)等等。

本章我们就来写一个最简单的Pass。

一、项目结构

我们把这个简单的项目命名为MyPass。可以参考LLVM的源码中其它Pass流程的组织结构,来组织我们自己的代码(示例):

llvm-project/llvm
├── ...
├── lib
│   └── Transforms
│       ├── CMakeLists.txt
│       └── MyPass.cpp
│           ├── CMakeLists.txt
│           └── MyPass.cpp
└── ...

二、项目细节

1. 程序模块

这个简单的项目只包含了一个模块:

  1. MyPass,一个简单的Pass模块

MyPass将会对每一个函数进行处理,即把其函数名打印出来。

注意,我们需要把MyPass项目加入到LLVM Transforms父项目中,即指示CMake在编译LLVM源码的同时,也要编译MyPass项目。

以下是跟项目组织结构相关的部分CMake脚本。

(1) lib/Transforms/MyPass/CMakeLists.txt文件(示例):

# CMakeLists.txt

add_llvm_library(MyPass MODULE BUILDTREE_ONLY
    MyPass.cpp

    PLUGIN_TOOL
    opt
)

(2) lib/Transforms/CMakeLists.txt文件(示例):

...
add_subdirectory(MyPass)
...

3. My Pass

MyPass的实现在文件lib/Transforms/MyPass/MyPass.cpp中:

// MyPass.cpp

#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"

// Only needed for printing
#include  <iostream>

using namespace llvm;

namespace
{
    class MyPass : public PassInfoMixin<MyPass>
    {
    public:

        // The first argument of the run() function defines on what level
        // of granularity your pass will run (e.g. Module, Function).
        // The second argument is the corresponding AnalysisManager
        // (e.g ModuleAnalysisManager, FunctionAnalysisManager)
        PreservedAnalyses run(Function& function, FunctionAnalysisManager& analysisManager)
        {
            std::cout << "MyPass in function: " << function.getName().str() << std::endl;

            // Here goes what you want to do with a pass

            // Assuming we did not change anything of the IR code
            return PreservedAnalyses::all();
        }
    };
}

// This part is the new way of registering your pass
extern "C" PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo()
{
    return
    {
        LLVM_PLUGIN_API_VERSION,
        "MyPass",
        "v0.1",
        [](PassBuilder &passBuilder) {
            passBuilder.registerPipelineParsingCallback(
                [](StringRef name, FunctionPassManager &passManager, ArrayRef<PassBuilder::PipelineElement>) {
                    if(name == "my-pass")
                    {
                        passManager.addPass(MyPass());
                        return true;
                    }

                    return false;
                }
            );
        }
    };
}

三、编译

1. 生成项目文件

用CMake工具生成项目文件(示例):

cd /path/to/llvm-project
mkdir build
cd build

cmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang ../llvm

输出log如下(示例):

-- clang project is enabled
-- clang-tools-extra project is disabled
-- compiler-rt project is disabled
-- debuginfo-tests project is disabled
-- libc project is disabled
-- libclc project is disabled
-- libcxx project is disabled
-- libcxxabi project is disabled
-- libunwind project is disabled
-- lld project is disabled
-- lldb project is disabled
-- mlir project is disabled
-- openmp project is disabled
-- parallel-libs project is disabled
-- polly project is disabled
-- pstl project is disabled
-- flang project is disabled
-- Found libtool - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool
-- Native target architecture is X86
-- Threads enabled.
-- Doxygen disabled.
-- Go bindings enabled.
-- Ninja version: 1.10.2
-- Found ld64 - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
-- Could NOT find OCaml (missing: OCAMLFIND OCAML_VERSION OCAML_STDLIB_PATH) 
-- Could NOT find OCaml (missing: OCAMLFIND OCAML_VERSION OCAML_STDLIB_PATH) 
-- OCaml bindings disabled.
-- LLVM host triple: x86_64-apple-darwin20.6.0
-- LLVM default target triple: x86_64-apple-darwin20.6.0
-- Building with -fPIC
-- Targeting AArch64
-- Targeting AMDGPU
-- Targeting ARM
-- Targeting AVR
-- Targeting BPF
-- Targeting Hexagon
-- Targeting Lanai
-- Targeting Mips
-- Targeting MSP430
-- Targeting NVPTX
-- Targeting PowerPC
-- Targeting RISCV
-- Targeting Sparc
-- Targeting SystemZ
-- Targeting WebAssembly
-- Targeting X86
-- Targeting XCore
-- Clang version: 12.0.1
-- Host linker version: 711
-- Registering Bye as a pass plugin (static build: OFF)
-- Failed to find LLVM FileCheck
-- Version: 0.0.0
-- Performing Test HAVE_THREAD_SAFETY_ATTRIBUTES -- failed to compile
-- Performing Test HAVE_GNU_POSIX_REGEX -- failed to compile
-- Performing Test HAVE_POSIX_REGEX -- success
-- Performing Test HAVE_STEADY_CLOCK -- success
-- Configuring done
-- Generating done
-- Build files have been written to: .../llvm-project/build

2. 编译

用ninja进行编译(示例):

ninja

如果我们是在第一章的编译LLVM完成之后,再编译此项目,则仅仅需要编译MyPass项目即可。当然,这是ninja自动就能识别出来的,即所谓的增量编译技术。输出log如下(示例):

[4/4] Linking CXX shared module lib/MyPass.dylib

3. 运行

为了简单起见,假设我们要对以下test.ll文件中的IR代码进行处理(示例):

define i32 @Foo() {
  %a = add i32 2, 3
  ret i32 %a
}

define i32 @Bar() {
  ret i32 0
}

运行My Pass(示例):

./bin/opt -load-pass-plugin=lib/MyPass.dylib -passes="my-pass" -disable-output test.ll

输出结果如下(示例):

MyPass in function: Foo
MyPass in function: Bar

四、总结

我们用LLVM提供的C++ API,创建了一个简单的Pass,并且编译运行成功。完整源码示例请参看:
https://github.com/wuzhanglin/llvm-pass-examples

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LLVM系列第十八章:写一个简单的IR处理流程Pass 的相关文章

  • LLVM IR 指令和源代码行之间的映射

    如果使用 llvm gcc 或 Dragonegg 我如何存储 LLVM IR 指令和源代码行之间的映射 内部 LLVM IR 调试信息应用于此目的 看http llvm org docs SourceLevelDebugging html
  • 使用 python libclang 检索评论

    在下面的头文件中我想得到相应的 reflect对类和成员变量的注释 ifndef HEADER FOO define HEADER FOO reflect class Foo public private int m int reflect
  • 使用 llvm-prof 收集 LLVM 边缘分析

    我正在使用这些命令来编译下面的代码以收集 trunk llvm 中的边缘 块分析 clang emit llvm c sort c o sort bc opt insert edge profiling sort bc o sort pro
  • 通过修改LLVM Backend来Clobber X86寄存器

    我正在尝试稍微改变 X86 目标的 LLVM 后端 以产生一些所需的行为 更具体地说 我想模拟一个像 gcc 的 fcall used 这样的标志reg option https gcc gnu org onlinedocs gcc Cod
  • 链接不支持异常处理的代码 (C++/LLVM)

    我正在尝试使用 llvm 作为我的软件的代码生成后端 并且刚刚意识到 llvm 的编译不支持 C 异常处理 为了提高效率 然而 在我的软件中 我广泛使用异常处理 如果我将所有回调函数包装在 try catch blocks 中 这样就不需要
  • badref 是什么意思?

    IR线是什么意思 define i32
  • 在源代码上添加一个新属性,该属性会传播到 LLVM 中的 MC 级别?

    我对以下内容的传播方式感兴趣 void foo int attribute aligned 16 p 在这种情况下 指针的 对齐 在 MC 级别可用 但显然没有使用 LLVM IR 元数据方法来实现这一点 对齐信息对于某些目标非常重要 这些
  • llvm OCaml 绑定

    我正在研究 llvm OCaml 绑定 我通过 opam 安装了 llvm 包 opam install llvm 当我在 utop 中使用 llvm 时 出现以下错误 require llvm Error The external fun
  • 使用 Clang AST 打印函数的参数

    我想将参数传递给函数 例如 如果我接到电话 printf d d i j 输出应该是 d dij 我可以使用 RecursiveASTVisitor 中的 VisitCallExpr 进行函数调用 还能够获取参数数量和参数类型 但我不知道如
  • MSYS2环境的使用

    我想彻底了解MSYS2平台环境的使用情况 部分描述可在以下位置找到 https www msys2 org docs environments https www msys2 org docs environments 我理解的事情 MSY
  • 如何从 LLVM 的中间表示中获取程序每个函数中执行的函数调用列表?

    我正在尝试使用 LLVM 构建一个简单版本的代码分析工具 我有一些 ll 文件 其中包含某些程序的中间 LLVM 表示 如何从 LLVM 的中间表示中获取程序每个函数中执行的函数调用列表 我的输入参数是 LLVM Module 类的一个实例
  • 使用 LLVM 为整个源代码生成 CFG

    LLVM 社区的任何人都知道是否有一种方法可以使用以下方法为整个输入源代码生成 CFG opt dot cfg foo ll bc 由于此函数为每个函数生成 CFG 因此函数之间的连接将被忽略 看来旧的分析工具已经贬值了 我想知道你是否找到
  • 使用 libclang 从内存中的 C 代码生成程序集

    我需要实现一个使用 LLVM Clang 作为后端将 C 代码编译为 eBPF 字节码的库 代码将从内存中读取 我也需要在内存中获取生成的汇编代码 到目前为止 我已经能够使用以下代码编译为 LLVM IR include
  • C++11 的 LLVM&Clang 支持

    我有一些为 MS VC 10 编写的代码 我使用 C 11 特别是像这样的表达式 std function
  • XCode 4.2 编译器错误

    当我使用 XCode 4 2 创建新项目 例如 单视图 iOS 应用程序 时 支持文件 文件夹中的 main m 文件如下所示 import
  • LLVM cpp 后端,它会取代 c 后端吗?

    我的问题是关于 CPP 后端 它与 C 后端的用途相同吗 C 后端是我最喜欢的 LLVM 功能之一 我对它被删除感到非常沮丧 真正的区别是什么 我非常感谢任何帮助 参考 LLVM 3 1 发行说明 http llvm org release
  • 从什么时候起 Xcode 不再需要前向方法声明,为什么?

    我注意到 Xcode 或更准确地说是 Apple LLVM 编译器 不再需要前向方法声明 换句话说 构建以下代码时不会发出警告 implementation Foo void foo self bar void bar end 这曾经发出警
  • 是否可以使用 gold 链接器编译和链接 Clang/LLVM?

    我正在为 LLVM Clang 编写自定义通道 重新编译往往需要一段时间并使用大量内存 我听说 gold 链接器 1 比标准 ld 链接器花费更少的时间并且 2 使用更少的内存 有没有办法将标志传递到 LLVM Clang 构建过程并更改为
  • 如何从 LLVM 指令获取文件名和目录?

    我需要在 llvm 过程中提取目录和文件名 当前版本的 llvm 已移动getFilename and getDirectory from DebugLoc to DebugInfoMetadata 我找不到班级成员getFilename直
  • 一个单元在哪一级测试无锁代码?

    Can LLVM https packages debian org stretch llvm QEMU https packages debian org stretch qemu kvm GDB https packages debia

随机推荐

  • python经典面试题之交换a和b两个数的值

    a b两个值交换 不借助第三个变量如何进行交换 通过异或 交换a b个值 我们要知道异或的规则 就是 0 0 0 1 1 0 0 1 1 0 5 5 0 x x x x 0 知道这个了之后 我们再去看下面的异或交换a b两个值 看看它是怎样
  • 二级域名的查找与扫描

    关于域名的概念我不在这里做过多介绍 关于查找和扫描二级域名的作用 我想对于每一个搞渗透的同志来说是至关重要的 就一点 当主站无从下手的时候 你可以从C段 同IP站点下手 但往往二级域名站点存在的潜在 漏洞 概率是非常高的 同时 这也对摸清目
  • 运维经验记录 在CentOS上挂载Windows共享磁盘

    1 需求 非root用户 普通用户 能够读写windows共享目录 比如查看文件 创建文件 修改文件 删除文件 让普通用户也可以正常读写 uid value and gid value Set the owner and group of
  • 大数据项目-用flink实现用户行为分析二

    实时流量统计 利用用户的偏好行为 例如点击浏览等 对用户进行流量统计 执行步骤 创建一个NetworkFlowAnalysis子模块 将apache服务器的日志文件复制到资源文件目录下 我们将从中读取数据 1 基于服务器log的热门页面浏览
  • SQL 外键约束

    概念 外键用来让2张表的数据之间建立连接 从而保证数据的一致性和完整性 添加外键 第一种 在建表时直接添加 CREATE TABLE 表名 字段名 数据类型 CONSTRAINT 外键名称 FOREIGN KEY 外键字段名 REFEREN
  • Web Service

    1 1 Web Service 基本概念 Web Service 也叫 XML Web Service WebService 是一种可以接收从 Internet 或者 Intranet 上的其它系统中传递过来的请求 轻量级的独立的通讯技术
  • ajax填充没显示出来,ajax请求数据成功,页面的数据没有加载出来

    w3c的ajax的例子 点击按钮 ajax请求读取一个本地ajax txt文件 页面展示其内容 在chrome中打开页面 点击按钮请求成功 但是页面没有显示ajax txt的内容 这是为什么呢 代码和chrome截图如下 function
  • python 虚拟环境

    使用虚拟环境 创建一个完全独立的局部python环境 在此环境中 安装所有与这个项目相匹配的库 一个项目使用一个局部的独立的python环境 互相之间没有干扰 这个局部的独立的python环境就称为虚拟环境 完全模拟系统全局python环境
  • 达梦数据库 linux安装配置步骤

    数据库服务器安装 root TKWOA NWEB5 mount o loop data soft dm8 20210630 x86 rh6 64 ent 8 1 2 18 pac iso mnt root TKWOA NWEB5 root
  • 深度学习-yolov3

    卷积层 从一张完整图片中提取多个特征 池化层 选择一部分最明显的特征 全连接层 将最终选择的特征放在一起组合输出 残差网络 ResNet BN 详解 详解 博文 卷积神经网络中卷积层 池化层 全连接层的作用 池化层作用 shinemyang
  • mobaxterm连接到Linux虚拟机

    软件 VMware CentOS 7 mobaxterm 一 查看虚拟机host 在VMware启动虚拟机后 点击应用程序 再点击终端进入 输入ifconfig查看虚拟机host和用户名 密码是创建虚拟机时设的 红框是虚拟机的ip 下面的是
  • Qt程序crash定位问题

    文章目录 问题 思路 从windos日志获取出错位置 启动Qt命令行环境 问题 Qt程序由于某种未知错误Crash掉 如何定位到出错位置 思路 固件开发时 出错时KDB会弹出少数出错信息 包含出错位置 调用堆栈 可以由出错地址 配合objd
  • lab5:深入理解进程切换

    Linux中的进程切换由context switch函数完成 该函数位于源代码目录的kernel sched core c 中 代码如下 context switch函数 context switch switch to the new M
  • QWidget设置背景图及圆角

    在Qt开发过程中 QWidget是经常作为主窗体的父窗口 有时我们需要对主窗口设置背景 设置圆角以达到美观的效果 通常的有以下三种方法 qss QPalette设置以及paintEvent绘制 下面介绍这三种方法 背景设置介绍 方法一 se
  • Redis4 - 编译安装&连接

    下载安装 redis连接 redis信息查询 下载安装 1 源码下载 https redis io 目前最新版本 4 11 2 解压到指定文件夹 eg 我的放到 build下 3 编译 安装 cd build redis 4 0 11 新建
  • 简单快速复制CSDN上的博客到自己的电脑上(带图片和格式)

    准备工具 typora md编辑器 直接去官网https www typora io 下载 一直点下一步 下载好了后界面是这样的 清爽且好用 需要做一点设置 文件 偏好设置 图像 如下设置 软件已经安装好并且可以使用了 看到这里可能你会有疑
  • ctex插入中文的方法

    documentclass 12pt article 使用中日韩的文字宏包 usepackage CJK begin document 插入中文 hei 表示字体为黑体 kai 楷 li 隶 song 宋 begin CJK GBK hei
  • Python 面向对象详细讲解

    Python 面向对象详细讲解 Python从设计之初就已经是一门面向对象的语言 正因为如此 在Python中创建一个类和对象是很容易的 本章节我们将详细介绍Python的面向对象编程 如果你以前没有接触过面向对象的编程语言 那你可能需要先
  • 声音“三要素”---响度(loudness),音高(pitch),音色(timbre)

    由于人耳听觉系统非常复杂 迄今为止人类对它的生理结构和听觉特性还不能从生理解剖角度完全解释清楚 所以 对人耳听觉特性的研究目前仅限于在心理声学和语言声学 人耳对不同强度 不同频率声音的听觉范围称为声域 在人耳的声域范围内 声音听觉心理的主观
  • LLVM系列第十八章:写一个简单的IR处理流程Pass

    系列文章目录 LLVM系列第一章 编译LLVM源码 LLVM系列第二章 模块Module LLVM系列第三章 函数Function LLVM系列第四章 逻辑代码块Block LLVM系列第五章 全局变量Global Variable LLV