Hi, insn_invalid_p might add clobbers in order to match an instruction. Unfortunately that change is not recorded in the 'changes' array. So if it is decided to rollback the changes the added clobbers will stay. This is a problem if the back-end provides two (mostly) identical insn patterns, one of them with a clobber and the other without. Adding a clobber might allow to pick the other pattern. If this is part of a bigger change which is rolled back, the insn code will be set back to the old value but the clobbers won't be removed. The result is an insn where the code doesn't match the pattern.
This currently breaks Ada bootstrap on s390x. The problem has been revealed by the recent fwprop change: http://gcc.gnu.org/ml/gcc-patches/2012-03/msg01269.html Fixed with the attached patch. Bootstrapped and regtested on s390x, ppc64 and x86_64. Ok for mainline? Bye, -Andreas- 2012-04-20 Andreas Krebbel <andreas.kreb...@de.ibm.com> * recog.c (insn_invalid_p): Add IN_GROUP parameter and use validate_change to add clobbers if IN_GROUP is nonzero. (verify_changes): Set IN_GROUP parameter to true. * recog.h (insn_invalid_p): Add IN_GROUP parameter to function prototype. * gcse.c (process_insert_insn): Set IN_GROUP to false. * config/s390/s390.c (insn_invalid_p): Set IN_GROUP to false. --- gcc/config/s390/s390.c | 4 !!!! gcc/gcse.c | 2 !! gcc/recog.c | 15 !!!!!!!!!!!!!!! gcc/recog.h | 2 !! 4 files changed, 23 modifications(!) Index: gcc/recog.c =================================================================== *** gcc/recog.c.orig --- gcc/recog.c *************** canonicalize_change_group (rtx insn, rtx *** 309,318 **** /* This subroutine of apply_change_group verifies whether the changes to INSN ! were valid; i.e. whether INSN can still be recognized. */ int ! insn_invalid_p (rtx insn) { rtx pat = PATTERN (insn); int num_clobbers = 0; --- 309,322 ---- /* This subroutine of apply_change_group verifies whether the changes to INSN ! were valid; i.e. whether INSN can still be recognized. ! ! If IN_GROUP is true clobbers which have to be added in order to ! match the instructions will be added to the current change group. ! Otherwise the changes will take effect immediately. */ int ! insn_invalid_p (rtx insn, bool in_group) { rtx pat = PATTERN (insn); int num_clobbers = 0; *************** insn_invalid_p (rtx insn) *** 344,350 **** newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_clobbers + 1)); XVECEXP (newpat, 0, 0) = pat; add_clobbers (newpat, icode); ! PATTERN (insn) = pat = newpat; } /* After reload, verify that all constraints are satisfied. */ --- 348,357 ---- newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_clobbers + 1)); XVECEXP (newpat, 0, 0) = pat; add_clobbers (newpat, icode); ! if (in_group) ! validate_change (insn, &PATTERN (insn), newpat, 1); ! else ! PATTERN (insn) = pat = newpat; } /* After reload, verify that all constraints are satisfied. */ *************** verify_changes (int num) *** 413,419 **** } else if (DEBUG_INSN_P (object)) continue; ! else if (insn_invalid_p (object)) { rtx pat = PATTERN (object); --- 420,426 ---- } else if (DEBUG_INSN_P (object)) continue; ! else if (insn_invalid_p (object, true)) { rtx pat = PATTERN (object); Index: gcc/gcse.c =================================================================== *** gcc/gcse.c.orig --- gcc/gcse.c *************** process_insert_insn (struct expr *expr) *** 2087,2093 **** { rtx insn = emit_insn (gen_rtx_SET (VOIDmode, reg, exp)); ! if (insn_invalid_p (insn)) gcc_unreachable (); } --- 2087,2093 ---- { rtx insn = emit_insn (gen_rtx_SET (VOIDmode, reg, exp)); ! if (insn_invalid_p (insn, false)) gcc_unreachable (); } Index: gcc/recog.h =================================================================== *** gcc/recog.h.orig --- gcc/recog.h *************** extern int asm_operand_ok (rtx, const ch *** 79,85 **** extern bool validate_change (rtx, rtx *, rtx, bool); extern bool validate_unshare_change (rtx, rtx *, rtx, bool); extern bool canonicalize_change_group (rtx insn, rtx x); ! extern int insn_invalid_p (rtx); extern int verify_changes (int); extern void confirm_change_group (void); extern int apply_change_group (void); --- 79,85 ---- extern bool validate_change (rtx, rtx *, rtx, bool); extern bool validate_unshare_change (rtx, rtx *, rtx, bool); extern bool canonicalize_change_group (rtx insn, rtx x); ! extern int insn_invalid_p (rtx, bool); extern int verify_changes (int); extern void confirm_change_group (void); extern int apply_change_group (void); Index: gcc/config/s390/s390.c =================================================================== *** gcc/config/s390/s390.c.orig --- gcc/config/s390/s390.c *************** s390_expand_addcc (enum rtx_code cmp_cod *** 4413,4419 **** insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); /* We use insn_invalid_p here to add clobbers if required. */ ! ret = insn_invalid_p (emit_insn (insn)); gcc_assert (!ret); /* Emit ALC instruction pattern. */ --- 4413,4419 ---- insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); /* We use insn_invalid_p here to add clobbers if required. */ ! ret = insn_invalid_p (emit_insn (insn), false); gcc_assert (!ret); /* Emit ALC instruction pattern. */ *************** s390_expand_addcc (enum rtx_code cmp_cod *** 4485,4491 **** insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); /* We use insn_invalid_p here to add clobbers if required. */ ! ret = insn_invalid_p (emit_insn (insn)); gcc_assert (!ret); /* Emit SLB instruction pattern. */ --- 4485,4491 ---- insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); /* We use insn_invalid_p here to add clobbers if required. */ ! ret = insn_invalid_p (emit_insn (insn), false); gcc_assert (!ret); /* Emit SLB instruction pattern. */