簡體   English   中英

Aarch64匯編LD2問題

[英]Aarch64 assembly LD2 issue

下面的展開式popcount的實現產生了錯誤的結果,我設法觀察到,僅元素b[0]b[2]被計數,而b[1]b[3]不被計數。

#include <stdio.h>

int count_multiple_bits(unsigned long long *b, int size) {
  unsigned long long *d = b;
  int c;
  __asm__("LD2 {v0.D, v1.D}[0], [%1], #16  \n\t"
          "LD2 {v0.D, v1.D}[1], [%1]       \n\t"
          "CNT v0.16b, v0.16b              \n\t"
          "CNT v1.16b, v1.16b              \n\t"
          "UADDLV h2, v0.16b               \n\t"
          "UADDLV h2, v1.16b               \n\t"
          "UMOV %0, v2.d[0]                \n\t"
          : "+r"(c)
          : "r"(d) : "v0", "v1", "v2");
  return c;
}

int main(int argc, const char *argv[]) {
  unsigned long long bits[] = { -1ull, -1ull, -1ull, -1ull };
  printf("Test: %i\n", count_multiple_bits(bits, 4));
  return 0;
}

一次包含2個元素的這一方法效果很好:

int count_multiple_bits(unsigned long long *b, int size) {
  unsigned long long *d = b;
  int c;
  __asm__("LD1 {v0.D}[0], [%1], #8   \n\t"
          "LD1 {v0.D}[1], [%1]       \n\t"
          "CNT v0.16b, v0.16b        \n\t"
          "UADDLV h1, v0.16b         \n\t"
          "UMOV %0, v1.d[0]          \n\t"
          : "+r"(c)
          : "r"(d) : "v0", "v1");
  return c;
}

在所有其他條件都相同的情況下,我猜這是錯誤的負載,這是我假定的布局:

  v0.D[0] = b[0]
  v1.D[0] = b[1]
  v0.D[1] = b[2]
  v1.D[1] = b[3]

我的錯。

問題出在UADDLV ,該寄存器清除了目標寄存器,這是最終版本,它累加了任意長度的輸入:

int count_multiple_bits(unsigned long long *b, unsigned int size) {
  unsigned long long *d = b;
  unsigned int masked = 0, i = 0;
  int c = 0;

  masked = size & ~3;
  for (; i < masked; i += 4)
    __asm__("LD1 {v0.2D, v1.2D}[0], [%1], #32 \n\t"
            "CNT v0.16b, v0.16b               \n\t"
            "CNT v1.16b, v1.16b               \n\t"
            "UADDLV h2, v0.16b                \n\t"
            "UADDLV h3, v1.16b                \n\t"
            "ADD d2, d3, d2                   \n\t"
            "UMOV x0, v2.d[0]                 \n\t"
            "ADD %0, x0, %0                   \n\t"
            : "+r"(c), "+r"(d)
            :: "x0", "v0", "v1", "v2", "v3");

  masked = size & 3;
  for (i = 0; i < masked; ++i)
    __asm__("LD1  {v0.D}[0], [%1], #8 \n\t"
            "CNT  v0.8b, v0.8b        \n\t"
            "UADDLV h1, v0.8b         \n\t"
            "UMOV x0, v1.d[0]         \n\t"
            "ADD %0, x0, %0           \n\t"
            : "+r"(c), "+r"(d)
            : : "x0", "v0", "v1");

  return c;
}

奇跡般有效 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM