内联装配; 浮点按位运算; 这里出了什么问题?

Exi*_*ius 2 c++ assembly gcc inline-assembly

这段简单的代码是我的问题:

扩展的asm(gcc); 英特尔语法(-masm = intel); 平台 - x86

它应该做什么:返回一个长度为1的浮点数和符号(+ - )与x的相同.

    float signf(float x)
    {
      float r = 1;
      asm volatile (
            "and %1,0x80000000;"
            "or %0,%1;"
            :"=r"(r):"r"(x));
      return r;
    }
Run Code Online (Sandbox Code Playgroud)

用公平骰子卷选择的任意随机数调用它给出:

    signf of -1352353.3253: -5.60519e-045
Run Code Online (Sandbox Code Playgroud)

Jes*_*ter 5

内联asm的实际问题是您r只声明为输出,因此编译器将优化掉初始化.您应该使用"+r"约束而不是"=r"它应该工作.

更好的优化版本可能如下所示:

float signf(float x)
{
    float r;
    __asm__  __volatile__ (
            "and %0, 0x80000000;"
            "or %0, 0x3f800000;"
            :"=r"(r):"0"(x));
    return r;
}
Run Code Online (Sandbox Code Playgroud)

请注意,此函数涉及float-> int-> float转换(通过内存),这可能会影响性能.

上述代码的C版本是:

float signf(float x)
{
    union { float f; int i; } tmp, res;
    tmp.f = x;
    res.f = 1;
    res.i |= tmp.i & 0x80000000;
    return res.f;
}
Run Code Online (Sandbox Code Playgroud)

这为我生成了相同的代码(使用gcc 4.4.5).

简单的C方法return x < 0 ? -1 : 1;生成完整的FPU代码,无需转换或内存访问(加载操作数除外),因此可能表现更好.fcmov如果可用,它还使用以避免分支.需要一些基准测试.