A recursive AST loop in nested compound statements ({ {} }) persisted for quite a while; it was a result of an optimization to ensure that the production top_statement consistently returned a compound statement node (CNC) even if the program only had a single statement at that point.
I tried to make the use of ECX for "this" part of the general register assignment code, but ended up having to make it a special case when that started getting unmanageable, and I hit cases where "this" was used, but the code decided not to save ECX around calls. Sometimes special cases can simplify.
Various too-aggressive optimizations actually lost information; sometimes temporaries were eliminated. For example, an overly aggressive optimization would optimize out something of the form "a = b / b = a" even in the case that one was a store. Fortunately, tests caught this pretty well.
Another optimization was accidentally erasing the wrong instruction: it removed a jump instruction, instead of an intended unused label.
Assumed for a while that the "not" instruction was boolean negation, when in fact it's one's-complement. (I actually wanted to xor with 1.)
... (%ebx populated earlier) 1 movl $5, %edx 2 movl $10, t3 3 addl %ebx, t3 4 movl -4(%ebp), t3 ... (%edx used later; %ebx and t3 not used again)%edx is live in [1, >4], %ebx is live in [<1, 3], and t3 is live in [2, 4], so %edx is a good candidate for t3 (since its definition is before t3's and its use is after, i.e. it encloses t3 completely) but %ebx is not, since its use is interleaved with t3's.