LLVM and GCC are great at optimizing until the last leg of the race where they convert IR to assembly code. Their back-ends were designed for modern systems, not the ancient 6502, and so getting them to work involves kludges and clever hacks. I recall there being a video on how LLVM approaches this - search LLVM MOS on youtube.
I plan on writing an article on how my own code generator works. If you check my HN profile in a week or two you'll probably see it submitted.