I originally did put loop alignment in my asm version, but I took it out because it was actually ever so slightly slower on mine. Make of that what you will.
The sorttest.zip Makefile has only the following flags specified: -O3 --std=c++11
Where bjourne has: -O3 --std=c++11 -fomit-frame-pointer -march=native -mtune=native
I might rerun your tests with bjourne's additions!
sortRoutine:
; rdi = items
; esi = count
push rbp ; <- stack alignment push
sortRoutine_start:
cmp esi, 2
jb done
dec esi
The "cmp esi, 2; jb done; dec esi" corresponds to your "sub rdx, 1; jbe done". That improves it on my machine to 63 ms/loop. If you are interested I can put it online somewhere. push rbp ; <- stack alignment push
This shouldn't be needed. 8 byte alignment is fine for the CPU itself. The purpose of 16 byte alignment is to facilitate making 16 byte aligned stack allocations.http://stackoverflow.com/questions/612443/why-does-the-mac-a...
I also checked similar manual for AMD and it doesn't seem to mention RSP alignment at all, except that "some calling conventions may require ...".
The CPU doesn't care. It only matters when you call functions which allocate 16B objects on the stack.* This function calls only itself and pushes only 8B words on the stack so it's fine with 8B alignment.
* Some functions generated by C compilers do and they segfault if you call them with wrong alignment. Ask me how I know.
edit:
OK, so I downloaded this code. Results:
as-is: 78111us
push rbp: 73093us
sub rsp,8: 72332us
sub rax,8: 72222us
Seems to be a matter of instruction alignment, nothing to do with the stack.Can you explain why this is faster? I assumed the ALU would be 64 bits wide, and 32-bit operations would just leave half of it unused.
Though I was wrong about that particular case because "xor r9d, r9d" and "xor r9, r9" are both three bytes long. But "xor eax, eax" is two bytes and "xor rax, rax" is three bytes. So that's why you should use the old GPR:s when you are able to choose.
Here are my results:
Compiler flags: -O3 --std=c++11 -fomit-frame-pointer -march=native -mtune=nativeSo on my computer, the assembly code (barely) beat g++ but not clang++. From a cursory glance of the assembler code clang++ generates, the difference seem to be that it adds alignment to critical loops.
It is also smarter at using 32bit registers when it can get away with it. F.e the handwritten assembler code contains "xor r9, r9". An equivalent but faster variant that the compiler generates is "xor r9d, r9d".
There is also a slight error in the assembly code. rsp should be aligned to a 16 byte boundary when a call instruction is executed and the code doesn't ensure that. Likely it loses a whole bunch of performance by calling from unaligned addresses.