aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2006-11-14 23:25:43 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2006-11-14 23:25:43 +0000
commita41a56b62d0638791b57ee160dd16fe144e2b49b (patch)
tree07b49d656bca875286894404e9122b058e2a2a0e
parent75dc0b383db8e50ab0c11ac25b09f3538106a3f0 (diff)
downloadgcc-a41a56b62d0638791b57ee160dd16fe144e2b49b.zip
gcc-a41a56b62d0638791b57ee160dd16fe144e2b49b.tar.gz
gcc-a41a56b62d0638791b57ee160dd16fe144e2b49b.tar.bz2
expmed.c (emit_store_flag_1): New function.
* 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. From-SVN: r118829
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/arm/arm.h2
-rw-r--r--gcc/config/arm/arm.md192
-rw-r--r--gcc/expmed.c193
-rw-r--r--gcc/expr.c32
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;
}
}
diff --git a/gcc/expr.c b/gcc/expr.c
index dc5f844..7462788 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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);