Calls and other instructions that use specific registers (variable shift and division on x86, for example) tend to ruin that ideal somewhat.
Calling conventions are similar (e.g. eax needs to be the return value), so you see things like this:
mov ecx, [ebp+16]
add ecx, edx
mov eax, ecx ; superfluous move
ret
when this could've been done instead: mov eax, [ebp+16]
add eax, edx
retHigher quality compilers will also try things like commuting instructions, using lea as a three-address add, etc to avoid a move.
[1] Some recent progress on register allocation over SSA may improve this situation, but I don't think that work has made it into production compilers yet.