On Mon, May 2, 2011 at 10:16 PM, Jakub Jelinek <ja...@redhat.com> wrote:
> As written in the PR, the testcase in the patch is miscompiled on > x86_64-linux, because during IRA a *btdi operand is changed from > register to CONST_INT 1 (to which that register was initialized). > Unfortunately when both 2nd and 3rd ZERO_EXTEND operands are constant > integers, *testqi_ext_3{,_rex64} patterns match it wrongly too, > but of course when splitting it into andl/q (which isn't desirable on > TARGET_USE_BT targets anyway) using CCCmode is wrong, as the jump then > looks at the carry bit set by bt{l,q}, while after and{l,q} the interesting > bit is the zero flag. > > The following patch is one of the many possibilities to fix it, > bootstrapped/regtested on x86_64-linux and i686-linux. > > Other options include just doing != CCCmode tests and remove the const1_rtx > checks from the patch, or on the other side also testing TARGET_USE_BT || > -Os, or for the define_insn moving *bt<mode> pattern earlier (the splitter > would still need guarding), or perhaps representing bt{l,q} insns > differently in RTL. I believe this bug is latent starting with 4.4, > when *bt<mode> insn has been added. IMO, this problem arises due to wrong fix for PR target/37184 [1] that added CCA, CCC, CCO, CCS mode bypasses to ix86_match_ccmode. We should make these new modes incompatible to every other requested mode, so perhaps something like attached (totally untested) patch fixes these problems in more general way. Jakub, can you please check the patch, I'm not able to test it properly until tonight. [1] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37184 Thanks, Uros. Index: i386.c =================================================================== --- i386.c (revision 173287) +++ i386.c (working copy) @@ -17299,11 +17299,15 @@ ix86_match_ccmode (rtx insn, enum machin if (req_mode == CCZmode) return false; /* FALLTHRU */ + case CCZmode: + break; + case CCAmode: case CCCmode: case CCOmode: case CCSmode: - case CCZmode: + if (set_mode != req_mode) + return false; break; default: