【问题标题】:LLVM generated vector math assembly segfaultingLLVM 生成向量数学程序集段错误
【发布时间】:2014-07-20 19:57:04
【问题描述】:

以下 LLVM 函数采用三个指向五个双精度数组的指针并计算 C = A*B + C:

define void @my_vector_math(double* %A1, double* %B2, double* %C3) {
entry:
  %0 = bitcast double* %C3 to <5 x double>*
  %1 = load <5 x double>* %0, align 64
  %2 = bitcast double* %B2 to <5 x double>*
  %3 = load <5 x double>* %2, align 64
  %4 = bitcast double* %A1 to <5 x double>*
  %5 = load <5 x double>* %4, align 64
  %6 = fmul <5 x double> %3, %5
  %7 = fadd <5 x double> %1, %6
  store <5 x double> %7, <5 x double>* %0, align 64
  ret void
}

它在我的机器上编译成以下程序集(64 位 Ubuntu 13.10,LLVM 3.4):

  30:   c5 fb 10 42 20          vmovsd 0x20(%rdx),%xmm0
  35:   c5 fb 10 4e 20          vmovsd 0x20(%rsi),%xmm1
  3a:   c5 fd 28 16             vmovapd (%rsi),%ymm2
  3e:   c5 fb 10 5f 20          vmovsd 0x20(%rdi),%xmm3
  43:   c5 f5 59 cb             vmulpd %ymm3,%ymm1,%ymm1
  47:   c5 ed 59 17             vmulpd (%rdi),%ymm2,%ymm2
  4b:   c5 fd 58 c1             vaddpd %ymm1,%ymm0,%ymm0
  4f:   c5 ed 58 0a             vaddpd (%rdx),%ymm2,%ymm1
  53:   c5 fd 29 0a             vmovapd %ymm1,(%rdx)
  57:   c5 f9 13 42 20          vmovlpd %xmm0,0x20(%rdx)
  5c:   c5 f8 77                vzeroupper
  5f:   c3                      retq

使用大小为 5 的数组调用时,它总是会出现段错误,但有时会在使用过大的数组时产生正确的结果:

int main() {
  double A[] = {1,1,1,1,1};
  double B[] = {2,2,2,2,2};
  double C[] = {3,3,3,3,3};
  my_vector_math(A, B, C); // Segfaults
  for (int i = 0; i < 5; i++) {
    printf("%f\n",C[i]);
  }
  return 0;
}

我很难弄清楚为什么会发生这种情况,任何指针都将不胜感激。


编辑:

没有经过任何优化的 LLVM IR:

define void @my_vector_math(double* %A1, double* %B2, double* %C3) {
entry:
  %a = alloca <5 x double>
  %b = alloca <5 x double>
  %c = alloca <5 x double>
  %C = alloca double*
  %B = alloca double*
  %A = alloca double*
  store double* %A1, double** %A
  store double* %B2, double** %B
  store double* %C3, double** %C
  %C4 = load double** %C
  %0 = bitcast double* %C4 to <5 x double>*
  %1 = load <5 x double>* %0
  store <5 x double> %1, <5 x double>* %c
  %B5 = load double** %B
  %2 = bitcast double* %B5 to <5 x double>*
  %3 = load <5 x double>* %2
  store <5 x double> %3, <5 x double>* %b
  %A6 = load double** %A
  %4 = bitcast double* %A6 to <5 x double>*
  %5 = load <5 x double>* %4
  store <5 x double> %5, <5 x double>* %a
  %c7 = load <5 x double>* %c
  %a8 = load <5 x double>* %a
  %b9 = load <5 x double>* %b
  %6 = fmul <5 x double> %a8, %b9
  %7 = fadd <5 x double> %c7, %6
  %C10 = load double** %C
  %8 = bitcast double* %C10 to <5 x double>*
  store <5 x double> %7, <5 x double>* %8
  ret void
}

【问题讨论】:

    标签: segmentation-fault llvm x86-64 vectorization


    【解决方案1】:

    您的 IR 声称双精度数组具有 64 字节对齐,这会导致编译器生成对齐的负载。您可能打算改为指定 8 字节对齐方式(许多平台上双精度的自然对齐方式)。

    【讨论】:

    • 将加载和存储的对齐更改为 8 个字节就可以了。我没有手动指定对齐方式; “指令组合”优化通道就是这样做的。 PNaCL 人似乎已经添加了他们自己的通行证来解决这个问题:chromium.googlesource.com/native_client/pnacl-llvm/+/master/lib/… 想知道这是不是应该在上游报告的错误?这也可能是同一个问题:stackoverflow.com/questions/5065800/…
    • 我怀疑您正在指定对齐方式,但没有意识到您正在这样做;这些向量是如何声明的,如何从 double 数组转换为它们?
    • 我已将通过 C API 生成的预优化传递 IR 添加到原始帖子中。我认为我根本没有指定任何对齐方式。
    • IIRC &lt;5 x double&gt; 的自然对齐是 64(= 5*8 向上取整到 2 的幂)或平台支持的最大对齐,以较小者为准。所以load &lt;5 x double&gt;* 假定为 64B 对齐,除非您添加明确的 align
    猜你喜欢
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    相关资源
    最近更新 更多