Skip to content

Instantly share code, notes, and snippets.

@BlueRyth
Last active August 29, 2015 14:15
Show Gist options
  • Save BlueRyth/473f4cbff279baf8814c to your computer and use it in GitHub Desktop.
Save BlueRyth/473f4cbff279baf8814c to your computer and use it in GitHub Desktop.
On the topic of swaps...
The xor swap is a fairly well-known optimization used in lower level languages
to swap the value between two variables without the need for temporary storage.
Almost everyone has an opinion on it. It avoids allocation. It reduces
readability. It's great! It's bad!
Working in VS2013, let's take a look at what C++ does to the swap after
optimization. A dynamic environment is required to keep the compiler from
making too many optimizations like using constant values, unrolling loops, etc.
I'll be setting up a test with arrays of random values on the heap, iterating
over the elements and swapping their values.
The following is short-hand, as the specific assembly generated deviates on
registers, widths, etc.
x ^= y; -> mov eax, [ecx]
y ^= x; -> xor [edx], eax
x ^= y; -> mov eax, [edx]
-> xor [ecx], eax
-> mov eax, [ecx]
-> xor [edx], eax
This is just the gist of it, at least, but it does what's expected. This
doesn't change if we avoid the ^= operator and write out the swap long-hand.
The alternative, or naive, approach uses a temporary variable to facilitate the
swap (we'll call ours t):
auto t = x; -> mov eax, [ecx]
x = y; -> mov ebx, [edx]
y = t; -> mov [ecx], ebx
-> mov [edx], eax
And that's where things get interesting. The compiler optimizes away the
temporary variable allocation. And if we use the std::swap(...)?
std::swap(x, y) -> mov eax, [ecx]
-> mov ebx, [edx]
-> mov [ecx], ebx
-> mov [edx], eax
Interesting. Take from it what you will.
#include <cstdio>
#include <random>
int main(void)
{
std::random_device rd;
std::default_random_engine eng;
std::uniform_int_distribution<int> rand(-INT_MAX, INT_MAX);
std::uniform_int_distribution<unsigned int> urand(0, UINT_MAX);
unsigned int count = rand(eng);
int* x = new int[count];
int* y = new int[count];
for (int i = 0; i < count; i++)
{
x[i] = rand(eng);
y[i] = rand(eng);
}
for (int i = 0; i < count; i++)
{
x[i] ^= y[i];
y[i] ^= x[i];
x[i] ^= y[i];
}
for (int i = 0; i < count; i++)
{
printf("%d\n", x[i]);
}
delete[] x;
delete[] y;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment