【问题标题】:Inline assembly causes Segmentation fault (core dumped)内联汇编导致分段错误(核心转储)
【发布时间】:2019-08-06 08:46:54
【问题描述】:

我正在尝试将 Intel 内在函数转换为内联汇编。

代码将计算一个 4x4 矩阵。 AB的大小分别为4 x kckc x 4

这是完整的功能:

 #define MR 4
 #define NR 4
 // compute C := beta * C + alpha * AB
 static void  dgemm_micro_kernel(int kc,
               double alpha, const double *A, const double *B,
               double beta,
               double *C, int incRowC, int incColC)
{ 
    double AB[MR*NR] __attribute__ ((aligned (32)));

    int i, j, p;
    register __m256d ab_00_10_20_30, ab_01_11_21_31, ab_02_12_22_32, ab_03_13_23_33;
    register __m256d a_0123, b_0000, b_1111, b_2222, b_3333;


    ab_00_10_20_30 = _mm256_setzero_pd();
    ab_01_11_21_31 = _mm256_setzero_pd();
    ab_02_12_22_32 = _mm256_setzero_pd();
    ab_03_13_23_33 = _mm256_setzero_pd();

    for (p = 0; p < kc; p++)
    {
        a_0123 = _mm256_load_pd(A);
        b_0000 = _mm256_broadcast_sd(B);
        b_1111 = _mm256_broadcast_sd(B + 1);
        b_2222 = _mm256_broadcast_sd(B + 2);
        b_3333 = _mm256_broadcast_sd(B + 3);

        // Col 1
        ab_00_10_20_30 = _mm256_fmadd_pd(a_0123, b_0000, ab_00_10_20_30);
        // Col 2
        ab_01_11_21_31 = _mm256_fmadd_pd(a_0123, b_1111, ab_01_11_21_31);
        // Col 3
        ab_02_12_22_32 = _mm256_fmadd_pd(a_0123, b_2222, ab_02_12_22_32);
        // Col 4
        ab_03_13_23_33 = _mm256_fmadd_pd(a_0123, b_3333, ab_03_13_23_33);

        A += MR;
        B += NR;
  }
    _mm256_store_pd(AB +  0, ab_00_10_20_30);
    _mm256_store_pd(AB +  4, ab_01_11_21_31);
    _mm256_store_pd(AB +  8, ab_02_12_22_32);
    _mm256_store_pd(AB + 12, ab_03_13_23_33);

    // Updata C := beta * C
    if (beta == 0.0)
   {
        // C == 0
        for (j = 0; j < NR; j++)
        {
            for (i = 0; i < MR; i++)
           {
                C[i * incRowC + j * incColC] = 0.0;
          }
      }
    }
    else if (beta != 1.0)
    {
        // C := beta * C
        for (j = 0; j < NR; j++)
        {
            for (i = 0; i < MR; i++)
            {
                C[i * incRowC + j * incColC] *= beta;
            }
        }
    }

    // Updata C := C + alpha * AB
    if (alpha == 1.0)
    {
        for (j = 0; j < NR; j++)
        {
            for (i = 0; i < MR; i++)
            {
                C[i * incRowC + j * incColC] += AB[j * MR + i];
            }
        }
    }
    else
    {
        for (j = 0; j < NR; j++)
        {
            for (i = 0; i < MR; i++)
            {
                C[i * incRowC + j * incColC] += alpha * AB[j * MR + i];
            }
        }
    }
}

这是我的内联汇编(只需发布相关部分):

