(Off topic "Note" correction)
In my previous note I suggested the instruction "movsbq dh -> rdx". There is no such instruction! One cannot encode register ah/bh/ch/dh in an instruction requiring a REX prefix. A REX prefix would be required for sign extending ah/bh/ch/dh to 64 bits.
My note does apply to zero extending dh to 64 bits. "movzbl dh -> edx" achieves this since edx is implicitly zero extended to rdx.

This is different from PR50176, at least the incomplete patch there wouldn't do anything for this testcase (the PR50176 problem is QImode and 32-bit IA-32 code with the unavailability of %sil/%dil/%bpl registers).
The problem in this PR (at least that we don't generate the same code as 4.6 did) is that the REE pass doesn't do anything here, because of the
&& REGNO (dest) == REGNO (XEXP (src, 0))
check in add_removable_extension. We have
(set (reg:HI %ax) (mem:HI (whatever)))
(set (reg:DI %rdx) (sign_extend:DI (reg:HI %ax))
(set (reg:DI %rax) (zero_extend:DI (reg:QI %al))
and when processing the sign_extend, we give up because of that failed REGNO == REGNO check, and while we queue the zero_extend, that alone can't be optimized,
both as it is a MEM:HI load, not QImode load, and because changing it into movzbl would make the sign extension wrong.
Perhaps we could extend the REE pass for this slightly, by allowing REGNO != REGNO, if there is just a single reaching def and the REGNO != REGNO extension is the first use of that reg (i.e. all other uses are dominated by the extension being considered). Then perhaps we could attempt to change the load from loading into reg:HI %ax into sign extending load from HI to reg:DI %rdx, followed by either adding there a (set (reg:DI %rax) (reg:DI %rdx)) move where the sign extension currently is (and hoping some further pass will propagate that into all other uses), or changing all uses (from ax/al to dx/dl) right away.

Jakub,
I'm playing with some of your ideas from c#5. It's actually not a bad approach to fixing this problem.
Presumably in the REGNO != REGNO case, if we were to allow it, the requirement that there be a single reaching def is so that we don't end up with different destination registers in the different reaching defs. Right? It also makes updating marginally easier as there's only one def to fixup.
I don't offhand recall a good way to test that the extension under consideration dominates all the others. Can't they be in arbitrary blocks and locations within the blocks? And "all the others" presumably means other users of the original memory load, right? What did you have in mind for testing this?
We definitely want to change the destination of the load to use the other register and emit a copy from the other register to the load's original destination. That insn needs to be emitted immediately after the defining insn. And yes, the hard register propagation pass should propagate away the copy most of the time.
Anyway, it's showing enough promise that I'll keep poking.

Author: law
Date: Wed Jan 8 06:03:12 2014
New Revision: 206418
URL: http://gcc.gnu.org/viewcvs?rev=206418&root=gcc&view=rev
Log:
PR middle-end/53623
* ree.c (combine_set_extension): Handle case where source
and destination registers in an extension insn are different.
(combine_reaching_defs): Allow source and destination
registers in extension to be different under limited
circumstances.
(add_removable_extension): Remove restriction that the
source and destination registers in the extension are the
same.
(find_and_remove_re): Emit a copy from the extension's
destination to its source after the defining insn if
the source and destination registers are different.
PR middle-end/53623
* gcc.target/i386/pr53623.c: New test.
Added:
trunk/gcc/testsuite/gcc.target/i386/pr53623.c
Modified:
trunk/gcc/ChangeLog
trunk/gcc/ree.c
trunk/gcc/testsuite/ChangeLog

(In reply to H.J. Lu from comment #12)
> This regression is only fixed in 4.9 and should be backported to 4.8
> branch.
Unfortunately, r206418 introduced many regressions. Backport r206418
requires backporting all bug fixes caused by r206418.