我正在尝试用LLVM自动矢量化一个归约循环。但即使我运行他们文档中给出的相同示例代码,它也会失败 static void iadd(int&R、Vector&A){ 无符号和=0; INTA; 对于(inti=0;i

我正在尝试用LLVM自动矢量化一个归约循环。但即使我运行他们文档中给出的相同示例代码,它也会失败 static void iadd(int&R、Vector&A){ 无符号和=0; INTA; 对于(inti=0;i,llvm,vectorization,reduction,Llvm,Vectorization,Reduction,,这个问题中没有足够的信息可以自信地回答它。但是我向您保证,LLVM和Clang将至少在树的顶部对简化循环进行矢量化(我没有检查旧版本的功能) 第一个问题是矢量化实际上取决于体系结构。在我的示例中,我将使用x86-64和Haswell微体系结构(支持AVX2),因为您没有列出特定的体系结构。如果您指定,我很乐意更新其他体系结构的答案 下一个问题是,您的描述听起来不像一个真正的缩减循环。首先,如果数组是静态的,那么我不知道这是关于什么的——这是一个全局的。但是假设您指的是长度为32的成员数组,那么

,这个问题中没有足够的信息可以自信地回答它。但是我向您保证,LLVM和Clang将至少在树的顶部对简化循环进行矢量化(我没有检查旧版本的功能)

第一个问题是矢量化实际上取决于体系结构。在我的示例中,我将使用x86-64和Haswell微体系结构(支持AVX2),因为您没有列出特定的体系结构。如果您指定,我很乐意更新其他体系结构的答案

下一个问题是,您的描述听起来不像一个真正的缩减循环。首先,如果数组是静态的,那么我不知道这是关于什么的——这是一个全局的。但是假设您指的是长度为32的成员数组,那么这应该相当于以下完整且可编译的(稍微简化的)代码:

static void iadd(int &R, Vector &A) {
     unsigned sum = 0;
     int a;

     for (int i=0; i<A.vector_elements_16; i++) {
          a = static_cast<int>(A.data_16[i]);
          sum += a ;

      }

     R=static_cast<int>(sum);

    }

编译器使用:Clang 3.8非常感谢您的详细响应。很抱歉,我没有提供我的矢量数据结构,但它与您生成的相同。我在多个体系结构上运行相同的代码,测试自动矢量化质量。正如您所说,我观察的是展开的循环,而不是矢量化,因为我有静态数组to表示我的向量。你能再给我一点启发吗?为什么静态数组是这样而指针不是这样?同时,你能告诉我LLVM是否支持Xeon phi-MIC指令的自动向量化吗?
struct V {
  static constexpr int length = 32;
  unsigned short data[32];
};

int reduce(V &v) {
  int sum = 0;
  for (int i = 0; i < v.length; ++i)
    sum += static_cast<int>(v.data[i]);
  return sum;
}
struct V {
  int length;
  unsigned short *data;
};

int reduce(V &v) {
  int sum = 0;
  for (int i = 0; i < v.length; ++i)
    sum += static_cast<int>(v.data[i]);
  return sum;
}
_Z6reduceR1V:                           # @_Z6reduceR1V
  .cfi_startproc
# BB#0:                                 # %entry
  movslq        (%rdi), %rcx
  xorl          %eax, %eax
  testq         %rcx, %rcx
  jle           .LBB0_11
# BB#1:                                 # %for.body.lr.ph
  movq          8(%rdi), %rdx
  xorl          %edi, %edi
  movl          $0, %eax
  cmpl          $31, %ecx
  jbe           .LBB0_10
# BB#2:                                 # %min.iters.checked
  xorl          %edi, %edi
  movq          %rcx, %r9
  movl          $0, %eax
  andq          $-32, %r9
  je            .LBB0_10
# BB#3:                                 # %vector.body.preheader
  leaq          -32(%r9), %rsi
  shrq          $5, %rsi
  leal          1(%rsi), %r8d
  andl          $1, %r8d
  xorl          %eax, %eax
  testq         %rsi, %rsi
  je            .LBB0_4
# BB#5:                                 # %vector.body.preheader.new
  leaq          -1(%r8), %rdi
  subq          %rsi, %rdi
  vpxor         %ymm0, %ymm0, %ymm0
  xorl          %eax, %eax
  vpxor         %ymm1, %ymm1, %ymm1
  vpxor         %ymm2, %ymm2, %ymm2
  vpxor         %ymm3, %ymm3, %ymm3
  .p2align      4, 0x90
.LBB0_6:                                # %vector.body
                                        # =>This Inner Loop Header: Depth=1
  vpmovzxwd     (%rdx,%rax,2), %ymm4    # ymm4 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpmovzxwd     16(%rdx,%rax,2), %ymm5  # ymm5 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpmovzxwd     32(%rdx,%rax,2), %ymm6  # ymm6 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpmovzxwd     48(%rdx,%rax,2), %ymm7  # ymm7 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpaddd        %ymm0, %ymm4, %ymm0
  vpaddd        %ymm1, %ymm5, %ymm1
  vpaddd        %ymm2, %ymm6, %ymm2
  vpaddd        %ymm3, %ymm7, %ymm3
  vpmovzxwd     64(%rdx,%rax,2), %ymm4  # ymm4 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpmovzxwd     80(%rdx,%rax,2), %ymm5  # ymm5 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpmovzxwd     96(%rdx,%rax,2), %ymm6  # ymm6 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpmovzxwd     112(%rdx,%rax,2), %ymm7 # ymm7 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  leaq          64(%rax), %rax
  vpaddd        %ymm0, %ymm4, %ymm0
  vpaddd        %ymm1, %ymm5, %ymm1
  vpaddd        %ymm2, %ymm6, %ymm2
  vpaddd        %ymm3, %ymm7, %ymm3
  addq          $2, %rdi
  jne           .LBB0_6
  jmp           .LBB0_7
.LBB0_4:
  vpxor         %ymm0, %ymm0, %ymm0
  vpxor         %ymm1, %ymm1, %ymm1
  vpxor         %ymm2, %ymm2, %ymm2
  vpxor         %ymm3, %ymm3, %ymm3
.LBB0_7:                                # %middle.block.unr-lcssa
  testq         %r8, %r8
  je            .LBB0_9
# BB#8:                                 # %middle.block.epilog-lcssa
  vpmovzxwd     48(%rdx,%rax,2), %ymm4  # ymm4 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpaddd        %ymm3, %ymm4, %ymm3
  vpmovzxwd     32(%rdx,%rax,2), %ymm4  # ymm4 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpaddd        %ymm2, %ymm4, %ymm2
  vpmovzxwd     16(%rdx,%rax,2), %ymm4  # ymm4 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpaddd        %ymm1, %ymm4, %ymm1
  vpmovzxwd     (%rdx,%rax,2), %ymm4    # ymm4 = mem[0],zero,mem[1],zero,mem[2],zero,mem[3],zero,mem[4],zero,mem[5],zero,mem[6],zero,mem[7],zero
  vpaddd        %ymm0, %ymm4, %ymm0
.LBB0_9:                                # %middle.block
  vpaddd        %ymm0, %ymm1, %ymm0
  vpaddd        %ymm0, %ymm2, %ymm0
  vpaddd        %ymm0, %ymm3, %ymm0
  vextracti128  $1, %ymm0, %xmm1
  vpaddd        %ymm1, %ymm0, %ymm0
  vpshufd       $78, %xmm0, %xmm1       # xmm1 = xmm0[2,3,0,1]
  vpaddd        %ymm1, %ymm0, %ymm0
  vphaddd       %ymm0, %ymm0, %ymm0
  vmovd         %xmm0, %eax
  movq          %r9, %rdi
  cmpq          %r9, %rcx
  je            .LBB0_11
  .p2align      4, 0x90
.LBB0_10:                               # %for.body
                                        # =>This Inner Loop Header: Depth=1
  movzwl        (%rdx,%rdi,2), %esi
  addl          %esi, %eax
  addq          $1, %rdi
  cmpq          %rcx, %rdi
  jl            .LBB0_10
.LBB0_11:                               # %for.cond.cleanup
  vzeroupper
  retq