如果加载/存储必须拆分或跨越缓存行,则至少需要一个额外的周期。
有详尽的表格指定了Cortex-A8(按顺序)和Cortex-A9(部分OoO)的各种对齐所需的周期数和寄存器数。例如,带有一个 reg 的 vld1 对于未对齐访问与 64 位对齐访问相比,有 1 个周期的惩罚。
Cortex-A55(按顺序)最多可进行 64 位加载和 128 位存储,因此,its optimization manual 的第 3.3 节指出以下情况会产生 1 个周期的惩罚:
• 加载跨越 64 位边界的操作
• 跨越 128 位边界的 128 位存储操作
根据its optimization guide 的第 5.4 节,Cortex-A75 (OoO) 有以下处罚:
• 加载跨越 64 位边界的操作。
• 在 AArch64 中,所有跨越 128 位边界的存储。
• 在 AArch32 中,所有跨越 64 位边界的存储。
正如吉列尔莫的回答一样,A57 (OoO) 会受到以下处罚:
• 跨越缓存线(64 字节)边界的加载操作
• 跨 [128 位] 边界的存储操作
考虑到 A55 和 A75 跨越 64 位边界,我有点怀疑 A57 不会受到惩罚。所有这些都有 64 字节的缓存线;他们也应该因跨越缓存线而受到处罚。最后,注意有unpredictable behavior for split access crossing pages。
从使用 Cavium ThunderX 的一些粗略测试(没有性能计数器)来看,似乎更接近 2 个周期的惩罚,但这可能是在循环中具有背靠背未对齐加载和存储的附加效应.
AArch64 NEON 指令不区分对齐和未对齐(例如,参见 LD1)。对于 AArch32 NEON,对齐在寻址中静态指定 (VLDn):
vld1.32 {d16-d17}, [r0] ; no alignment
vld1.32 {d16-d17}, [r0@64] ; 64-bit aligned
vld1.32 {d16-d17}, [r0:64] ; 64 bit-aligned, used by GAS to avoid comment ambiguity
我不知道在最近以 AArch32 模式运行的芯片上,没有对齐限定符的对齐访问是否比使用对齐限定符的访问慢。 ARM 的一些旧文档鼓励尽可能使用限定符。 (相比之下,英特尔改进了他们的芯片,使未对齐和对齐的移动在地址对齐时执行相同的操作。)
如果您使用内在函数,MSVC 具有接受对齐的_ex-后缀变体。让 GCC 发出对齐限定符的可靠方法是使用 __builtin_assume_aligned。
// MSVC
vld1q_u16_ex(addr, 64);
// GCC:
addr = (uint16_t*)__builtin_assume_aligned(addr, 8);
vld1q_u16(addr);