Llvm 源码结构及测试基础

Llvm 源码结构及测试基础

Llvm 源码目录功能简介

了解一下Llvm源码工程目录介绍、Llvm相关lib库的介绍、Llvm生成的工具链介绍,方便我们后期学习Llvm。

LLVM 源码工程目录介绍

 

 

 一、docs目录

这个目录下存放Llvm各个模块的相关介绍文档。

二、examples目录

这个目录是一些使用LLVM IR和JIT的简单例子。

三、include目录

 

 

 include 目录主要是包含llvm做为lib的c++和c的api头文件。在include下还有三个主要的子目录:

【1】include/llvm

所有LLVM特定的头文件和头文件子目录。子目录对应LLVM各个部分:Analysis,CodeGen,Target,Transforms,etc...

【2】include/llvm/Support

LLVM提供的通用支持工具的lib头文件目录。例如,一些C++ STL小工具和命令行选项相关的lib的头文件会放在该文件夹里。

【3】include/llvm/Config

由cmake配置的头文件。他们包括标准UNIX和C的头文件。源码可以引入这些自动处理的头文件。#include that cmake generates

四、lib目录

 

 

 

 

 这个目录下存放着大部分的源码,将源码放进库中,可以使得LLVM能在一些工具间分享代码。

【1】lib/IR/

核心LLVM源文件,实现了核心的类比如:Instruction和BasicBlock

 【2】lib/AsmParser/

解释汇编语言的源码

 3】lib/Bitcode/

读写字节码的源码

 【4】lib/Analysis/

各种分析程序的源码,例如:Call-Graphs,Induction-Variables,Natural-Loop-Identification,etc

【5】lib/Transforms/

IR-to-IR 程序转换,例如:主动死代码消除,稀疏有条件常量传播,内联,循环不变码变化,死全局消除...

【6】lib/Target/

Target目录是目标平台指令集相关内容,内部代码量很大,具体芯片指令,版本等相关信息都在其中,最新的专有功能,比如AMD,NVIDIA相关的显卡计算目标代码生成也在其中。

【7】lib/CodeGen/

代码生成的主要部分:指令选择器,指令调度以及寄存器分配。

【8】lib/ExecutionEngine/

用于直接在JIT解释器中执行字节码的库。

【9】lib/Support/

对应于llvm/include/ADT和llvm/include/Support的头文件。

五、projects目录

这个目录严格上来说并不是llvm的一部分,是附属于llvm。这个目录可以存放用户自己利用llvm,构建的系统。

六、test目录

LLVM基础结构上的特性和回归测试以及其他健全性检查。它们旨在快速运行并覆盖很多领域,而不会很低效。

七、tools目录

 

 

 这个目录下存放的是由之前介绍过的库文件build而成的可执行文件(工具),这是用户交互的主要部分。

基本命令

  • llvm-as - 汇编器,将 .ll 汇编成字节码。
  • llvm-dis - 反汇编器,将字节码编成可读的 .ll 文件。
  • opt - 字节码优化器。
  • llc - 静态编译器,将字节码编译成汇编代码。
  • lli - 直接执行 LLVM 字节码。
  • llvm-link - 字节码链接器,可以把多个字节码文件链接成一个。
  • llvm-ar - 字节码文件打包器。
  • llvm-lib - LLVM lib.exe 兼容库工具。
  • llvm-nm - 列出字节码和符号表。
  • llvm-config - 打印 LLVM 编译选项。
  • llvm-diff - 对两个进行比较。
  • llvm-cov - 输出 coverage infomation。
  • llvm-profdata - Profile 数据工具。
  • llvm-stress - 生成随机 .ll 文件。
  • llvm-symbolizer - 地址对应源码位置,定位错误。
  • llvm-dwarfdump - 打印 DWARF。

调试工具

  • bugpoint - 自动测试案例工具
  • llvm-extract - 从一个 LLVM 的模块里提取一个函数。
  • llvm-bcanalyzer - LLVM 字节码分析器。

开发工具

  • FileCheck - 灵活的模式匹配文件验证器。
  • tblgen - C++ 代码生成器。
  • lit - LLVM 集成测试器。
  • llvm-build - LLVM 构建工程时需要的工具。
  • llvm-readobj - LLVM Object 结构查看器。

更多工具信息,请参考http://llvm.org/docs/CommandGuide/index.html

