我已经为 LLVM 代码生成器后端编写了低级优化。基本上,优化将在基本 block 级别重新排序汇编指令,以允许稍后(现有)优化更有效地优化结果代码。有很多测试用例我想验证,我想对测试过程提出一些建议,因为这是我第一次尝试这样的事情。
到目前为止我考虑过的事情:
编译用 C 编写的基准测试,并检查使用
-S
选项生成的结果 ASM。我这样做了,并将我的优化结果与原始结果进行了比较。这种方法让我看到我的优化有效,但即使我编写自定义不可执行的 C 文件,我也无法检查所有我想要的指令排序测试用例。将基准编译为 LLVM 程序集,对其进行编辑,然后将 ASM 降低到目标机器程序集。这可能有效,但由于 LLVM 和目标 ASM 之间的抽象级别不同,我怀疑我是否能够通过攻击 LLVM ASM 来检查所有测试用例,直到它生成我想要的结果。
使用目标 ASM 测试用例作为 LLVM 的输入,并使用新的优化重新编译。我无法为 LLVM 或 gcc(LLVM 接受的大部分选项)找到接受 ASM 作为输入的选项。
在验证低级 ASM 编译器优化时,测试特定 ASM 测试用例的好策略是什么?LLVM(或 gcc)是否有一些命令行选项可以简化此过程?
编辑:澄清一下,我不是在问自动生成 ASM 测试用例;我的问题是我有那些测试用例(例如,ASM_before.s
和 reference_ASM_after.s
),但我需要能够通过 ASM_before.s
到 LLVM 中,并确保优化后的输出 ASM_after.s
与已知良好的 reference_ASM_after.s
相匹配。我正在寻找一种方法来执行此操作,而不必将 ASM_before.s
“反编译”为高级语言,然后将其(通过优化)编译为 ASM_after.s
.
最佳答案
基准测试是其中一种滑坡,你可以想出一个基准来让任何语言或工具看起来好或坏,这取决于你试图证明什么。
首先,我通常在没有操作系统的 arm 平台上工作,因此对执行时间进行计时非常简单,有时精确到时钟,加上或减去一个来比较编译器或选项。
特别是当您进入带有缓存的平台时,情况会变得更糟。如果您在启动代码中添加或删除 nop,导致整个程序更改其在内存中的位置,这意味着所有内容都会更改其缓存对齐方式,而没有任何编译器优化更改,您有时会发现缓存导致的性能差异比编译器或后端的差异更多优化。
我通常运行 dhrystone,但不要以此宣告胜利或失败。如果您使用 float 或带有软 fpu 的磨刀石,您可能还想做磨刀石。
正如上面有人提到的,自检测试是个好主意。现实世界的代码也是如此。例如压缩例程,获取一些文本(可能是 gutenburg 项目的一本书的一部分),压缩它,然后解压缩它并将输出与输入进行比较,您可以通过在主机等控制平台上压缩它来添加额外的验证如果被测试的压缩版本不匹配但它获得正确的输出但它仍然失败,则将压缩大小硬编码到测试中。我还使用了 jpeg 库将图像从 jpeg 转换为 jpeg,如果图像不希望通过有损压缩返回到其原始状态,那么您可以只进行一次传输和校验和或验证大小或携带一份预期输出并进行比较。 aes和des加解密。
您可以将大量开源项目与修改后的编译器一起使用,以将其与标准编译器或其他编译器进行比较。作为真实世界的代码,您的编译器无论如何都会使用这种代码。请注意,当您访问 toms hardware 或其他基准测试站点时,有许多不同的基准测试,渲染某些东西所花费的时间,编译 gcc 或 linux 或执行数据库搜索所花费的时间,一堆真实世界的应用程序。并且各种应用程序获得不同的分数,非常罕见的是一个平台/解决方案横扫电池测试。
当您在进行更改时性能下降时,就是您检查汇编器并尝试找出原因的时候了。记住 Michael Abrash(和其他人)所说的话,无论您认为您的汇编程序有多好,您仍然需要为它计时。还可以尝试一些您确定会变慢的疯狂事情,因为有时您会出于您从未想过的原因发现它们很快。
关于测试代码生成器优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6084052/