为什么gcc不能矢量化这个直线代码?

时间:2014-07-10 16:38:32

标签: c gcc vectorization

我有以下代码,它似乎是SLP的完美候选者:

struct vector {
  double x, y, z;
} __attribute__((aligned(16)));

int
slp_test(struct vector *x0, struct vector *n)
{
  double t = -x0->z/n->z;
  double u = x0->x + t*n->x;
  double v = x0->y + t*n->y;
  return t >= 0.0 && u >= 0.0 && v >= 0.0 && u + v <= 1.0;
}

uv的计算似乎很容易实现矢量化,而x0n应该足够好地对齐它。但是在-O3的x86-64上,gcc 4.9.0生成了这段代码:

    movsd   .LC0(%rip), %xmm1
    movsd   16(%rdi), %xmm0
    movsd   (%rdi), %xmm2
    xorpd   %xmm1, %xmm0
    movsd   (%rsi), %xmm1
    pxor    %xmm3, %xmm3
    divsd   16(%rsi), %xmm0 ; t = x0->z/n->z
    mulsd   %xmm0, %xmm1    ; t*n->x
    addsd   %xmm1, %xmm2    ; u = x0->x + t*n->x
    movsd   8(%rsi), %xmm1
    mulsd   %xmm0, %xmm1    ; t*n->y
    ucomisd %xmm3, %xmm2
    addsd   8(%rdi), %xmm1  ; v = x0->y + t*n->y
    setae   %dl
    ucomisd %xmm3, %xmm1
    setae   %al
    testb   %al, %dl
    je      .L3
    ucomisd %xmm3, %xmm0
    jb      .L3
    addsd   %xmm2, %xmm1
    movsd   .LC2(%rip), %xmm0
    xorl    %eax, %eax
    ucomisd %xmm1, %xmm0
    setae   %al
    ret
.L3:
    xorl    %eax, %eax
    ret

为什么gcc不使用mulpd addpd代替两个mulsdaddsd?我使用-fopt-info-all-vec试图了解原因,并抱怨对齐(full output):

slp-test.c:8:17: note: === vect_analyze_data_refs_alignment ===
slp-test.c:8:17: note: vect_compute_data_ref_alignment:
slp-test.c:8:17: note: misalign = 0 bytes of ref x0_3(D)->z
slp-test.c:8:17: note: vect_compute_data_ref_alignment:
slp-test.c:8:17: note: misalign = 0 bytes of ref n_6(D)->z
slp-test.c:8:17: note: vect_compute_data_ref_alignment:
slp-test.c:8:17: note: misalign = 0 bytes of ref x0_3(D)->x
slp-test.c:8:17: note: vect_compute_data_ref_alignment:
slp-test.c:8:17: note: misalign = 0 bytes of ref n_6(D)->x
slp-test.c:8:17: note: vect_compute_data_ref_alignment:
slp-test.c:8:17: note: misalign = 8 bytes of ref x0_3(D)->y
slp-test.c:8:17: note: vect_compute_data_ref_alignment:
slp-test.c:8:17: note: misalign = 8 bytes of ref n_6(D)->y
slp-test.c:8:17: note: === vect_analyze_slp ===
slp-test.c:8:17: note: Failed to SLP the basic block.
slp-test.c:8:17: note: not vectorized: failed to find SLP opportunities in basic block.

除非我误解了__attribute__((aligned(16))),否则它应该能够强制对齐这些访问。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

此代码不会从矢量化中获益太多,请记住cpus能够在一个周期内执行多个指令。 例如,Nehalem乘法/加法的延迟为4,倒数吞吐量为1,因此在理想情况下,它应该能够在四个周期内计算这些指令中的4个。这里至少应该有2个。 这已经意味着即使向量寄存器已经完美归档,您也无法通过使用压缩指令获得任何收益。

编辑:我没有意识到数据可以一次加载,因此设置成本可以忽略不计

为了填充它们,你可能已经需要一个高和低的mov指令,这将比你以后获得的少量打包指令花费更多。 (在Nehalem上,mov [hl] pd的延迟为~5,而movsd的延迟为2)

比较无法有利地进行矢量化,因为您需要将打包的比较解包回正常的寄存器,这是一个非常昂贵的操作。 编译器也不知道分支的概率,它必须假设第一次比较总是会使其余部分短路,所以并行做任何事情都是有害的。

编辑:使用sse4 ptest虽然可能有利可图

这里的瓶颈也可能是不可归类的部门。 您可能更好地尝试一次矢量化2个结构的操作,而不是尝试在一个结构中矢量化操作。