八、unittests目录

这个目录下存放Llvm各个模块下的一些单元测试。

九、utils目录

 

 

 LLVM源码的实用程序。有些是构建器的一部分,因为它们是代码生成的一部分。

【1】codegen-diff

codegen-diff找出LLC和LLI生成代码的不同之处。如果你在调试其中一个,另一个是正确的程序,这个工具将对你非常有用。使用命令:perldoc codegen-diff, 获取全部的用户参考手册。

【2】emacs

LLVM汇编文件和TableGen描述文件的Emacs和XEmacs语法高亮。查看README来获取更多的使用信息。

【3】llvmgrep

使用正则表达式查找每个LLVM源文件(在每个文件中执行egrep -H -n re-expression)。这是一个非常高效的基于正则表达式的源文件搜索工具。

【4】TableGen

用于生成寄存器信息,指令集描述,以及其他普通的编译器描述文件。

【5】vim

vim高亮语法文件

结论

学习Llvm库的源码目录结构,有助于我们后期学习Llvm源码。Llvm源码功能目录划分的很清晰,各个模块的耦合性也很低,是一套非常不错的开源代码。学习Llvm源码有助于我们更深入的理解编译器的工作原理和底层的编译原理相关知识。

参考资料

1. http://llvm.org/docs/GettingStarted.html

LLVM:测试基础,llvm-lit、FileCheck

将使用一个例子介绍如何使用 llvm-lit 和 FileCheck 这两个最常用的工具完成测试工作。

llvm-lit,LLVM Integrated Tester,通过 Python 语法编写配置文件,完成对某个项目的测试工作

 FileCheck,一个比 grep 功能更多的文本查找与匹配验证工具,可以帮助程序员确认代码是否正确生成

 这两个工具都可以通过 pip 安装,分别叫 lit 和 filecheck如果使用了 pip 安装,下面的相关工具名请自行更改替换。

关于两个工具的更多使用细节请自行前往相关网站。

下面用一个小例子说明如何使用这两个工具,

1文件结构

