summaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorrearnsha <rearnsha@138bc75d-0d04-0410-961f-82ee72b054a4>2006-11-14 23:25:43 +0000
committerrearnsha <rearnsha@138bc75d-0d04-0410-961f-82ee72b054a4>2006-11-14 23:25:43 +0000
commit595d88b592402d3f629fa77662f81ea572a8a1bf (patch)
tree07b49d656bca875286894404e9122b058e2a2a0e /gcc/expmed.c
parentae0788d3e71731902b1b55ee6af8a6e767443a4e (diff)
downloadgcc-595d88b592402d3f629fa77662f81ea572a8a1bf.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@118829 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c193
1 files changed, 130 insertions, 63 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 6a0d3532ca7..4008c08d223 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;
}
}