如何在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:

我想在执行位移位后获得进位标志的值

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:
  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]
将是一个轻微的优化,但内存dest
shr
在英特尔(如Skylake)上是一条3-uop指令,内存dest
setcc
是2个uop,因此总共是5个uop,这与使用
movzx eax,byte[rdi]可以做的一样
/
rorx edx、eax、1
复制和移位/
和al、1
/2x存储。但是如果没有BMI2 rorx(或者如果编译器在忽略高位的情况下无法使用它进行右移),您的方式会更好,而且无论哪种方式,代码大小都会更小。我不认为您可以拥有更好的程序集。