【问题标题】:gcc -O3 optimize :: xmm0 register?gcc -O3 优化 :: xmm0 寄存器?
【发布时间】:2013-11-06 01:45:36
【问题描述】:

我正在编写一个 vsprintf 函数来使用我的 64 位操作系统内核(由 C 编写),并检查它在 Visual Studio 和 Cygwin gcc 中运行良好。 然后,我放入我的内核并运行......但内核不能正常工作

我调试并发现问题:vsprintf 包含下一个汇编代码

movdqa xmm0,XMMWORD PTR [rip+0x0]

真正的问题是我从不使用浮点数!

我猜那是 gcc 的优化,它似乎是正确的,因为它在没有优化的情况下运行良好。

是否有任何解决方案,可以说,gcc 选项禁用 xmm 寄存器的优化?

【问题讨论】:

  • xmm/ymm 寄存器不仅仅用于浮点。 movdqa 是一个整数指令。
  • 啊哈...但是 XMM 寄存器似乎无法使用,因为我还没有在内核中初始化它们...
  • 有趣的是,你的英语一点问题都没有! :-)

标签: c optimization gcc sse


【解决方案1】:

生成 XMM 寄存器移动指令,因为在 System V AMD64 ABI 中,浮点参数存储在 XMM0–XMM7 中。

由于仅通过查看可变参数函数我们不知道是否使用了浮点数,因此编译器还需要生成指令以将浮点值推送到va_list


您可以使用-mno-sse flag to disable SSE。例如,

__attribute__((noinline))
void f(const char* x, ...) {
    va_list va;
    va_start(va, x);
    vprintf(x, va);
    va_end(va);
}

没有-mno-sse 标志:

subq    $0x000000d8,%rsp
testb   %al,%al
movq    %rsi,0x28(%rsp)
movq    %rdx,0x30(%rsp)
movq    %rcx,0x38(%rsp)
movq    %r8,0x40(%rsp)
movq    %r9,0x48(%rsp)
je  0x100000f1b
movaps  %xmm0,0x50(%rsp)
movaps  %xmm1,0x60(%rsp)
movaps  %xmm2,0x70(%rsp)
movaps  %xmm3,0x00000080(%rsp)
movaps  %xmm4,0x00000090(%rsp)
movaps  %xmm5,0x000000a0(%rsp)
movaps  %xmm6,0x000000b0(%rsp)
movaps  %xmm7,0x000000c0(%rsp)
0x100000f1b:
leaq    0x000000e0(%rsp),%rax
movl    $0x00000008,0x08(%rsp)
movq    %rax,0x10(%rsp)
leaq    0x08(%rsp),%rsi
leaq    0x20(%rsp),%rax
movl    $0x00000030,0x0c(%rsp)
movq    %rax,0x18(%rsp)
callq   0x100000f6a ; symbol stub for: _vprintf
addq    $0x000000d8,%rsp
ret

带有-mno-sse 标志:

subq    $0x58,%rsp
leaq    0x60(%rsp),%rax
movq    %rsi,0x28(%rsp)
movq    %rax,0x10(%rsp)
leaq    0x08(%rsp),%rsi
leaq    0x20(%rsp),%rax
movq    %rdx,0x30(%rsp)
movq    %rcx,0x38(%rsp)
movq    %r8,0x40(%rsp)
movq    %r9,0x48(%rsp)
movl    $0x00000008,0x08(%rsp)
movq    %rax,0x18(%rsp)
callq   0x100000f6a ; symbol stub for: _vprintf
addq    $0x58,%rsp
ret

您也可以使用 target attribute 为该功能禁用 SSE,例如

__attribute__((noinline, target("no-sse")))
//                       ^^^^^^^^^^^^^^^^
void f(const char* x, ...) {
    va_list va;
    va_start(va, x);
    vprintf(x, va);
    va_end(va);
}

但请注意,其他支持 SSE 的函数不会知道 f 不使用 SSE,因此使用浮点数调用它们会导致未定义的行为

int main() {
    f("%g %g", 1.0, 2.0);  // 1.0 and 2.0 are stored in XMM0–1
                           // So this will print garbage e.g. `0 6.95326e-310`
}

【讨论】:

  • 使用该选项我不能在 SSE 中使用浮点,可以吗?我只想禁用那个优化..但如果没有其他方法,我应该听从你的建议..谢谢
  • 啊..我的交叉编译器不支持那个属性..你知道如何启用吗?我可以编译 gcc。
  • 哦,不是不支持,但是其他功能也有同样的问题!谢谢
【解决方案2】:

使用 -O2 而不是 -O3 它会起作用。

【讨论】:

  • 原提问者很清楚问题来自优化。已经有一个很好的解释的答案。您的回答几乎没有增加价值。不管怎样,欢迎来到 StackOverflow。祝您住宿愉快!
猜你喜欢
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 2013-11-07
  • 2015-05-06
  • 2013-10-13
  • 2017-01-25
  • 1970-01-01
  • 2021-08-10
相关资源
最近更新 更多