我刚刚完成了一项测试,作为求职面试的一部分,一个问题让我感到难过 - 甚至使用谷歌作为参考.我想看看stackoverflow工作人员可以用它做什么:
"memset_16aligned"函数需要传递给它的16byte对齐指针,否则它将崩溃.
a)如何分配1024字节的内存,并将其与16字节边界对齐?
b)执行memset_16aligned后释放内存.
{
void *mem;
void *ptr;
// answer a) here
memset_16aligned(ptr, 0, 1024);
// answer b) here
}
Run Code Online (Sandbox Code Playgroud) 在我的程序中,我有一个功能,可以添加一个简单的向量c[0:15] = a[0:15] + b[0:15].功能原型是:
void vecadd(float * restrict a, float * restrict b, float * restrict c);
Run Code Online (Sandbox Code Playgroud)
在我们的32位嵌入式架构中,有一个加载/存储双字加载/存储选项,如:
r16 = 0x4000 ;
strd r0,[r16] ; stores r0 in [0x4000] and r1 in [0x4004]
Run Code Online (Sandbox Code Playgroud)
GCC优化器识别循环的向量性质并生成代码的两个分支 - 一个用于3个数组是双字对齐的情况(因此它使用双重加载/存储指令)而另一个用于数组的情况是字对齐的(它使用单个加载/存储选项).
问题是地址对齐检查相对于加法部分是昂贵的,我想通过暗示编译器a,b和c始终是8对齐来消除它.是否有一个修饰符添加到指针声明以告诉编译器?
用于调用此函数的数组具有aligned(8)属性,但它不会反映在函数代码本身中.是否可以将此属性添加到函数参数?
gcc是否具有内存对齐编译指示,类似于#pragma vector aligned英特尔编译器?我想告诉编译器使用对齐的加载/存储指令优化特定的循环.为了避免可能的混淆,这不是结构包装.
例如:
#if defined (__INTEL_COMPILER)
#pragma vector aligned
#endif
for (int a = 0; a < int(N); ++a) {
q10 += Ix(a,0,0)*Iy(a,1,1)*Iz(a,0,0);
q11 += Ix(a,0,0)*Iy(a,0,1)*Iz(a,1,0);
q12 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,0,1);
q13 += Ix(a,1,0)*Iy(a,0,0)*Iz(a,0,1);
q14 += Ix(a,0,0)*Iy(a,1,0)*Iz(a,0,1);
q15 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,1,1);
}
Run Code Online (Sandbox Code Playgroud)
谢谢
我正在尝试使用alignas作为类成员的指针,坦率地说,我不确定我应该把它放在哪里.
例如:
class A
{
private:
int n;
alignas(64) double* ptr;
public:
A(const int num) : n(num), ptr(new double[num])
{}
};
Run Code Online (Sandbox Code Playgroud)
我希望能确保ptr的数据在64字节块上对齐.使用英特尔编译器,它没有.
有人能指出我正确的方向吗?
对于以下循环,如果我告诉它使用关联数学,例如,GCC将仅对循环进行矢量化-Ofast.
float sumf(float *x)
{
x = (float*)__builtin_assume_aligned(x, 64);
float sum = 0;
for(int i=0; i<2048; i++) sum += x[i];
return sum;
}
Run Code Online (Sandbox Code Playgroud)
这是装配 -Ofast -mavx
sumf(float*):
vxorps %xmm0, %xmm0, %xmm0
leaq 8192(%rdi), %rax
.L2:
vaddps (%rdi), %ymm0, %ymm0
addq $32, %rdi
cmpq %rdi, %rax
jne .L2
vhaddps %ymm0, %ymm0, %ymm0
vhaddps %ymm0, %ymm0, %ymm1
vperm2f128 $1, %ymm1, %ymm1, %ymm0
vaddps %ymm1, %ymm0, %ymm0
vzeroupper
ret
Run Code Online (Sandbox Code Playgroud)
这清楚地表明循环已被矢量化.
但是这个循环也有一个依赖链.为了克服添加的延迟,我需要在x86_64上展开并执行至少三次部分和(不包括Skylake,需要展开八次并使用需要在Haswell和Broadwell上展开10次的FMA指令进行添加) .据我所知,我可以展开循环-funroll-loops.
这是装配-Ofast -mavx -funroll-loops.
sumf(float*):
vxorps …Run Code Online (Sandbox Code Playgroud) 我需要使用GCC向量扩展来访问未对齐的值
下面的程序崩溃了 - 包括clang和gcc
typedef int __attribute__((vector_size(16))) int4;
typedef int __attribute__((vector_size(16),aligned(4))) *int4p;
int main()
{
int v[64] __attribute__((aligned(16))) = {};
int4p ptr = reinterpret_cast<int4p>(&v[7]);
int4 val = *ptr;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我改变
typedef int __attribute__((vector_size(16),aligned(4))) *int4p;
Run Code Online (Sandbox Code Playgroud)
至
typedef int __attribute__((vector_size(16),aligned(4))) int4u;
typedef int4u *int4up;
Run Code Online (Sandbox Code Playgroud)
生成的汇编代码是正确的(使用未对齐的加载) - 在clang和gcc中.
单一定义有什么问题或者我错过了什么?clang和gcc都可以是同一个bug吗?
注意:它发生在clang和gcc中
我在其他帖子中写过这个问题。虽然事实并非如此。
GCC编译器版本:4.8.3(适用于ARM)
代码摘录:
uint8_t data[4] __attribute__ ((aligned (8))) = {1,2,3,4};
int main()
{
uint32_t p = 0;
p = (uint32_t)&data[0];
p = (uint32_t)&data[1];
p = (uint32_t)&data[2];
p = (uint32_t)&data[3];
}
Run Code Online (Sandbox Code Playgroud)
请注意,数据位于任何函数之外,因此不会在堆栈中分配。
我看到的结果(调试时)是p:536870912, 536870913, 536870914, 536870915;
我期待这样的事情:536870912, 536870920, 536870928, 536870936
任何帮助将非常感激。