- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
单个 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; }
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 explorer与 gcc -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
必须是 0
或 1
, 它无法优化 !foo
至 foo^=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 指令之一,可以将结果写入不同的寄存器而不是破坏其输入。 lea
是 copy-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/
我正在尝试学习 Fortran,并且看到了很多不同的定义,我想知道他们是否正在尝试完成同样的事情。以下有什么区别? 整数*4 整数(4) 整数(kind=4) 最佳答案 在 Fortran >=90
我以前从未编程过,最近(1 周前)才开始学习!第一门类(class)是函数式编程,使用 Haskell。 我有一项学校作业,我想通过删除一两个步骤来改进它,但我遇到了一个讨厌的错误。 基本上,我创建了
给定以下GraphQL请求和变量: 请求: query accounts($filter:AccountFilter, $first_:String, $skip_:Int) { accounts
我已经搜索了 StackOverflow,但找不到关于如何检查计算器应用程序的数字输入正则表达式的答案,该计算器应用程序将检查每个 keyup 的以下格式(jquery key up): 任何整数,例
类似于我上一篇致歉的文章,但没有那么长篇大论。基本上我想知道当每次重绘调用只重绘屏幕的一小部分时,优化重绘到 JFrame/JPanel 的最佳选择是什么。 此外,除了重绘重载之外,我并不是 100%
所以在我的教科书中有一个使用 f# 的递归函数的例子 let rec gcd = function | (0,n) -> n | (m,n) -> gcd(n % m,m);; 使用此功能,我的教科书
我有一个数据结构,例如表达式树或图形。我想添加一些“测量”功能,例如depth和 size . 如何最好地键入这些函数? 我认为以下三个变体的用处大致相同: depth :: Expr -> Int
这样写比较好 int primitive1 = 3, primitive2 = 4; Integer a = new Integer(primitive1); Integer b = new Inte
我是 Java 8 新手,想根据键对 Map 进行排序,然后在值内对每个列表进行排序。 我试图寻找一种 Java 8 方法来对键和值进行排序。HashMap>映射 map.entrySet().str
这就是我的目标... vector ,int> > var_name (x, pair (y),int>); 其中 x 是 vector var_name 的大小,y 是对内 vector 的大小。
这里是 an answer to "How do I instantiate a Queue object in java?" , Queue is an interface. You can't i
这个问题在这里已经有了答案: Weird Integer boxing in Java (12 个答案) Why are autoboxed Integers and .getClass() val
我们可以使用 C++ STL 做这样的事情吗?如果是,我将如何初始化元素?我试图这样做,但没有成功。 pair,vector>p; p.first[0]=2; 最佳答案 Can we do som
您好,我正在尝试为百分比和整数数组中的数字找到索引。假设 arraynum = ['10%','250','20%','500'] 并且用户发送一个值 15%,这个数字在哪个范围内居住?我可以使用这段
我与三列有关系:ProductName、CategoryID 和 Price。我需要选择仅那些价格高于给定类别中平均产品价格的产品。(例如,当apple(ProductName)是fruit(Cate
我已经坚持了一段时间,我正在尝试将一些数据配对在一起。这是我的代码。 #include #include using namespace std; int main() { pair data(
我收到错误:'(Int, Int)' 与 'CGPoint' 不相同 如何将 (Int, Int) 转换为 CGPoint let zigzag = [(100,100), (100,150)
我在 .cpp 文件中发现了以下代码。我不理解涉及头文件的构造或语法。我确实认识到这些特定的头文件与 Android NDK 相关。但是,我认为这个问题是关于 C++ 语法的一般问题。这些在某种程度上
我将这些输入到 Scala 解释器中: val a : Integer = 1; val b : Integer = a + 1; 我收到消息: :5: error: type mismatch;
C++:vector>v(size);当我试图打印出值时显示 0 作为值,但是当未声明 vector 大小时它显示正确的输出?为什么这样?例如: int x; cin>>x; vector>v(x);
我是一名优秀的程序员,十分优秀!