LLVM 测试

Posted by 叉叉敌 on May 19, 2022

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的用法,比如单个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 heo, 期望匹配的是 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博客

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