J.S. Cruz

Know Your Sizes

Just because a type is complex, doesn’t mean it is expensive to copy.

I see code like this sometimes:

1void bar(const std::pair<int, int>&)
2{
3    // I avoided an extra copy!
4}

In a 64-bit machine, an std::pair of integers is 64 bits. If you pass it to a function by reference, the compiler will pass in the address of the pair in a register, which is also 64 bits.

Instead of just putting the two integers in the register, you’re putting their address, so you have a useless indirection when you use the pair in the function!

1int foo(      std::pair<int, int>  p) { return p.first; }
2int bar(const std::pair<int, int>& p) { return p.first; }
 1-_Z3fooSt4pairIiiE:
 2+_Z3barRKSt4pairIiiE:
 3        pushq   %rbp
 4        movq    %rsp, %rbp
 5        movq    %rdi, -8(%rbp)
 6-       movl    -8(%rbp), %eax
 7+       movq    -8(%rbp), %rax
 8+       movl    (%rax), %eax
 9        popq    %rbp
10        ret

Look at that line 8! What a silly dereference!

The entire pair fits in %rdi, so just pass it directly. I’d go further: x64 has six registers available for parameter passing, which comes out to a total of 384 bits which are easily passed into the function before register spilling happens. For any arguments size fewer than 384 bits, just pass them in by value!

Tags: #C++ #programming