I've been optimizing some code and I've discovered something that I find upsetting. It appears that even the most trivial move operations can produce in-memory copies (sometimes actual calls to memcpy).
Here is a simplified example to illustrate. In practice I would expect this code to essentially compile down to the same machine code as a an isomorphic formulation using &mut but it appears to be creating a new buffer on the stack for each move. It even does this when the code is inlined.
Is there a trick to tell the compiler I want it to reuse the memory?
Your calls to addr_of!() are constraining what the optimizer can do (in practice, even if not in theory). Delete them and you get only one memcpy instead of three.
Thanks! Very interesting... Do you know why this happens?
I thought perhaps addr_of! is using the same back-end infrastructure as const borrowing, so the optimizer thinks it can't let an object mutate while it's borrowed? But that hypothesis seems silly because const borrows do end.
Thanks again. I would not have guessed that would have affected the optimizer.
If you ask for the address of something, then it has to have a specific address that it is at, for at least as long as the pointer might be read. If you don't ask, then moving the value has no effect on the program's behavior at all, so the optimizer is free to use as many or as few distinct locations as it likes; there are no constraints.
That makes sense. The variable binding is an alias, but maybe there is something in the specification that local variables live contiguously in their stack frame (just guessing...) so asking for an address forces a memcpy to make that happen.
As a related example, observing the address of something can force it to be on the stack when it otherwise might have been put in a register (since register's don't have addresses, for one; and because if you're observing the address, presumably it is significant to you, for another).