Here is a benchmark:
fn benchmark_or(repetitions: usize, mut increment: usize) -> usize {
let mut batch = 0;
for _ in 0..repetitions {
increment |= 1;
batch += increment | 1;
}
batch
}
fn benchmark_xor(repetitions: usize, mut increment: usize) -> usize {
let mut batch = 0;
for _ in 0..repetitions {
increment ^= 1;
batch += increment | 1;
}
batch
}
fn benchmark(c: &mut Criterion) {
let increment = 1;
let repetitions = 1000;
c.bench_function("Increment Or", |b| {
b.iter(|| black_box(benchmark_or(repetitions, increment)))
});
c.bench_function("Increment Xor", |b| {
b.iter(|| black_box(benchmark_xor(repetitions, increment)))
});
}
The results are:
Increment Or time: [271.02 ns 271.14 ns 271.28 ns]
Increment Xor time: [79.656 ns 79.761 ns 79.885 ns]
I get the same result if I replace or with and.
It's quite confusing as the or bench compiles to
.LBB0_5:
or edi, 1
add eax, edi
add rcx, -1
jne .LBB0_5
And the xor bench compiles to basically the same instructions plus two additional ones:
.LBB1_6:
xor edx, 1
or edi, 1
add eax, edi
mov edi, edx
add rcx, -1
jne .LBB1_6
Why is the difference so large?