移植到 Mac OS X 错误

Porting to Mac OS X error

我有跨平台音频处理应用程序。它是使用 Qt 和 PortAudio libraries. I also use Chaotic-Daw 源代码编写的,用于某些音频处理功能(Vibarto 效果和 Soft-Knee 动态范围压缩)。问题是我无法将我的应用程序从 Windows 移植到 Mac OSX 因为我得到 __asm 部分的编译器错误(我使用 Mac OSX Yosemite 和 Qt Creator 3.4.1 IDE):

/Users/admin/My projects/MySound/daw/basics/rosic_NumberManipulations.h:69:
error: expected '(' after 'asm' { ^

对于这样的行:

INLINE int floorInt(double x)
{
    const float round_towards_m_i = -0.5f;
    int i;

    #ifndef LINUX
    __asm
    { // <========= error indicates that row
      fld x;
      fadd st, st (0);
      fadd round_towards_m_i;
      fistp i;
      sar i, 1;
    }
    #else
    i = (int) floor(x);
    #endif

    return (i);
}

我该如何解决这个问题?

代码显然是为 Microsoft 的 Visual C++ 编译器编写的,因为这是它用于 inline assembly 的语法。它使用Intel语法并且相当简单,这使得它易于编写但阻碍了它的优化潜力。

Clang 和 GCC 都使用不同的内联汇编格式。特别是,他们使用 GNU AT&T syntax。写起来更复杂,但表现力更强。编译器错误基本上是 Clang 告诉你的方式,"I can tell you're trying to write inline assembly, but you've formatted it all wrong!"

因此,要使这段代码通过编译,您需要将MSVC 风格的内联汇编转换为GAS 格式的内联汇编。它可能看起来像这样:

int floorInt(double x)
{
    const float round_towards_m_i = -0.5f;
    int i;

    __asm__("fadd   %[x], %[x]  \n\t"
            "fadds  %[adj]      \n\t"
            "fistpl %[i]        \n\t"
            "sarl   , %[i]"
           : [i]   "=m" (i)    // store result in memory (as required by FISTP)
           : [x]   "t"  (x),   // load input onto top of x87 stack (equivalent to FLD)
             [adj] "m"  (round_towards_m_i)
           : "st");

    return (i);
}

但是,由于 GAS 样式的额外表现力,我们可以将更多工作卸载到内置优化器,这可能会产生更优化的目标代码:

int floorInt(double x)
{
    const float round_towards_m_i = -0.5f;
    int i;

    x += x;                  // equivalent to the first FADD
    x += round_towards_m_i;  // equivalent to the second FADD
    __asm__("fistpl %[i]"
           : [i]   "=m" (i)
           : [x]   "t"  (x)
           : "st");
    return (i >> 1);         // equivalent to the final SAR
}

Live demonstration
(请注意,从技术上讲,像最后一行所做的带符号右移是在 C 中实现定义的,通常是不可取的。但是,如果您使用的是内联汇编,则您已经将决定针对特定平台,因此可以依赖特定于实现的行为。在这种情况下,我知道并且可以很容易地证明所有 C 编译器将生成 SAR 指令来对有符号整数进行算术右移值。)

也就是说,当您针对 LINUX 以外的平台进行编译时,似乎 使用内联汇编代码的作者(据推测,那将是 Windows,他们希望您在其上使用 Microsoft 的编译器)。因此,您可以通过确保在命令行或 makefile 中定义 LINUX 来简单地编译代码。

我不确定为什么做出这个决定; Clang 和 GCC 都将生成与 MSVC 相同的低效代码(假设您的目标是较老一代的 x86 处理器并且无法使用 SSE2 指令)。这取决于您:代码会 运行 两种方式,但如果不使用内联汇编来强制使用这种巧妙的优化,它会变慢。