diff options
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 2 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 192 | ||||
-rw-r--r-- | gcc/expmed.c | 193 | ||||
-rw-r--r-- | gcc/expr.c | 32 |
5 files changed, 350 insertions, 82 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8e2c89c..81f3434 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2006-11-14 Richard Earnshaw <rearnsha@arm.com> + + * expmed.c (emit_store_flag_1): New function. + (emit_store_flag): Call it. If we can't find a suitable scc insn, + try a cstore insn. + * expr.c (do_store_flag): If we can't find a scc insn, try cstore. + Use do_compare_rtx_and_jump. + * arm.h (BRANCH_COST): Increase to 2 on Thumb. + * arm.md (cstoresi4): New define_expand. + (cstoresi_eq0_thumb, cstoresi_ne0_thumb): Likewise. + (cstoresi_eq0_thumb_insn, cstore_ne0_thumb_insn): New patterns. + (cstoresi_nltu_thumb, thumb_addsi3_addgeu): New patterns. + 2006-11-14 Caroline Tice <ctice@apple.com> * dwarf2out.c (debug_pubtypes_section): New static global variable. diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 73d8333..5570924 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -2091,7 +2091,7 @@ do { \ /* Try to generate sequences that don't involve branches, we can then use conditional instructions */ #define BRANCH_COST \ - (TARGET_ARM ? 4 : (optimize > 1 ? 1 : 0)) + (TARGET_ARM ? 4 : (optimize > 0 ? 2 : 0)) /* Position Independent Code. */ /* We decide which register to use based on the compilation options and diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index b28e3d0..b2e3c7e 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -7460,6 +7460,198 @@ (set_attr "length" "8")] ) +(define_expand "cstoresi4" + [(set (match_operand:SI 0 "s_register_operand" "") + (match_operator:SI 1 "arm_comparison_operator" + [(match_operand:SI 2 "s_register_operand" "") + (match_operand:SI 3 "reg_or_int_operand" "")]))] + "TARGET_THUMB" + "{ + rtx op3, scratch, scratch2; + + if (operands[3] == const0_rtx) + { + switch (GET_CODE (operands[1])) + { + case EQ: + emit_insn (gen_cstoresi_eq0_thumb (operands[0], operands[2])); + break; + + case NE: + emit_insn (gen_cstoresi_ne0_thumb (operands[0], operands[2])); + break; + + case LE: + scratch = expand_binop (SImode, add_optab, operands[2], constm1_rtx, + NULL_RTX, 0, OPTAB_WIDEN); + scratch = expand_binop (SImode, ior_optab, operands[2], scratch, + NULL_RTX, 0, OPTAB_WIDEN); + expand_binop (SImode, lshr_optab, scratch, GEN_INT (31), + operands[0], 1, OPTAB_WIDEN); + break; + + case GE: + scratch = expand_unop (SImode, one_cmpl_optab, operands[2], + NULL_RTX, 1); + expand_binop (SImode, lshr_optab, scratch, GEN_INT (31), + NULL_RTX, 1, OPTAB_WIDEN); + break; + + case GT: + scratch = expand_binop (SImode, ashr_optab, operands[2], + GEN_INT (31), NULL_RTX, 0, OPTAB_WIDEN); + scratch = expand_binop (SImode, sub_optab, scratch, operands[2], + NULL_RTX, 0, OPTAB_WIDEN); + expand_binop (SImode, lshr_optab, scratch, GEN_INT (31), operands[0], + 0, OPTAB_WIDEN); + break; + + /* LT is handled by generic code. No need for unsigned with 0. */ + default: + FAIL; + } + DONE; + } + + switch (GET_CODE (operands[1])) + { + case EQ: + scratch = expand_binop (SImode, sub_optab, operands[2], operands[3], + NULL_RTX, 0, OPTAB_WIDEN); + emit_insn (gen_cstoresi_eq0_thumb (operands[0], scratch)); + break; + + case NE: + scratch = expand_binop (SImode, sub_optab, operands[2], operands[3], + NULL_RTX, 0, OPTAB_WIDEN); + emit_insn (gen_cstoresi_ne0_thumb (operands[0], scratch)); + break; + + case LE: + op3 = force_reg (SImode, operands[3]); + + scratch = expand_binop (SImode, lshr_optab, operands[2], GEN_INT (31), + NULL_RTX, 1, OPTAB_WIDEN); + scratch2 = expand_binop (SImode, ashr_optab, op3, GEN_INT (31), + NULL_RTX, 0, OPTAB_WIDEN); + emit_insn (gen_thumb_addsi3_addgeu (operands[0], scratch, scratch2, + op3, operands[2])); + break; + + case GE: + op3 = operands[3]; + if (!thumb_cmp_operand (op3, SImode)) + op3 = force_reg (SImode, op3); + scratch = expand_binop (SImode, ashr_optab, operands[2], GEN_INT (31), + NULL_RTX, 0, OPTAB_WIDEN); + scratch2 = expand_binop (SImode, lshr_optab, op3, GEN_INT (31), + NULL_RTX, 1, OPTAB_WIDEN); + emit_insn (gen_thumb_addsi3_addgeu (operands[0], scratch, scratch2, + operands[2], op3)); + break; + + case LEU: + op3 = force_reg (SImode, operands[3]); + scratch = force_reg (SImode, const0_rtx); + emit_insn (gen_thumb_addsi3_addgeu (operands[0], scratch, scratch, + op3, operands[2])); + break; + + case GEU: + op3 = operands[3]; + if (!thumb_cmp_operand (op3, SImode)) + op3 = force_reg (SImode, op3); + scratch = force_reg (SImode, const0_rtx); + emit_insn (gen_thumb_addsi3_addgeu (operands[0], scratch, scratch, + operands[2], op3)); + break; + + case LTU: + op3 = operands[3]; + if (!thumb_cmp_operand (op3, SImode)) + op3 = force_reg (SImode, op3); + scratch = gen_reg_rtx (SImode); + emit_insn (gen_cstoresi_nltu_thumb (scratch, operands[2], op3)); + emit_insn (gen_negsi2 (operands[0], scratch)); + break; + + case GTU: + op3 = force_reg (SImode, operands[3]); + scratch = gen_reg_rtx (SImode); + emit_insn (gen_cstoresi_nltu_thumb (scratch, op3, operands[2])); + emit_insn (gen_negsi2 (operands[0], scratch)); + break; + + /* No good sequences for GT, LT. */ + default: + FAIL; + } + DONE; +}") + +(define_expand "cstoresi_eq0_thumb" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (eq:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0))) + (clobber (match_dup:SI 2))])] + "TARGET_THUMB" + "operands[2] = gen_reg_rtx (SImode);" +) + +(define_expand "cstoresi_ne0_thumb" + [(parallel + [(set (match_operand:SI 0 "s_register_operand" "") + (ne:SI (match_operand:SI 1 "s_register_operand" "") + (const_int 0))) + (clobber (match_dup:SI 2))])] + "TARGET_THUMB" + "operands[2] = gen_reg_rtx (SImode);" +) + +(define_insn "*cstoresi_eq0_thumb_insn" + [(set (match_operand:SI 0 "s_register_operand" "=&l,l") + (eq:SI (match_operand:SI 1 "s_register_operand" "l,0") + (const_int 0))) + (clobber (match_operand:SI 2 "s_register_operand" "=X,l"))] + "TARGET_THUMB" + "@ + neg\\t%0, %1\;adc\\t%0, %0, %1 + neg\\t%2, %1\;adc\\t%0, %1, %2" + [(set_attr "length" "4")] +) + +(define_insn "*cstoresi_ne0_thumb_insn" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (ne:SI (match_operand:SI 1 "s_register_operand" "0") + (const_int 0))) + (clobber (match_operand:SI 2 "s_register_operand" "=l"))] + "TARGET_THUMB" + "sub\\t%2, %1, #1\;sbc\\t%0, %1, %2" + [(set_attr "length" "4")] +) + +(define_insn "cstoresi_nltu_thumb" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (neg:SI (gtu:SI (match_operand:SI 1 "s_register_operand" "l,*h") + (match_operand:SI 2 "thumb_cmp_operand" "lI*h,*r"))))] + "TARGET_THUMB" + "cmp\\t%1, %2\;sbc\\t%0, %0, %0" + [(set_attr "length" "4")] +) + +;; Used as part of the expansion of thumb les sequence. +(define_insn "thumb_addsi3_addgeu" + [(set (match_operand:SI 0 "s_register_operand" "=l") + (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") + (match_operand:SI 2 "s_register_operand" "l")) + (geu:SI (match_operand:SI 3 "s_register_operand" "l") + (match_operand:SI 4 "thumb_cmp_operand" "lI"))))] + "TARGET_THUMB" + "cmp\\t%3, %4\;adc\\t%0, %1, %2" + [(set_attr "length" "4")] +) + ;; Conditional move insns diff --git a/gcc/expmed.c b/gcc/expmed.c index 6a0d353..4008c08 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -5091,6 +5091,77 @@ expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target) return target; } +/* Helper function for emit_store_flag. */ +static rtx +emit_store_flag_1 (rtx target, rtx subtarget, enum machine_mode mode, + int normalizep) +{ + rtx op0; + enum machine_mode target_mode = GET_MODE (target); + + /* If we are converting to a wider mode, first convert to + TARGET_MODE, then normalize. This produces better combining + opportunities on machines that have a SIGN_EXTRACT when we are + testing a single bit. This mostly benefits the 68k. + + If STORE_FLAG_VALUE does not have the sign bit set when + interpreted in MODE, we can do this conversion as unsigned, which + is usually more efficient. */ + if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (mode)) + { + convert_move (target, subtarget, + (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + && 0 == (STORE_FLAG_VALUE + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) -1)))); + op0 = target; + mode = target_mode; + } + else + op0 = subtarget; + + /* If we want to keep subexpressions around, don't reuse our last + target. */ + if (optimize) + subtarget = 0; + + /* Now normalize to the proper value in MODE. Sometimes we don't + have to do anything. */ + if (normalizep == 0 || normalizep == STORE_FLAG_VALUE) + ; + /* STORE_FLAG_VALUE might be the most negative number, so write + the comparison this way to avoid a compiler-time warning. */ + else if (- normalizep == STORE_FLAG_VALUE) + op0 = expand_unop (mode, neg_optab, op0, subtarget, 0); + + /* We don't want to use STORE_FLAG_VALUE < 0 below since this makes + it hard to use a value of just the sign bit due to ANSI integer + constant typing rules. */ + else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (STORE_FLAG_VALUE + & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))) + op0 = expand_shift (RSHIFT_EXPR, mode, op0, + size_int (GET_MODE_BITSIZE (mode) - 1), subtarget, + normalizep == 1); + else + { + gcc_assert (STORE_FLAG_VALUE & 1); + + op0 = expand_and (mode, op0, const1_rtx, subtarget); + if (normalizep == -1) + op0 = expand_unop (mode, neg_optab, op0, op0, 0); + } + + /* If we were converting to a smaller mode, do the conversion now. */ + if (target_mode != mode) + { + convert_move (target, op0, 0); + return target; + } + else + return op0; +} + /* Emit a store-flags instruction for comparison CODE on OP0 and OP1 and storing in TARGET. Normally return TARGET. Return 0 if that cannot be done. @@ -5180,12 +5251,14 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, { rtx op00, op01, op0both; - /* Do a logical OR or AND of the two words and compare the result. */ + /* Do a logical OR or AND of the two words and compare the + result. */ op00 = simplify_gen_subreg (word_mode, op0, mode, 0); op01 = simplify_gen_subreg (word_mode, op0, mode, UNITS_PER_WORD); op0both = expand_binop (word_mode, op1 == const0_rtx ? ior_optab : and_optab, - op00, op01, NULL_RTX, unsignedp, OPTAB_DIRECT); + op00, op01, NULL_RTX, unsignedp, + OPTAB_DIRECT); if (op0both != 0) return emit_store_flag (target, code, op0both, op1, word_mode, @@ -5197,15 +5270,13 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, /* If testing the sign bit, can just test on high word. */ op0h = simplify_gen_subreg (word_mode, op0, mode, - subreg_highpart_offset (word_mode, mode)); + subreg_highpart_offset (word_mode, + mode)); return emit_store_flag (target, code, op0h, op1, word_mode, unsignedp, normalizep); } } - /* From now on, we won't change CODE, so set ICODE now. */ - icode = setcc_gen_code[(int) code]; - /* If this is A < 0 or A >= 0, we can do this by taking the ones complement of A (for GE) and shifting the sign bit to the low bit. */ if (op1 == const0_rtx && (code == LT || code == GE) @@ -5213,7 +5284,8 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, && (normalizep || STORE_FLAG_VALUE == 1 || (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) - == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))))) + == ((unsigned HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) - 1)))))) { subtarget = target; @@ -5248,6 +5320,8 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, return op0; } + icode = setcc_gen_code[(int) code]; + if (icode != CODE_FOR_nothing) { insn_operand_predicate_fn pred; @@ -5305,72 +5379,65 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, if (pattern) { emit_insn (pattern); + return emit_store_flag_1 (target, subtarget, compare_mode, + normalizep); + } + } + else + { + /* We don't have an scc insn, so try a cstore insn. */ + + for (compare_mode = mode; compare_mode != VOIDmode; + compare_mode = GET_MODE_WIDER_MODE (compare_mode)) + { + icode = cstore_optab->handlers[(int) compare_mode].insn_code; + if (icode != CODE_FOR_nothing) + break; + } + + if (icode != CODE_FOR_nothing) + { + enum machine_mode result_mode + = insn_data[(int) icode].operand[0].mode; + rtx cstore_op0 = op0; + rtx cstore_op1 = op1; - /* If we are converting to a wider mode, first convert to - TARGET_MODE, then normalize. This produces better combining - opportunities on machines that have a SIGN_EXTRACT when we are - testing a single bit. This mostly benefits the 68k. + do_pending_stack_adjust (); + last = get_last_insn (); - If STORE_FLAG_VALUE does not have the sign bit set when - interpreted in COMPARE_MODE, we can do this conversion as - unsigned, which is usually more efficient. */ - if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (compare_mode)) + if (compare_mode != mode) { - convert_move (target, subtarget, - (GET_MODE_BITSIZE (compare_mode) - <= HOST_BITS_PER_WIDE_INT) - && 0 == (STORE_FLAG_VALUE - & ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (compare_mode) -1)))); - op0 = target; - compare_mode = target_mode; + cstore_op0 = convert_modes (compare_mode, mode, cstore_op0, + unsignedp); + cstore_op1 = convert_modes (compare_mode, mode, cstore_op1, + unsignedp); } - else - op0 = subtarget; + + if (!insn_data[(int) icode].operand[2].predicate (cstore_op0, + compare_mode)) + cstore_op0 = copy_to_mode_reg (compare_mode, cstore_op0); - /* If we want to keep subexpressions around, don't reuse our - last target. */ + if (!insn_data[(int) icode].operand[3].predicate (cstore_op1, + compare_mode)) + cstore_op1 = copy_to_mode_reg (compare_mode, cstore_op1); - if (optimize) - subtarget = 0; + comparison = gen_rtx_fmt_ee (code, result_mode, cstore_op0, + cstore_op1); + subtarget = target; - /* Now normalize to the proper value in COMPARE_MODE. Sometimes - we don't have to do anything. */ - if (normalizep == 0 || normalizep == STORE_FLAG_VALUE) - ; - /* STORE_FLAG_VALUE might be the most negative number, so write - the comparison this way to avoid a compiler-time warning. */ - else if (- normalizep == STORE_FLAG_VALUE) - op0 = expand_unop (compare_mode, neg_optab, op0, subtarget, 0); - - /* We don't want to use STORE_FLAG_VALUE < 0 below since this - makes it hard to use a value of just the sign bit due to - ANSI integer constant typing rules. */ - else if (GET_MODE_BITSIZE (compare_mode) <= HOST_BITS_PER_WIDE_INT - && (STORE_FLAG_VALUE - & ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (compare_mode) - 1)))) - op0 = expand_shift (RSHIFT_EXPR, compare_mode, op0, - size_int (GET_MODE_BITSIZE (compare_mode) - 1), - subtarget, normalizep == 1); - else - { - gcc_assert (STORE_FLAG_VALUE & 1); - - op0 = expand_and (compare_mode, op0, const1_rtx, subtarget); - if (normalizep == -1) - op0 = expand_unop (compare_mode, neg_optab, op0, op0, 0); - } + if (optimize || !(insn_data[(int) icode].operand[0].predicate + (subtarget, result_mode))) + subtarget = gen_reg_rtx (result_mode); - /* If we were converting to a smaller mode, do the - conversion now. */ - if (target_mode != compare_mode) + pattern = GEN_FCN (icode) (subtarget, comparison, cstore_op0, + cstore_op1); + + if (pattern) { - convert_move (target, op0, 0); - return target; + emit_insn (pattern); + return emit_store_flag_1 (target, subtarget, result_mode, + normalizep); } - else - return op0; } } @@ -9155,6 +9155,17 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap) return 0; icode = setcc_gen_code[(int) code]; + + if (icode == CODE_FOR_nothing) + { + enum machine_mode wmode; + + for (wmode = operand_mode; + icode == CODE_FOR_nothing && wmode != VOIDmode; + wmode = GET_MODE_WIDER_MODE (wmode)) + icode = cstore_optab->handlers[(int) wmode].insn_code; + } + if (icode == CODE_FOR_nothing || (only_cheap && insn_data[(int) icode].operand[0].mode != mode)) { @@ -9200,25 +9211,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap) target = gen_reg_rtx (GET_MODE (target)); emit_move_insn (target, invert ? const0_rtx : const1_rtx); - result = compare_from_rtx (op0, op1, code, unsignedp, - operand_mode, NULL_RTX); - if (GET_CODE (result) == CONST_INT) - return (((result == const0_rtx && ! invert) - || (result != const0_rtx && invert)) - ? const0_rtx : const1_rtx); - - /* The code of RESULT may not match CODE if compare_from_rtx - decided to swap its operands and reverse the original code. - - We know that compare_from_rtx returns either a CONST_INT or - a new comparison code, so it is safe to just extract the - code from RESULT. */ - code = GET_CODE (result); - label = gen_label_rtx (); - gcc_assert (bcc_gen_fctn[(int) code]); - - emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label)); + do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX, + NULL_RTX, label); + emit_move_insn (target, invert ? const1_rtx : const0_rtx); emit_label (label); |