我有跨平台的音频处理应用程序。它是使用Qt和PortAudio库编写的。我还使用Chaotic-Daw源来处理某些音频处理功能(Vibarto效果和Soft-Knee Dynamic范围压缩)。问题是我无法将我的应用程序从Windows移植到Mac OSX,因为我收到__asm
部分的编译器错误(我使用Mac OSX Yosemite和Qt Creator 3.4.1 IDE):
/用户/管理员/我的 项目/为mySound /司/基础/ rosic_NumberManipulations.h:69:
的错误: 预期'('之后' 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);
}
如何解决此问题?
答案 0 :(得分:1)
代码清楚地为Microsoft的Visual C ++编译器编写,因为它是inline assembly使用的语法。它使用英特尔语法,相当简单,这使得编写起来很容易,但却阻碍了它的优化潜力。
Clang和GCC都使用不同的格式进行内联汇编。特别是,他们使用GNU AT&T syntax。写作更复杂,但更具表现力。编译器错误基本上是Clang告诉你的方式,&#34;我可以告诉你正在尝试编写内联汇编,但是你把它格式化错了!&#34;
因此,要编译此代码,您需要将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 $1, %[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指令)。这取决于你:代码将以任何一种方式运行,但如果不使用内联汇编来强制使用这种聪明的优化,它将会更慢。