LLVM 优化器不尊重使用 Rust 内联 asm 设置非默认舍入模式?

Setting a non-default rounding mode with Rust inline asm isn't respected by the LLVM optimizer?

我正在开发一个 Rust crate,它可以改变舍入模式(+inf、-inf、最近或截断)。

改变舍入方式的函数是用内联汇编写的:

fn upward() {
    let cw: u32 = 0;
    unsafe {
    asm!("stmxcsr [=10=];
          mov [=10=], %eax;
          or $[=10=]x4000, %eax;
          mov %eax, [=10=];
          ldmxcsr [=10=];"
          : "=*m"(&cw)
          : "*m"(&cw)
          : "{eax}"
        );
    }
}

当我在调试模式下编译代码时,它按预期工作,当向正无穷大舍入时,我得到三分之一的 0.3333333333337,但是当我在发布模式下编译时,无论我设置什么舍入模式,我都会得到相同的结果.我猜这种行为是由于 LLVM 后端所做的优化所致。

如果我知道哪些 LLVM passes 负责此优化,我可以禁用它们,因为我目前没有看到任何其他解决方法。

基本上,你不能这样做。 LLVM 假定所有浮点运算都使用默认的舍入模式,并且永远不会读取或修改浮点控制寄存器。

已经有 some discussion of this issue recently on the LLVM-dev mailing list,如果你有兴趣的话。

与此同时,唯一可靠的解决方法是使用内联汇编,例如 asm!("addsd [=10=], "

Rust 的标准库也假定您不修改舍入模式(特别是,浮点数和字符串之间转换的代码对此很敏感)。