Tag: punning

严格别名和内存对齐

我有性能关键代码,并且有一个巨大的函数,在函数开始时在堆栈上分配40个不同大小的数组。 这些arrays中的大多数必须具有一定的对齐性(因为这些arrays是使用需要内存对齐的cpu指令(对于Intel和arm CPU)在链中的其他位置访问的。 由于某些版本的gcc无法正确对齐堆栈变量(特别是对于arm代码),或者甚至有时它表示目标体系结构的最大对齐小于我的代码实际请求的对齐,我别无选择,只能分配这些数组在堆栈上并手动对齐它们。 因此,对于每个数组,我需要做类似的事情才能使它正确对齐: short history_[HIST_SIZE + 32]; short * history = (short*)((((uintptr_t)history_) + 31) & (~31)); 这样, history现在在32字节边界上对齐。 对所有40个数组执行相同的操作非常繁琐,而且这部分代码实际上是cpu密集型的,我根本无法对每个数组执行相同的对齐技术(这种对齐混乱会使优化器混淆并且不同的寄存器分配会降低函数的使用时间,为了更好的解释,请参阅问题末尾的解释)。 所以…显然,我只想做一次手动对齐,并假设这些数组一个接着一个。 我还为这些数组添加了额外的填充,以便它们总是32个字节的倍数。 那么,我只需在堆栈上创建一个jumbo char数组并将其转换为包含所有这些对齐数组的结构: struct tmp { short history[HIST_SIZE]; short history2[2*HIST_SIZE]; … int energy[320]; … }; char buf[sizeof(tmp) + 32]; tmp * X = (tmp*)((((uintptr_t)buf) + 31) & (~31)); 这样的事情。 也许不是最优雅的,但它产生了非常好的结果,并且生成的组件的手动检查certificate生成的代码或多或少是足够的和可接受的。 构建系统已更新为使用更新的GCC,突然我们开始在生成的数据中有一些工件(例如,即使在具有禁用的asm代码的纯C构建中,validation测试套件的输出也不再精确)。 调试问题花了很长时间,它似乎与别名规则和更新版本的GCC有关。 那么,我该怎么做呢? […]