.
|-- lit.cfg
`-- main.c

main.c

首先编写一个待测试的文件,

// RUN: cc %s -o %t && %t | FileCheck %s
// CHECK: Hello world
#include <stdio.h>
int main() {
  printf("Hello world\n");
  return 0;
}

在测试文件的顶部加入了待 llvm-lit 去驱动执行的标记以及待执行代码。

很简单,通过 cc 编译当前文件 %s 为一个临时文件 %t,然后执行这个 %t,最后通过 FileCheck 去和原文件中的 CHECK 标记的语句对比,看是否符合预期。

lit.cfg

接下来编写配置文件,

import lit.formats
config.name = "My example"
config.test_format = lit.formats.ShTest(True)
config.suffixes = [".c"]

这里也比较简单,就说明了测试项目的名称、类型、对应文件类型。

2运行

在这两个文件的所在目录,执行

 llvm-lit main.c
-- Testing: 1 tests, 1 workers --
PASS: My example :: main.c (1 of 1)
Testing Time: 0.11s
  Passed: 1

可以看到,这一个测试用例通过了。

3结语

当然,这只是一个很简单的例子。但在更复杂的工程中,他们同样能发挥很好的作用。下期继续介绍如何在一个 cmake 项目中引入 LLVM 测试套件完成测试。

LLVM 测试

LLVM 测试基础设施包含三大类测试: 单元测试、回归测试和整个程序。单元测试和回归测试分别包含在 LLVM 存储在 LLVM/unittest 和 LLVM/test 之下,并且应该始终通过,一般情况作为checkin,即它们应该在每次提交之前运行。

单元测试是使用 Google Test 和 Google Mock 编写的,位于 llvm/unittest 目录中。在一般情况下,单元测试用于针对支持库和其他通用数据结构,我们倾向于依赖回归测试来测试 IR 上的转换和分析。

回归测试是测试 LLVM 特定特性或在 LLVM 中触发特定 bug 的小段代码。它们使用的语言取决于测试的 LLVM 部分。这些测试由 Lit 测试工具(LLVM 的一部分)驱动,位于 LLVM/test 目录中。

通常,当在 LLVM 中发现 bug 时,应该编写一个回归测试,其中包含足够的代码来重现问题,并将该测试放置在这个目录的某个位置。例如,它可以是从实际应用程序或基准中提取的一小段 LLVM IR。

 

 

 mxmvRb

快速入门

测试位于两个独立的存储库中。单元测试和回归测试位于主“ LLVM”目录下的 LLVM/unittest 和 LLVM/test 目录下,(因此您可以通过主 LLVM-project 免费获得这些测试)。在构建 LLVM 之后,使用 make check-all 运行单元测试和回归测试。

测试套件模块包含更全面的测试,包括整个 C 和 C++ 程序。

如何运行单元测试和回归测试

要运行所有 LLVM 单元测试,请使用 check-LLVM-unit 目标:

make check-llvm-unit

要运行所有 LLVM 回归测试,请使用 check-LLVM 目标:

make check-llvm

为了获得合理的测试性能,在编译的时候,应该是-release模式下构建 LLVM-project,编译命令

cmake -DCMAKE_BUILD_TYPE="Release" -DLLVM_ENABLE_ASSERTIONS=On

如果您已经构建了 Clang ,那么您可以使用以下方法同时运行 LLVM 和 Clang 测试:

make check-all

同时还可以给运行测试的用例传递参数, 请使用 LIT_ARGS 变量将所需的选项传递给 LIT。例如,您可以使用:

make check LIT_ARGS="-v --vg --vg-leak"

其他可以参考lit的用法[1],比如单个ll文件或者整个目录。

回归测试的架构

LLVM 回归测试由 lit 驱动,位于 llvm/test 目录中。

这个目录包含大量的小型测试,这些测试使用 LLVM 的各种特性,并确保不会发生回归。这个目录被分成几个子目录,每个子目录都关注 LLVM 的一个特定区域。

如何编译一个新的测试用例

回归测试结构非常简单,但是需要设置一些信息。这些信息通过 cmake 收集并写入构建目录中的文件 test/lit.site.cfg。Llvm/test Makefile文件 为您完成这项工作。

为了使回归测试工作,每个测试目录必须有一个 lit.local.cfg文件。Lit 查找此文件以确定如何运行测试。这个文件只是 Python 代码,因此非常灵活,但是我们已经为 LLVM 回归测试对它进行了标准化。如果要添加一个测试目录,只需从另一个目录复制 lit.local.cfg 即可。标准的 lit.local.cfg 只是指定要查找哪些文件以进行测试。任何只包含目录的目录都不需要 lit.local.cfg 文件。

每个测试文件必须包含以“ RUN:”开头的行,告诉 lit 如何运行它。如果没有 RUN 行,lit 将在运行测试时发出错误。

同时还可以有多个RUN行。RUN 行在测试程序的注释中使用关键字 RUN 后跟冒号和要执行的命令(管道)来指定。这些行组成了 lit 执行以运行测试用例的“脚本”。RUN 行的语法类似于 shell 管道的语法,包括 I/O 重定向和变量替换。但是,即使这些行看起来像 shell 脚本,它们也不是。RUN 行由 lit 解释。因此,语法与 shell 在几个方面有所不同。您可以根据需要指定尽可能多的 RUN 行。

Lit 对每个 RUN 行执行替换操作,以替换 LLVM 工具名,使用为每个工具构建的可执行文件的完整路径(在 $(LLVM_OBJ_ROOT)/$(BuildMode)/bin 中)。这样可以确保 lit 在测试期间不会调用用户路径中的任何其他 LLVM 工具。

每个 RUN 行都是独立执行的,与其他行不同,除非它的最后一个字符是\,和python的换行有点类似。这个延续字符将使 RUN 行与下一行连接起来。通过这种方式,您可以构建长长的命令管道,而不需要制造巨大的行长度。以该行结尾的行被连接起来,直到找到一个不以该行结尾的 RUN 行。然后,这组连接的 RUN 行构成一个执行。Lit 将替换变量并安排管道的执行。如果管道中的任何进程失败,则整个行(和测试用例)也会失败。

下面是.ll 文件中合法的 RUN 行的示例:

; RUN: llvm-as < %s | llvm-dis > %t1
; RUN: llvm-dis < %s.bc-13 > %t2
; RUN: diff %t1 %t2

测试的时候,不会修改文件的内容信息,一般来说,您应该尽量保持您的RUN 行尽可能简单,只使用它们来运行生成文本输出的工具,然后您可以检查这些工具。检查输出以判断测试是否通过的推荐方法是使用 FileCheck 工具。[不推荐在 RUN 行中使用 grep-请不要发送或提交使用它的补丁程序。]

自动生成断言

有些回归测试用例非常大,手工编写/更新非常复杂。在这种情况下,为了减少人工工作,我们可以使用 llvm/utils/中提供的脚本来生成断言。

例如,要在基于 llc 的测试中生成断言,请运行:

llvm/utils/update_llc_test_checks.py --llc-binary build/bin/llc test.ll

除了生成,还可以更新断言信息-u

以下是生成断言时最常见的脚本及其用途/应用程序:

update_analyze_test_checks.py
opt -passes='print<cost-model>'
 
update_cc_test_checks.py
C/C++, or clang/clang++ (IR checks)
 
update_llc_test_checks.py
llc (assembly checks)
 
update_mca_test_checks.py
llvm-mca
 
update_mir_test_checks.py
llc (MIR checks)
 
update_test_checks.py
opt

高级用法

如果您的测试需要除了包含 RUN: 行的文件之外的其他文件,并且额外的文件很小,那么可以考虑在同一个文件中指定它们,并使用 split-file 来获取它们。比如说,

; RUN: split-file %s %t
; RUN: llvm-link -S %t/a.ll %t/b.ll | FileCheck %s
 
; CHECK: ...
 
;--- a.ll
...
;--- b.ll
...

上面分隔的用的;--- a.ll,符合这个即可^(.|//)--- <part>.

如果您想要测试像 [[#@LINE+1]] 这样的相对行号,那么指定 --leading-lines 以添加前导空行来保留行号。

期望匹配和不期望匹配,

;CHECK: xx 这个是期望匹配
;CHECK-NOT:期望不匹配

为了保持健壮性,始终在 RUN 行中使用 xxx .. < %s

平台测试

比如有nvidia、adm、x86、metax等等,此外,如果测试依赖于在任何后端中编码的任何行为,那么它必须放在自己的目录中。

因此,例如,ARM 的代码生成器测试进入 test/CodeGen/ARM 等。这些目录包含一个特殊的指定配置文件,确保该目录中的所有测试只有在特定的后端已编译并可用时才会运行。

在 test/CodeGen/ARM 中,这个文件lit.local.cfg 是内容是:

config.suffixes = ['.ll', '.c', '.cpp', '.test']
if not 'MetaX' in config.root.targets:
  config.unsupported = True

测试约束

有些测试只能在特定的配置中运行,例如使用调试构建或在特定的平台上运行。使用 REQUIRES 和 UNSUPPORTED 控制何时启用测试。

比如:一些测试预计会失败。例如,测试可能检测到一个已知的 bug。使用 XFAIL 将测试标记为预期失败。如果执行失败,XFAIL 测试将成功; 如果执行成功,XFAIL 测试将失败。

; This test will be only enabled in the build with asserts.
; REQUIRES: asserts
; This test is disabled on Linux.
; UNSUPPORTED: -linux-
; This test is expected to fail on PowerPC.
; XFAIL: powerpc

REQUIRES、 UNSUPPORTED 和 XFAIL 都接受以逗号分隔的布尔表达式列表

  • REQUIRES 如果所有表达式都为 true,则启用测试
  • UNSUPPORTED 如果任何表达式都为 true,则禁用测试
  • XFAIL 如果任何表达式都为 true,则预期测试失败

还有检查点可以使用正则表达,比如;CHECK: load he{{l+}}o, 期望匹配的是 load helo|hello|hellllo等。

Read more

https://www.youtube.com/watch?v=VFHYaH5Vr4I&ab_channel=LLVM

https://llvm.org/docs/TestingGuide.html#extra-files

github博客[2]

微信公众号:cdtfug, 欢迎关注一起吹牛逼,也可以加微信号「xiaorik」朋友圈围观。

参考:

 [1]  lit的用法: https://llvm.org/docs/CommandGuide/lit.html

[2] github博客: https://chasays.github.io/

 

 

参考文献链接

https://mp.weixin.qq.com/s/4PnCYGMF-ktoC4N72x6neA

https://mp.weixin.qq.com/s/TUBYSBP0DqWxWvRz4IiERw

https://mp.weixin.qq.com/s/gsK1TJW2mo2vnesnin8ShA

posted @ 2023-02-17 04:39  吴建明wujianming  阅读(2442)  评论(0编辑  收藏  举报