我们在Debug版本下有一个断言触发,用于检查对齐。断言用于使用uint8x16_t
加载到vld1q_u8
的字节数组。当断言触发时,我们没有观察到SIG_BUS
。
以下是代码中的用法:
const byte* input = ...;
...
assert(IsAlignedOn(input, GetAlignmentOf(uint8x16_t));
uint64x2_t message = vreinterpretq_u64_u8(vld1q_u8(input));
我也尝试了以下内容,并且断言触发uint8_t*
的对齐:
assert(IsAlignedOn(input, GetAlignmentOf(uint8_t*));
uint64x2_t message = vreinterpretq_u64_u8(vld1q_u8(input));
使用uint8x16_t
将字节数组加载到vld1q_u8
时,字节数组有哪些对齐要求?
在上面的代码中,input
是函数参数。 IsAlignedOn
检查其两个参数的对齐方式,确保第一个参数与至少第二个对齐。 GetAlignmentOf
是一个抽象,用于检索类型或变量的对齐方式。
uint8x16_t
和uint64x2_t
是128位ARM NEON向量数据类型expected to be placed in a Q register。 vld1q_u8
是一条NEON伪指令,预计会被编译成VLD1.8
指令。 vreinterpretq_u64_u8
是一个NEON伪指令,可以简化数据类型的使用。
答案 0 :(得分:4)
编写直接汇编程序(内联文件或外部文件)时,您可以选择是否要指定对齐(例如vld1.8 {q0}, [r0, :64]
)或将其保留(例如vld1.8 {q0}, [r0]
)。如果没有指定,它根本不需要任何特定的对齐,如Dric512所说。
当通过内在函数使用vld1q_u8
时,你实际上并没有指定对齐,所以据我所知,编译器不会假定它,并产生没有对齐规范的指令。我不确定某些编译器是否可以推断出实际保证对齐的一些情况,并在这些情况下使用对齐说明符。 (在这种特殊情况下,gcc,clang和MSVC似乎都生成vld1.8
而没有对齐说明符。)
请注意,这只是32位手臂的问题;在AArch64中,ld1
指令没有对齐说明符。但即使在那里,对齐仍然显然有帮助,如果你使用未对齐的地址,你的性能会更差。
答案 1 :(得分:3)
将{16}字节加载到Quad寄存器的 import csv
# expected codes and their replacements
CODES = {
'50': 'order now',
'999': 'no order necessary',
'500': 'order next month',
'amount available': 'order timeline'
}
# you can multiple with statements in one
with open('input.csv', 'r') as fp_in, open('output.csv', 'w') as fp_out:
reader = csv.reader(fp_in)
writer = csv.writer(fp_out)
for row in reader:
val = row[2].strip() # deal with the weird spaces
val = CODES.get(val, val) # see if this is a known constant, and replace if exists
row[2] = ' ' + val # add space back and insert back into row
writer.writerow(row)
指令的自然对齐是一个字节。这意味着即使不允许未对齐的传输,该指令也不会出错。
所以看起来这个特定的断言是不正确的。
答案 2 :(得分:2)
从另一端看这个,从一个示例编译器(Visual Studio 2015的arm_neon.h
)的角度来看,这是该类型的实际定义:
typedef union __declspec(intrin_type) _ADVSIMD_ALIGN(8) __n128
{
unsigned __int64 n128_u64[2];
unsigned __int32 n128_u32[4];
unsigned __int16 n128_u16[8];
unsigned __int8 n128_u8[16];
__int64 n128_i64[2];
__int32 n128_i32[4];
__int16 n128_i16[8];
__int8 n128_i8[16];
float n128_f32[4];
struct
{
__n64 low64;
__n64 high64;
} DUMMYNEONSTRUCT;
} __n128;
...
typedef __n128 int8x16_t;
所以,至少在Windows平台上,由于该联合,所需要的__int64
和AAPCS的对齐意味着8个字节(即使没有 - 非常具有挑战性地猜测_ADVSIMD_ALIGN(8)
可能意味着什么......)
容器化矢量的内容对于大多数过程调用标准是不透明的:其布局中唯一定义的方面是存储器格式(基本类型存储在存储器中的方式)与不同类型的寄存器之间的映射。过程调用接口。
换句话说,在ABI级别,矢量类型是矢量类型,无论其中可能包含或不包含什么,并且64位和128位容器化矢量都需要8字节对齐,因为ABI说所以(§4.1)。因此,无论底层指令可能具备什么功能,微软的实现都不像我最初推测的那样过于严格,它只是符合要求。 八个是你要对齐的数字,对齐的数量应该是八个。
另一方面,vld1q_u8()
的参数是uint8_t const *
,其指向的数据没有对齐要求,因此断言它满足8字节对齐可能会失败很多。