【问题标题】:Using inline assembler in iOS aarch64 application在 iOS aarch64 应用程序中使用内联汇编程序
【发布时间】:2015-12-16 21:13:19
【问题描述】:

我尝试为 64 位 iOS 应用程序编译一些内联汇编程序。

这是一个例子:

   int roundff(float _value) {
       int res;
       float temp;
       asm("vcvtr.s32.f32 %[temp], %[value] \n vmov %[res], %[temp]" : [res] "=r" (res), [temp] "=w" (temp) : [value] "w" (_value));
       return res;
   }

我有这个错误:

无法识别的指令助记符。

但是这段代码编译得很好:

__asm__ volatile(
                 "add %[result], %[b], %[a];"
                 : [result] "=r" (result)
                 : [a] "r" (a), [b] "r" (b), [c] "r" (c)
                 );

我发现在 aarch64 中我必须使用 fcvt 而不是 vcvt。因为

int a = (int)(10.123);

编译成

fcvtzs w8, s8

但我不知道如何在内联汇编器中编写它。像这样的

int roundff(float _value)
{
    int res;
    asm("fcvtzs %[res], %[value]" : [res] "=r" (res) : [value] "w" (_value));
    return res;
}

也不起作用并生成此错误:

指令'fcvtz'不能设置标志,但指定了's'后缀。

指令操作数无效。

我还需要 round 而不是 trim。 (fcvtns)

有什么帮助吗?在哪里可以阅读有关 arm(32/64) asm 的更多信息?

更新 行。这:float res = nearintf(v) 编译成很好的指令 frinti s0 s0。但是为什么我的内联汇编器在使用 clang 编译器的 iOS 上不起作用?

【问题讨论】:

  • 为什么要这样做?你用汇编做什么?
  • 因为我需要最快的 round(float) 函数。 fcvtns 是浮点转换为有符号整数,四舍五入到最接近的偶数。
  • Google 从 arm.com 网站出现 this。如果您在内容窗格中打开“ARM 编译器 armasm 参考指南”条目,您将看到“一般指令”、“浮点指令”等条目。
  • 作为一个建议,当涉及到 iOS 之类的东西时,我会避免像瘟疫一样的内联汇编。从长远来看,这只是自找麻烦。
  • 您是否尝试过编写使用多个步骤来实现指令执行结果的 C 语言?然后检查编译器是否针对该指令对其进行了优化。

标签: ios objective-c xcode assembly


【解决方案1】:

这是你的做法:

-(int) roundff:(float)a {
    int y;
    __asm__("fcvtzs %w0, %s1\n\t" : "=r"(y) : "w"(a));
    return y;
}

保重,

/A

【讨论】:

  • 这是我的版本:{ int res; asm __volatile__("fcvtns %[res], %s[value]" :[res] "=r" (res) : [value] "w" (value));返回资源; }
【解决方案2】:

您可以使用内联到单个 ARM 指令的标准 math.h 函数获得所需的舍入。更好的是,编译器知道它们在做什么,因此可以通过例如更好地优化。证明整数不能为负,如果是这样的话。

检查godbolt 的编译器输出:

#include <math.h>

int truncate_f_to_int(float v)
{
  int res = v;  // standard C cast: truncate with fcvtzs on ARM64
  // AMD64: inlines to cvtTss2si rax, xmm0   // Note the extra T for truncate
  return res;
}

int round_f_away_from_zero(float v)
{
    int res = roundf(v);  // optimizes to fcvtas on ARM64
  // AMD64: AND/OR with two constants before converting with truncation
    return res;
}


//#define NOT_ON_GODBOLT
// godbolt has a broken setup and gets x86-64 inline asm for lrintf on ARM64

#if defined(NOT_ON_GODBOLT) || defined (__x86_64__) || defined(__i386__)
int round_f_to_even(float v)
{
  int res =  lrintf(v);  // should inline to a convert using the current rounding mode
  // AMD64: inlines to cvtss2si rax, xmm0
  // nearbyintf(v); // ARM64: calls the math library
  // rintf(v); // ARM64: calls the math library
  return res;
}
#endif

godbolt 为非 x86 架构安装了错误的头文件:它们仍然使用 x86 数学头文件,包括内联 asm。

此外,您的 roundff 函数带有用于 fcvtzs 的内联 asm,在带有 gcc 4.8 的 Godbolt 上编译得很好。也许您正在尝试为 32 位 ARM 构建?但就像我说的,使用库函数来做你想做的事,然后检查以确保它内联到漂亮的 ASM。

【讨论】:

  • truncate_f_to_int 编译成:fcvtzs w8, s0 round_f_away_from_zero 编译成: frintx s1, s0 frinta s0, s0 fcvtzs w8, s0 但是汇编只有一条指令:fcvtns。我正在使用 clang 编译“Apple LLVM 版本 7.0.0 (clang-700.1.76)”并仅为 arm64 开发应用程序。 (-Os)
  • 好的。这:float res = nearintf(v) 编译成很好的指令 frinti s0 s0。但是为什么我的内联汇编器在使用 clang 编译器的 iOS 上不起作用?
  • @Joker:IDK。最近还有一个关于 iOS 应用程序的内联汇编的问题,并猜测苹果禁止它,因为它们只编译为 LLVM 中间表示或其他东西。 Apple 可能希望能够在新 CPU 可用时为其生成二进制文件,而不是让供应商直接生成最终的二进制文件。
猜你喜欢
  • 2011-09-04
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 2012-02-20
相关资源
最近更新 更多