AVX加载指令在cygwin上失败

AVX加载指令在cygwin上失败,c,gcc,cygwin,x86-64,avx,C,Gcc,Cygwin,X86 64,Avx,当我在我的机器上运行代码时,程序会出错 #include <immintrin.h> #include <stdint.h> static inline __m256i load_vector(__m256i const * addr){ __m256i res = _mm256_load_si256(addr); return res; } void test2(){ int32_t *src; src = _mm_malloc(siz

当我在我的机器上运行代码时,程序会出错

#include <immintrin.h>
#include <stdint.h>

static inline __m256i load_vector(__m256i const * addr){
    __m256i res = _mm256_load_si256(addr);
    return res;
}
void test2(){
    int32_t *src;
    src = _mm_malloc(sizeof(__m256i), 32);
    __m256i vec = load_vector((__m256i const * )src);
    _mm_free(src);
}

int main(int argc,char *argv[]){
    test2();
    return 0;
}
#包括
#包括
静态内联加载向量(uuum256i const*addr){
__m256i res=_mm256_load_si256(地址);
返回res;
}
void test2(){
int32_t*src;
src=mm_malloc(sizeof(uu m256i),32);
__m256i向量=荷载向量((uu m256i常量*)src);
_mm_-free(src);
}
int main(int argc,char*argv[]){
test2();
返回0;
}
我试着用gdb调试它,当调用_mm256_load_si256时,它会出现分段错误

我在AMD 2990wx CPU上的cygwin gcc上运行代码。
怎么会发生这样的事情呢?

我做了进一步的调试<代码>\u mm\u malloc不是问题,而是局部变量的对齐

在第二次
vmovdqa
将向量存储到调用方的指针时,RAX没有32字节对齐
vec
在test2中似乎没有对齐。
(Cygwin/mingw通过调用方传递隐藏指针的引用返回
\uuuuum256i
向量,这与标准Windows x64调用约定按值返回不同)

这就是已知的Cygwin bug(),Mysticial在评论中链接了它:Cygwin GCC不能安全地使用AVX,因为它没有正确地对齐存储到内存中的
\uuuu m256i
局部变量的堆栈。(Cygwin/MinGW gcc将正确对齐
alignas(32)int-arr[8]={0};
,但它们通过对齐一个单独的指针来完成,而不是RSP或RBP。显然,在堆栈帧操作上存在一些SEH限制)

Clang、MSVC和ICC都正确地支持
\uuuu m256i

启用优化后,gcc通常不会生成错误代码,但有时即使是优化的代码也会将32字节的向量存储/重新加载到堆栈中

_ZL11load_vectorPKDv4_x:
.LFB3671:
    .file 2 "min_case.c"
    .loc 2 4 0
    .cfi_startproc
    pushq   %rbp
    .seh_pushreg    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    .seh_stackalloc 16
    .seh_endprologue
    movq    %rcx, 16(%rbp)
    movq    %rdx, 24(%rbp)
    movq    24(%rbp), %rax
    movq    %rax, -8(%rbp)
.LBB4:
.LBB5:
    .file 3 "/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/avxintrin.h"
    .loc 3 909 0
    movq    -8(%rbp), %rax
    vmovdqa (%rax), %ymm0
.LBE5:
.LBE4:
    .loc 2 5 0
    movq    16(%rbp), %rax
    vmovdqa %ymm0, (%rax)
    .loc 2 6 0
    movq    16(%rbp), %rax
    addq    $16, %rsp
    popq    %rbp
    .cfi_restore 6
    .cfi_def_cfa 7, 8
    ret

\uuu m256i
在此测试用例中未对齐

#include <immintrin.h>
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

const char* check_alignment(const void *ptr, uintptr_t alignment){
    return (((uintptr_t)ptr) & (alignment - 1)) == 0 ? "aligned" : "NOT aligned";
}

static inline __m256i load_vector(__m256i const * addr){
    printf("addr:%s\n", check_alignment(addr, 32));
    __m256i res;
    printf("&res:%s\n", check_alignment(&res, 32));
    res = _mm256_load_si256(addr);
    return res;
}
void test2(){
    int32_t *src;
    src = (int32_t *)_mm_malloc(sizeof(__m256i), 32);
    src[0] = 0; src[0] = 1; src[2] = 2; src[3] = 3;
    src[4] = 4; src[5] = 5; src[6] = 6; src[7] = 7;
    __m256i vec = load_vector((__m256i const * )src);
    _mm_free(src);
}

int main(int argc,char *argv[]){
    test2();
    return 0;
}

// results
// addr:aligned
// &res:NOT aligned
// Segmentation fault
#包括
#包括
#包括
#包括
#包括
常量字符*检查对齐(常量无效*ptr、uintptr对齐){
返回((uintpttr_t)ptr)和(对齐-1))==0?“对齐”:“未对齐”;
}
静态内联加载向量(uuum256i const*addr){
printf(“地址:%s\n”,检查对齐(地址,32));
__m256i res;
printf(“&res:%s\n”,检查对齐(&res,32));
res=_mm256_load_si256(地址);
返回res;
}
void test2(){
int32_t*src;
src=(int32_t*)_mm_malloc(sizeof(u m256i),32);
src[0]=0;src[0]=1;src[2]=2;src[3]=3;
src[4]=4;src[5]=5;src[6]=6;src[7]=7;
__m256i向量=荷载向量((uu m256i常量*)src);
_mm_-free(src);
}
int main(int argc,char*argv[]){
test2();
返回0;
}
//结果
//地址:对齐
//&res:未对齐
//分段故障

在我的机器上工作;我看那里没有什么问题。您可以尝试更仔细地查看gdb,看看哪里出了问题。是什么指令生成了segfault?cygwin gcc的
\u mm_malloc
是否已损坏且未返回32字节对齐的内存?读取未初始化的内存是未定义的行为:@chtz技术上是UB,但我们可以做得更好。我不明白这怎么会导致OP的故障@由于您使用的是cygwin,这可能意味着Windows。您使用的编译器标志是什么?如果是
-O0
,则可能是
res
被放在堆栈上@神秘的我同意这不太可能是断层的原因。因此,我只是将其作为评论发布(当然,我本可以更清楚地表明,这可能是无关的)。