当前位置: 首页 > 知识库问答 >
问题:

在单个CPU指令中可以在0和1之间翻转位/整数/布尔的任何可能的代码

阳兴朝
2023-03-14

一条x86指令可以在“0”和“1”之间切换布尔值吗?

我想到了以下的方法,但所有的结果是两个指令与-O3标志的GCC。

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; }

在Godbolt上对此进行编译:

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

共有1个答案

宗意蕴
2023-03-14

若要翻转整数中的一个位,请使用异或,如下所示:foo^=1

gcc已经知道针对bool的这种优化,因此您可以像正常人一样返回!status;而不会损失任何效率。gcc也会将status|^=1编译为xor指令。事实上,除了表查找之外,您的所有想法都编译成一个带有bool输入/返回值的XOR指令。

在Godbolt编译器资源管理器中使用gcc-o3查看它,并使用boolint的asm输出窗格。

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

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

vs.

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

这就是获得test/setcc(通过异或将零扩展为32位int的原因-在测试之前将寄存器清零)。

相关:编译器中的布尔值为8位。对他们的操作效率低吗?。像(bool1&&bool2)这样的东西?x:y的编译效率并不总是如您所希望的那样高。编译器是很好的,但确实有遗漏优化的bug。

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

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

x86没有复制与异或整数指令,因此对于独立函数来说,至少需要一个mov才能从参数传递寄存器复制到eax

LEA很特别:它是为数不多的整数ALU指令之一,可以将结果写入不同的寄存器,而不是破坏其输入。lea是一个复制和移位/添加指令,但x86中没有复制和异或指令。许多RISC指令集具有3操作数指令,例如MIPS可以执行异或$T1、$T2、$T3

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

 类似资料:
  • 问题内容: 我想转换一个查询,例如: 进入一个位掩码,其中的位是由上面的值定义的。 例如,如果和为true,则我想要或。 我想到以下几点: 但是我不确定这是否是最好的方法,而且看起来很冗长。是否有捷径可寻? 问题答案: 对于位掩码,类型 将是更好的选择。然后可能看起来像这样: 皈依,对。您可以简单地将位连接为位串。 将bit(n)转换为整数 看来您需要一个结果-有一个简单而快速的方法: 请务必阅读

  • 给定布尔值如何来回翻转它?我当然可以这样做: 但那感觉太长了。有什么巧妙而干净的方法可以做到这一点吗?谢谢。

  • 问题内容: 我在Python中有一个布尔列表 我想将其更改为与逻辑相反 的方法吗?在Python中是否有一种内置的方法(类似于call )可以执行此操作,而无需使用手写循环来反转元素? 问题答案: 列表理解很容易: 产量

  • 问题内容: 在python中,我得到了一个64位整数。该整数是通过采用几个不同的8位整数并将它们混搭为一个64位巨型整数而创建的。再次将它们分开是我的工作。 例如: 所以我想做的是获取我的源代码并返回一个长度为8的数组,其中数组中的每个int都是上面列出的int。 我打算使用,但老实说,阅读文档并不清楚我将如何实现。 问题答案: 在Python 2.x中,返回一个字节字符串。将其转换为整数数组很容

  • 本文向大家介绍在C ++中可以被2和7整除的前N个自然数之和,包括了在C ++中可以被2和7整除的前N个自然数之和的使用技巧和注意事项,需要的朋友参考一下 在这个问题中,我们得到一个数字N。我们的任务是找到可以被2和7整除的前N个自然数之和。 因此,在这里我们将得到一个数字N,程序将找到1到N之间的数字之和,该数字之和可被2和7整除。 让我们举个例子来了解这个问题, 输入- 输出- 说明- 因此,

  • 求可被1到N的所有数整除的最小数,不留余数。由于数字可能非常大,我们取模100000007的答案。 我认为可以被从1到N的所有数字整除的最小数字是LCM(1... N)。 例如:对于N=5,最小值为60。 因为60是能被所有数字形式(1-5)整除的最小数。 但由于一些奇怪的原因,它给了我错误的答案大N(1000),等等。什么可以导致这里可能的错误,我在这里的登录正确吗? 这是我试图实现的。