Last active
August 29, 2015 14:15
-
-
Save BlueRyth/473f4cbff279baf8814c to your computer and use it in GitHub Desktop.
On the topic of swaps...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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