The bad name for many premature optimizations comes from being for a different age.
Then:
- Memory is scarce, but access is cheap
- Instructions are expensive
- Optimizers are stupid, and are easily outdone manually. Your compiler needs a lot of "hints"
- (at least for for the x86 platform): Multiplication is slow, division triply so, and floating point may take ages. Source to machine code was rather straightforward, and CPU's would more or less execute that step by step.
Now:
- There's more than enough memory for most applications, but access is strongly nonlinear (hotspot access is still cheap)
- Instructions are very cheap
- Optimizers are more clever than most of us. They even understand the C++ standard better than many of us do
- (x86) We've moved from a CISC architecture to a RISCified arhitecture executing RISCified CISC code. And only Agner Fog and your optimizer know what that actually means.
One thing to note is when moving from desktop to embedded, you get a general technology throwback of ten years.
So here's a list of things I either leave to my compiler, or don't bother anymore
- replacing multiplication by constant by shift-and-add
(e.g. x*5 == x+(x<<2))
- replacing integer division by constant by overflow-multiplication
- precalculating constants
- lookup tables, e.g. for fast but less accurate sine calculation.
- XOR fpor integer swap
- hoisting simple constant evaluations out of a loop
- unrolling short constant-length loops
Premature optimizations aren't bad as such. Otherwise, we'd all have to use Bubble sort until proven that the sort is a bottleneck :-)
Knuth, in his original quote, critizised focusing on the small things rather than dealing with performance on a higher level - design, data access patterns and algorithms.
Early optimization (or "optimization by suspicion", as you say, I like that term) is evil only if it's not proven to be effective and degrades another aspect the code (such as readability, simplicity or flexibility).
Also, library code gets some leeway. You don't know how often your new UnfuddleString functions gets called per end-user action, after all.