Hi, This appears to fix the problem with PR53334 and deals with the fallout of not validating properly operands to movsicc. In addition I took the opportunity of merging all the other places where we validized such transforms into a single function and dealt with the fallout accordingly. It also helps some of the tests in the testsuite which were previously ICE'ing as a result of the previous patch to now get fixed up.
Tested cross with trunk for arm-linux-gnueabi with armv7-a (arm/thumb), armv5t multilibs for C,C++, Committed. regards. Ramana 2012-05-22 Ramana Radhakrishnan <ramana.radhakrish...@linaro.org> PR target/53334 * config/arm/arm-protos.h (arm_validize_comparison): Declare. * config/arm/arm.c (arm_validize_comparison): Define. * config/arm/arm.md ("cbranchsi4"): Cleanup expansion and use arm_validize_comparison. ("cbranchdi4"): Likewise. ("cstoredi4"): Likewise. ("movsicc"): Likewise. ("movsfcc"): Likewise. ("movdfcc"): Likewise.
Index: gcc/config/arm/arm.c =================================================================== --- gcc/config/arm/arm.c (revision 187760) +++ gcc/config/arm/arm.c (working copy) @@ -26185,4 +26185,54 @@ #undef BRANCH } + +/* Returns true if a valid comparison operation and makes + the operands in a form that is valid. */ +bool +arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2) +{ + enum rtx_code code = GET_CODE (*comparison); + enum rtx_code canonical_code; + enum machine_mode mode = (GET_MODE (*op1) == VOIDmode) + ? GET_MODE (*op2) : GET_MODE (*op1); + + gcc_assert (GET_MODE (*op1) != VOIDmode || GET_MODE (*op2) != VOIDmode); + + if (code == UNEQ || code == LTGT) + return false; + + canonical_code = arm_canonicalize_comparison (code, op1, op2); + PUT_CODE (*comparison, canonical_code); + + switch (mode) + { + case SImode: + if (!arm_add_operand (*op1, mode)) + *op1 = force_reg (mode, *op1); + if (!arm_add_operand (*op2, mode)) + *op2 = force_reg (mode, *op2); + return true; + + case DImode: + if (!cmpdi_operand (*op1, mode)) + *op1 = force_reg (mode, *op1); + if (!cmpdi_operand (*op2, mode)) + *op2 = force_reg (mode, *op2); + return true; + + case SFmode: + case DFmode: + if (!arm_float_compare_operand (*op1, mode)) + *op1 = force_reg (mode, *op1); + if (!arm_float_compare_operand (*op2, mode)) + *op2 = force_reg (mode, *op2); + return true; + default: + break; + } + + return false; + +} + #include "gt-arm.h" Index: gcc/config/arm/arm-protos.h =================================================================== --- gcc/config/arm/arm-protos.h (revision 187760) +++ gcc/config/arm/arm-protos.h (working copy) @@ -248,6 +248,7 @@ extern void arm_emit_coreregs_64bit_shift (enum rtx_code, rtx, rtx, rtx, rtx, rtx); +extern bool arm_validize_comparison (rtx *, rtx *, rtx *); #endif /* RTX_CODE */ extern void arm_expand_vec_perm (rtx target, rtx op0, rtx op1, rtx sel); Index: gcc/config/arm/arm.md =================================================================== --- gcc/config/arm/arm.md (revision 187760) +++ gcc/config/arm/arm.md (working copy) @@ -6977,12 +6977,12 @@ (match_operand:SI 2 "nonmemory_operand" "")]) (label_ref (match_operand 3 "" "")) (pc)))] - "TARGET_THUMB1 || TARGET_32BIT" + "TARGET_EITHER" " if (!TARGET_THUMB1) { - if (!arm_add_operand (operands[2], SImode)) - operands[2] = force_reg (SImode, operands[2]); + if (!arm_validize_comparison (&operands[0], &operands[1], &operands[2])) + FAIL; emit_jump_insn (gen_cbranch_cc (operands[0], operands[1], operands[2], operands[3])); DONE; @@ -7054,33 +7054,13 @@ (pc)))] "TARGET_32BIT" "{ - rtx swap = NULL_RTX; - enum rtx_code code = GET_CODE (operands[0]); - /* We should not have two constants. */ gcc_assert (GET_MODE (operands[1]) == DImode || GET_MODE (operands[2]) == DImode); - /* Flip unimplemented DImode comparisons to a form that - arm_gen_compare_reg can handle. */ - switch (code) - { - case GT: - swap = gen_rtx_LT (VOIDmode, operands[2], operands[1]); break; - case LE: - swap = gen_rtx_GE (VOIDmode, operands[2], operands[1]); break; - case GTU: - swap = gen_rtx_LTU (VOIDmode, operands[2], operands[1]); break; - case LEU: - swap = gen_rtx_GEU (VOIDmode, operands[2], operands[1]); break; - default: - break; - } - if (swap) - emit_jump_insn (gen_cbranch_cc (swap, operands[2], operands[1], - operands[3])); - else - emit_jump_insn (gen_cbranch_cc (operands[0], operands[1], operands[2], + if (!arm_validize_comparison (&operands[0], &operands[1], &operands[2])) + FAIL; + emit_jump_insn (gen_cbranch_cc (operands[0], operands[1], operands[2], operands[3])); DONE; }" @@ -8065,33 +8045,15 @@ (match_operand:DI 3 "cmpdi_operand" "")]))] "TARGET_32BIT" "{ - rtx swap = NULL_RTX; - enum rtx_code code = GET_CODE (operands[1]); - /* We should not have two constants. */ gcc_assert (GET_MODE (operands[2]) == DImode || GET_MODE (operands[3]) == DImode); - /* Flip unimplemented DImode comparisons to a form that - arm_gen_compare_reg can handle. */ - switch (code) - { - case GT: - swap = gen_rtx_LT (VOIDmode, operands[3], operands[2]); break; - case LE: - swap = gen_rtx_GE (VOIDmode, operands[3], operands[2]); break; - case GTU: - swap = gen_rtx_LTU (VOIDmode, operands[3], operands[2]); break; - case LEU: - swap = gen_rtx_GEU (VOIDmode, operands[3], operands[2]); break; - default: - break; - } - if (swap) - emit_insn (gen_cstore_cc (operands[0], swap, operands[3], - operands[2])); - else - emit_insn (gen_cstore_cc (operands[0], operands[1], operands[2], + if (!arm_validize_comparison (&operands[1], + &operands[2], + &operands[3])) + FAIL; + emit_insn (gen_cstore_cc (operands[0], operands[1], operands[2], operands[3])); DONE; }" @@ -8186,12 +8148,14 @@ "TARGET_32BIT" " { - enum rtx_code code = GET_CODE (operands[1]); + enum rtx_code code; rtx ccreg; - if (code == UNEQ || code == LTGT) + if (!arm_validize_comparison (&operands[1], &XEXP (operands[1], 0), + &XEXP (operands[1], 1))) FAIL; - + + code = GET_CODE (operands[1]); ccreg = arm_gen_compare_reg (code, XEXP (operands[1], 0), XEXP (operands[1], 1), NULL_RTX); operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); @@ -8202,22 +8166,18 @@ [(set (match_operand:SF 0 "s_register_operand" "") (if_then_else:SF (match_operand 1 "expandable_comparison_operator" "") (match_operand:SF 2 "s_register_operand" "") - (match_operand:SF 3 "nonmemory_operand" "")))] + (match_operand:SF 3 "arm_float_add_operand" "")))] "TARGET_32BIT && TARGET_HARD_FLOAT" " { enum rtx_code code = GET_CODE (operands[1]); rtx ccreg; - if (code == UNEQ || code == LTGT) - FAIL; + if (!arm_validize_comparison (&operands[1], &XEXP (operands[1], 0), + &XEXP (operands[1], 1))) + FAIL; - /* When compiling for SOFT_FLOAT, ensure both arms are in registers. - Otherwise, ensure it is a valid FP add operand */ - if ((!(TARGET_HARD_FLOAT && TARGET_FPA)) - || (!arm_float_add_operand (operands[3], SFmode))) - operands[3] = force_reg (SFmode, operands[3]); - + code = GET_CODE (operands[1]); ccreg = arm_gen_compare_reg (code, XEXP (operands[1], 0), XEXP (operands[1], 1), NULL_RTX); operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); @@ -8235,9 +8195,10 @@ enum rtx_code code = GET_CODE (operands[1]); rtx ccreg; - if (code == UNEQ || code == LTGT) - FAIL; - + if (!arm_validize_comparison (&operands[1], &XEXP (operands[1], 0), + &XEXP (operands[1], 1))) + FAIL; + code = GET_CODE (operands[1]); ccreg = arm_gen_compare_reg (code, XEXP (operands[1], 0), XEXP (operands[1], 1), NULL_RTX); operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);