Arm64 中缺少 SSAT 和 USAT 指令的替代方案?

Posted

技术标签:

【中文标题】Arm64 中缺少 SSAT 和 USAT 指令的替代方案?【英文标题】:Alternatives to missing SSAT and USAT instructions in Arm64? 【发布时间】:2019-04-16 04:26:06 【问题描述】:

我们正在将主要应用程序从 Arm32 移植到 Arm64。我们的算法经常使用SSATUSAT 指令。它们非常有用,可以执行任意大小的左移或右移,然后执行有符号或无符号的饱和到任意位数。这对于图像处理算法非常有用,因为我们可以执行一些生成 32 位整数结果的数学运算,然后从中获取我们需要的任何位(饱和到输出图像的位深度的最大/最小值)一条指令。

这些指令在 Arm64 中莫名其妙地消失了,我们发现的最接近的替代方案是 SQSHRN / UQSHRN / SQSHLN / UQSHLN 执行移位和饱和,但它们执行的饱和度要有限得多(USAT 可以饱和到任何宽度,甚至 7 位;新指令只能饱和到输入宽度的一半,例如,在 32 位输入的情况下为 16 位,这需要额外的处理才能达到所需的结果) .

有人可以解释为什么这些指令被删除,以及有效移植使用它们的现有代码的最佳方法是什么?

【问题讨论】:

用 C 语言编写它们的等价物并让编译器翻译该代码? @IraBaxter 在 C 中编写饱和度代码需要一个分支(“如果值超过 255,则将其设置为 255”),这是我宁愿避免深入算法内核的东西。 查看我对 255 的限制:codereview.stackexchange.com/a/6504/8792 @itaych - 为什么你(r 编译器)不能使用条件指令而不是分支? @TobySpeight 因为 arm64 没有很多这些。您有什么特别的解决方案吗? 【参考方案1】:

--UPDATE-- 使用非汇编代码时,正确测试的时间明显变慢,我会继续寻找不同的方法

我比较了这个汇编代码:

#define __arm_ssat(src, bits)   asm("ssat %[srcr], %[satv], %[srcr]"    :[srcr]"+r"(src):[satv]"I"(bits));

用这个:

#define MAX_SIGNED_NUM(bits) ((1 << (bits -1)) -1)
#define __arm_ssat(src, bits)   src = ((src > MAX_SIGNED_NUM(bits)) ? MAX_SIGNED_NUM(bits) : src);

在 32 位设备上运行此 --UPDATED TEST-- 时:

volatile  void assert_ssat_asm(int* buf, size_t loops)
    int64_t num = buf[0];
    int64_t num_a = buf[1];
    int64_t num_b = buf[2];
    int sum = 0;
    struct timeval tmv1; gettimeofday(&tmv1,NULL);
    for (int i = 0; i < loops; ++i)
        __arm_ssat(num, 8);
        sum+=num;
        assert( 127 == num);
        num = buf[0];

        __arm_ssat(num, 16);
        sum+=num;
        assert(32767 == num);

        __arm_ssat(num_a, 8);
        sum+=num;
        assert( 127 == num_a);
        num_a = buf[1];

        __arm_ssat(num_a, 16);
        sum+=num;
        assert( 690 == num_a);

        __arm_ssat(num_b, 8);
        sum+=num;
        assert( 127 == num_b);
        num_b = buf[2];

        __arm_ssat(num_b, 16);
        sum+=num;
        assert( 32767 == num_b);
    
    struct timeval tmv2; gettimeofday(&tmv2,NULL);
    int tdiff_usec = (tmv2.tv_sec*1000000 + tmv2.tv_usec) - (tmv1.tv_sec*1000000 + tmv1.tv_usec);

    printf("%d\n", sum);
    printf("ran %d times, total time: %d,  average time asm: %.7f\n", loops, tdiff_usec, (double)tdiff_usec/loops);

int main ()

    int buf[] =  69000, 690, 64000 ;
    test_ssat(buf, 1000000);

我得到了这些结果:

运行 1000000 次循环,平均时间 reg: 0.0210270

运行 1000000 次循环,平均组装时间:0.0057960

【讨论】:

您的 0.0 平均时间可能只是表明使用纯 C 优化了所有内容(应该如此),因为您没有使用结果。 @PeterCordes 考虑了一下,所以我添加了: volatile int64_t rr;和 rr = 数量;在每个 __arm_ssat 之后。结果还是一样。

以上是关于Arm64 中缺少 SSAT 和 USAT 指令的替代方案?的主要内容,如果未能解决你的问题,请参考以下文章

Xcode:MagTek iOS 库中缺少 arm64 符号

二进制文件无效,二进制文件缺少架构[arm64]

缺少所需的架构 arm64

AArch64 - 并行运行 ARM 和 ASIMD 指令

iOS 指令集arm64、armv7s、armv7、i386、x86_64

缺少 ARM64 上的 vtbl2 内在函数