如何在Rust中获取进位标志的值
我想在执行位移位后获得进位标志的值 Rust具有稳定的功能,可检查溢流,如下所示:如何在Rust中获取进位标志的值,rust,x86,bit-shift,carryflag,Rust,X86,Bit Shift,Carryflag,我想在执行位移位后获得进位标志的值 Rust具有稳定的功能,可检查溢流,如下所示: pub fn add_with_carry(foo : &mut u8, bar : u8, cf : &mut u8) { let(result, overflow) = foo.overflowing_add(bar); *foo = result; *cf = overflow as u8; } 生成如下程序集: example::add_with_carry:
pub fn add_with_carry(foo : &mut u8, bar : u8, cf : &mut u8) {
let(result, overflow) = foo.overflowing_add(bar);
*foo = result;
*cf = overflow as u8;
}
生成如下程序集:
example::add_with_carry:
add byte ptr [rdi], sil
setb byte ptr [rdx]
ret
然而,溢出\u shr
仅当值被大小移位或更大时才返回true,我只关心最低有效位,它将存储在CF中,目前我得到的最好结果是:
pub fn shr(foo : &mut u8, cf : &mut u8) {
*cf = *foo & 1;
*foo >>=1
}
然而,这有点不太有效:
example::shr:
mov al, byte ptr [rdi]
and al, 1
mov byte ptr [rsi], al
shr byte ptr [rdi]
ret
我宁愿吃一些像:
example::shr:
shr byte ptr [rdi]
setc byte ptr [rdx]
ret
似乎不存在获取CF的内在机制,内联程序集目前不稳定。我猜别名分析无法证明
CF
和foo
都指向同一字节。如果将*foo&1
保存在本地变量中并分配给*cf
2nd,则编译器可以加载、移位、存储移位结果,然后存储and或SETC结果。然后,您将有一个真正的错误,您可以将其报告为LLVM错误。语言是否需要特征来揭示右移的结果尚不清楚;并非所有的ISA都有标志(例如MIPS),因此您无法在所有CPU上免费获得它。但这可能会对编译器有所帮助。使用shr[mem]
/setc[mem]
将是一个轻微的优化,但内存destshr
在英特尔(如Skylake)上是一条3-uop指令,内存destsetcc
是2个uop,因此总共是5个uop,这与使用movzx eax,byte[rdi]可以做的一样
/rorx edx、eax、1
复制和移位/和al、1
/2x存储。但是如果没有BMI2 rorx(或者如果编译器在忽略高位的情况下无法使用它进行右移),您的方式会更好,而且无论哪种方式,代码大小都会更小。我不认为您可以拥有更好的程序集。