double AB[16] __attribute__ ((aligned(32)));
__asm__ volatile
(
    "movl           %0,         %%esi               \n\t"   // kc
    "movq           %1,         %%rax               \n\t"   // A
    "movq           %2,         %%rbx               \n\t"   // B
    "movq           %3,         %%rcx               \n\t"   // AB
    "                                               \n\t"
    "vxorpd         %%ymm0,     %%ymm0,     %%ymm0  \n\t"   // SET ZERO
    "vxorpd         %%ymm1,     %%ymm1,     %%ymm1  \n\t"
    "vxorpd         %%ymm2,     %%ymm2,     %%ymm2  \n\t"
    "vxorpd         %%ymm3,     %%ymm3,     %%ymm3  \n\t"
    "                                               \n\t"
    "testl           %%esi,      %%esi               \n\t"   // CHECK
    "je             .DWRITEAB                       \n\t"
    "                                               \n\t"
    ".DLOOP:                                        \n\t"   // LOOP
    "vmovapd        (%%rax),    %%ymm4              \n\t"   // load a_0123
    "vbroadcastsd   (%%rbx),    %%ymm5              \n\t"   // load b_0000
    "vbroadcastsd   8(%%rbx),   %%ymm6              \n\t"   // load b_1111
    "vbroadcastsd   16(%%rbx),  %%ymm7              \n\t"   // load b_2222
    "vbroadcastsd   24(%%rbx),  %%ymm8              \n\t"   // load b_3333
    "                                               \n\t"
    "vfmadd132pd    %%ymm4,     %%ymm5,     %%ymm0  \n\t"   // Col 1
    "vfmadd132pd    %%ymm4,     %%ymm6,     %%ymm1  \n\t"   // Col 2
    "vfmadd132pd    %%ymm4,     %%ymm7,     %%ymm2  \n\t"   // Col 3
    "vfmadd132pd    %%ymm4,     %%ymm8,     %%ymm3  \n\t"   // Col 4
    "                                               \n\t"
    "addq           $32,        %%rax               \n\t"
    "addq           $32,        %%rbx               \n\t"
    "                                               \n\t"
    "decl           %%esi                           \n\t"
    "jne            .DLOOP                          \n\t"
    "                                               \n\t"
    ".DWRITEAB:                                     \n\t"
    "vmovapd        %%ymm0,     (%%rcx)             \n\t"
    "vmovapd        %%ymm1,     32(%%rcx)           \n\t"
    "vmovapd        %%ymm2,     64(%%rcx)           \n\t"
    "vmovapd        %%ymm3,     96(%%rcx)           \n\t"
    "                                               \n\t"
    : // output
    : // input
        "m" (kc), // 0
        "m" (A),  // 1
        "m" (B),  // 2
        "m" (AB) // 3
    : // clober list
        "rax", "rbx", "rcx", "esi",
        "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
        "xmm5", "xmm6", "xmm7", "xmm8", "memory"
);

然后我编译运行它,输出显示Segmentation fault (core dumped)。但是,内在版本运行良好。我的内联汇编代码有什么问题?

【问题讨论】:

  • 你能把这两个函数都完整地发布吗?第一个函数是否真的写回C
  • @chtz 我已经发布了完整的功能。我只修改了整个函数的内在函数部分。
  • 您的 sn-p 仍然不完整,例如,它错过了 MRNR 的定义。阅读如何(以及为什么)提供minimal reproducible example
  • @chtz 抱歉,我忘记了。已编辑。
  • 我不清楚你为什么不在调试器下运行它来准确找出崩溃的来源。如果那是不可能的,我会首先在 DWRITEAB 中删除 vmovapd。是的,你会得到错误的答案,但如果它没有崩溃,你就会知道去哪里找。另外,我看到您正在破坏 xmm*,但使用的是 ymm*。鉴于两者之间的关系,这可能会起作用,但我可能会尝试更改(或只是添加)ymm* 寄存器。

标签: x86 simd inline-assembly intrinsics avx


【解决方案1】:

AB 是一个数组,但您将它用作指针。 此外,它是一个输出,但它被列为输入。

解决此问题的最简单更改是使用lea 而不是movAB 的地址加载到rcx。还要将"=m"(AB) 作为输出。

更好的解决方案是让编译器进行寄存器分配并删除 eax、ebx、ecx 和 esi 的破坏者。通过使用"r" 约束,编译器将数组转换为指向其第一个元素的指针并将指针放入寄存器中。您可以通过两次列出数组操作数来避免内存破坏。

警告,这不太正确,因为它没有正确地表明汇编代码改变了它的输入寄存器。由于您没有展示整个功能,我无法判断这是否会导致问题(但肯定是错误的)。

asm ("..."
    : // output
      "=m"(AB)
    : // input
      "r"(kc), "r"(A), "r"(B), "r"(AB),
      "m"(*(double (*)[4*kc])A), "m"(*(double (*)[4*kc])B)
    : // clobber list
      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
      "xmm5", "xmm6", "xmm7", "xmm8"
);

这需要将汇编代码中对参数的所有引用更改为使用%1%2%3%4

【讨论】:

  • 我添加了一些关于函数的信息。 AB 是一个局部变量。
  • 啊,所以A和B是指针,只有AB是数组。我将编辑我的答案。
  • 我修改了代码,结果还是Segmentation fault (core dumped)
  • 如果您将更新后的代码添加到问题中(或提出新问题),我将很乐意查看。
猜你喜欢
  • 1970-01-01
  • 2020-05-30
  • 1970-01-01
  • 2022-08-23
  • 2023-03-12
  • 1970-01-01
  • 2022-01-02
  • 2010-10-29
  • 1970-01-01
相关资源
最近更新 更多