gpt4 book ai didi

c++ - 可以在单个 CPU 指令中在 0 和 1 之间翻转位/整数/ bool 值的任何可能代码

转载 作者:太空狗 更新时间:2023-10-29 19:40:12 27 4
gpt4 key购买 nike

单个 x86 指令能否在“0”和“1”之间切换 bool 值?

我想到了以下方法,但都导致了两 strip 有 gcc 的 -O3 标志的指令。

status =! status;

status = 1 - status;

status = status == 0 ? 1: 0;

int flip[2] = {1, 0};
status = flip[status];

有没有更快的方法来做到这一点?

这是我试过的:https://godbolt.org/g/A3qNUw


我需要的是一个切换输入和返回的函数,以编译为一条指令的方式编写。类似于此功能的内容:

int addOne(int n) { return n+1; }

compiles on Godbolt对此:

  lea eax, [rdi+1]    # return n+1 in a single instruction
ret

最佳答案

要翻转整数位,请使用 xor像这样:foo ^= 1 .

gcc 已经知道 bool 的优化,所以你可以 return !status;像正常人一样不损失任何效率。 gcc 编译 status ^= 1异或指令也是如此。事实上,除了表查找之外,你所有的想法都会编译成一个 xor。指令 bool输入/返回值。

检查一下 on the Godbolt compiler explorergcc -O3 , 带有 bool 的 asm 输出面板和 int .

MYTYPE func4(MYTYPE status) {
status ^=1;
return status;
}

# same code for bool or int
mov eax, edi
xor eax, 1
ret

对比

MYTYPE func1(MYTYPE status) {
status = !status;
return status;
}

# with -DMYTYPE=bool
mov eax, edi
xor eax, 1
ret

# with int
xor eax, eax
test edi, edi
sete al
ret

半相关:XOR是add-without-carry。所以如果你只关心低位,你可以用 lea eax, [rdi+1] 复制并翻转低位.参见 Check if a number is even and eax, 1 结合使用时很有用只需 2 条指令即可完成。


为什么是bool不同于int

The x86-64 System V ABI要求调用者传递 bool传递 0 或 1 值,而不仅仅是任何非零整数。因此,编译器可以假设输入。

但是用int foo , C 表达式 !foo需要对值进行“ bool 化”。 !foo类型为 _Bool/(又名 bool 如果你 #include <stdbool.h> ),并将其转换回整数必须产生 0 或 1 的值。如果编译器不知道 foo必须是 01 , 它无法优化 !foofoo^=1 ,并且无法意识到 foo ^= 1在 truthy/falsy 之间翻转一个值。 (在某种意义上,if(foo) 在 C 语言中表示 if(foo != 0))。

这就是为什么您得到 test/setcc(在 int 之前由 xor -zeroing a register 零扩展为 32 位 test)。

相关:Boolean values as 8 bit in compilers. Are operations on them inefficient? .像 (bool1 && bool2) ? x : y 这样的东西并不总是像您希望的那样高效地编译。编译器非常好,但确实存在优化错误。


那额外的mov呢?指令?

它会在内联时消失,如果编译器不需要/不想保留旧的未翻转值供以后使用。但是在独立函数中,第一个 arg 在 edi 中,返回值需要在eax中(在 x86-64 System V 调用约定中)。

像这样的微型函数非常接近作为大型函数的一部分可能得到的函数(如果不能将此翻转优化为其他函数),但需要将结果保存在不同的寄存器中是一个混杂因素。


x86 没有复制和异或整数指令,因此对于独立函数,它至少需要 mov。从 arg 传递寄存器复制到 eax .

lea是特殊的:它是为数不多的整数 ALU 指令之一,可以将结果写入不同的寄存器而不是破坏其输入。 leacopy-and-shift/add instruction ,但 x86 中没有复制和异或指令。许多 RISC 指令集有 3 个操作数指令,例如 MIPS 可以做 xor $t1, $t2, $t3 .

AVX 引入了 vector 指令的非破坏性版本(在大量代码中节省了大量 movdqa/movups 寄存器复制),但对于整数,只有少数新指令可以做不同的事情。 rorx eax, ecx, 16 例如 eax = rotate_right(ecx, 16) ,并使用与非破坏性 AVX 指令相同的 VEX 编码。

关于c++ - 可以在单个 CPU 指令中在 0 和 1 之间翻转位/整数/ bool 值的任何可能代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49056128/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com