我在某处看到 GCC 编译器有时更喜欢在将我的代码转换为 ASM 时不使用条件 mov。
在什么情况下它可能会选择做条件 mov 以外的事情?
在这段代码中,它被写成result += runs[i] > runs[i-1];一个隐式条件语句。在 C++ 中,分支预测器是否对该语句进行预测?或者我是否必须明确使用if关键字来进行分支预测?
using namespace std;
int progressDays(vector<int> runs) {
if (runs.size() < 2) {return 0;}
int result = 0;
for (int i = 1; i < runs.size(); i++) {result += runs[i] > runs[i-1];}
return result;
}
Run Code Online (Sandbox Code Playgroud) 我有一个值int x,我想有条件地添加(例如)一个值int y,具体取决于bool c. 我可以写这样的代码:
bool c; // C23, or stdbool.h macro for _Bool. Converts to integer 0 or 1
int x, y; // x could be a global or something
...
if (c)
x += y;
Run Code Online (Sandbox Code Playgroud)
如果没有分支我怎么能写这个?
ifx是一个没有其他线程可以引用的局部变量,如果编译器认为这样更有效,则可以将 if 转换为无分支。(特别是在自动向量化的情况下,但也适用于标量。)但这对于全局变量来说不是线程安全的,或者如果x实际上是*x带有int *. 编译器无法发明类似于*x += 0抽象机不读取或写入的可能共享对象的写入,这可能会引入数据竞争并影响其他线程存储的值。
c bit-manipulation micro-optimization twos-complement branchless
下面是一些 C++ 伪代码作为示例:
bool importantFlag = false;
for (SomeObject obj : arr) {
if (obj.someBool) {
importantFlag = true;
}
obj.doSomethingUnrelated();
}
Run Code Online (Sandbox Code Playgroud)
显然,一旦 if 语句评估为 true 并运行内部代码,就没有理由再次执行检查,因为无论哪种方式结果都是相同的。编译器是否足够聪明,能够识别这一点,还是会在每次循环迭代中继续检查 if 语句,并可能再次将 importantFlag 冗余地分配为 true?如果循环迭代次数很大,并且无法跳出循环,则这可能会对性能产生显着影响。
我通常会忽略这些情况,只是将信心寄托在编译器上,但如果能确切地知道它如何处理这些情况,那就太好了。
我有memchr我要使非分支的这段代码:
.globl memchr
memchr:
mov %rdx, %rcx
mov %sil, %al
cld
repne scasb
lea -1(%rdi), %rax
test %rcx, %rcx
cmove %rcx, %rax
ret
Run Code Online (Sandbox Code Playgroud)
我不确定是否cmove是分支指令。是吗?如果是这样,如何重新排列我的代码,使其不分支?
assembly x86-64 cpu-architecture micro-optimization branch-prediction