我需要修补一个现有的指令集测试,因为它没有测试所有使用的指令。所以我需要查看一个代码级别的汇编文件,找出导致指令发生的C代码,以便在我的补丁中使用它。
你的目标是疯狂的,并且你问题的前半部分是反向的/只与你真正的问题松散相关。可能有一种方法可以说服编译器使用你想要的每个特定指令,但这将是特定于你的编译器版本、选项和所有周围的代码,包括头文件中的常量。如果你想测试一个ISA中的所有指令,希望能够以某种方式说服C编译器生成它们,那么完全是错误的方法。你希望你的测试在未来继续测试相同的东西,所以你应该写汇编代码,如果你需要特定的汇编语言。
这是几周前针对ARM提出的相同问题:如何强制IAR使用期望的Cortex-M0+指令(将禁用此函数的优化),只不过您说您将启用优化构建(这可能会使得生成更广泛的指令更容易:有些只能用作简单常规代码生成的窥孔优化)。
此外,从汇编语言开始并将其反向转换为等效的 C 代码,并不能保证编译器在编译时选择该指令,因此问题标题只与您实际问题 loosly 相关。
如果你仍然想要手动编译生成特定的汇编代码,创建脆弱的源代码,只能在特定的编译器/版本/选项下实现你想要的功能,那么第一步就是思考“这条指令何时会成为优化方式的一部分?”。
通常,这种思路更适用于通过调整源代码来进行优化。首先,你需要考虑一个函数的高效汇编实现。然后,你可以使用相同的临时变量编写C或C++源代码,希望编译器也会使用这些变量。例如,请参见如何高效计算比特位,我能够手动引导gcc使用更高效的指令序列,就像clang对我的第一次尝试所做的那样。
有时候这种方法很有效;当指令集只有一种非常好的做法时,对于您的目的来说,它是简单的。例如,
ld.bu
看起来像是将一个字节加载到一个完整寄存器中并进行零扩展(
u
表示无符号)。
unsigned foo(unsigned char*p) {return *p;}
应该编译成这样,您可以使用
noinline
属性防止其被优化掉。
但是,如果insert
是将零位插入到位域中,则同样可以使用~1
(0xFE)进行and
,假设TriCore具有与立即数的与操作。如果insert
有一个非立即数形式,则对于single-bit bitfield = rand()
(或任何在常量传播优化后仍不是编译时常量的值),这可能是最有效的选项。
对于TriCores的打包算术(SIMD)指令,您需要编译器自动矢量化或使用内部函数。
在ISA中可能会有一些指令,你的编译器永远不会发出。尽管我认为你只是想测试编译器在代码其他部分发出的指令?你说“所有使用的指令”,而不是“所有指令”,所以这至少保证了任务是可能的。
一种带有参数的非内联函数是强制运行时变量代码生成的绝佳方式。我们经常查看编译器生成的汇编代码并编写小函数来使用参数返回值(或存储到全局或
volatile
),以便在不丢弃结果或常量传播将整个函数转换为
return 42;
(即
mov
-immediate /
ret
)的情况下,强制编译器为某些内容生成代码。请参见
如何从GCC/clang汇编输出中去除“噪音”?了解更多信息,并查看Matt Godbolt的CppCon2017演讲:“
我的编译器最近为我做了什么?打开编译器的盖子”,其中介绍了阅读编译器生成的汇编代码的初学者入门知识以及现代优化编译器为小函数执行的操作类型。
如果使用volatile
赋值并读取该变量,即使测试需要在没有外部输入的情况下运行,这也是打败常数传播的另一种方法,如果使用不带内联函数比较容易。 (编译器必须从C源中每次单独读取volatile
,即它们必须假设它可能被异步修改。)
int main(void) {
volatile int vtmp = 123;
int my_parameter = vtmp;
... then use my_parameter, not vtmp, so CSE and other optimizations can still work
}
[...] 它已经被优化了。
您展示的编译器输出看起来并不是经过优化的。它看起来像是加载/设置位/存储,然后加载/清除位/存储,这应该优化为只加载/清除位/存储。除非这些汇编块不是真正连续的,并且您正在显示从两个不同的块粘贴在一起的代码。
此外,InsertStruct.SomeMember = 0x0u;
是一个不完整的描述:它显然取决于结构体定义;我假设您使用了一个 int SomeMember :1;
单比特位域成员?根据我找到的 TriCore ISA参考手册,insert
将一个寄存器中的一系列位复制到另一个寄存器中,在指定的插入位置处,并以寄存器和立即源形式存在。
替换整个字节可能只需要进行存储而不是读取/修改/写入。因此,关键在于结构体定义,而不仅仅是编译为指令的语句。
x / 15
,或通过直接计算结果来删除整个循环求和值等等...如果您试图从这样的汇编重构C源代码,则最终将得到完全不同的源代码(算法方面)。 - Ped7g