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 的标准库也假定您不修改舍入模式(特别是,浮点数和字符串之间转换的代码对此很敏感)。
我正在开发一个 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 的标准库也假定您不修改舍入模式(特别是,浮点数和字符串之间转换的代码对此很敏感)。