aboutsummaryrefslogtreecommitdiff
path: root/gcc/optabs.c
diff options
context:
space:
mode:
authorPaolo Bonzini <bonzini@gnu.org>2009-04-09 10:57:03 +0000
committerPaolo Bonzini <bonzini@gcc.gnu.org>2009-04-09 10:57:03 +0000
commit4a77c72b6b82fe31fa897ef5ced8579b706c9dfc (patch)
treeece9481c78c8bf125765823a7704da2edc3e28dd /gcc/optabs.c
parentbf080c96e02d9b10dd18d7e900ed0c84d0d214af (diff)
downloadgcc-4a77c72b6b82fe31fa897ef5ced8579b706c9dfc.zip
gcc-4a77c72b6b82fe31fa897ef5ced8579b706c9dfc.tar.gz
gcc-4a77c72b6b82fe31fa897ef5ced8579b706c9dfc.tar.bz2
i386.md (cmpcc): New.
2009-04-09 Paolo Bonzini <bonzini@gnu.org> * config/i386/i386.md (cmpcc): New. * config/i386/sync.md (sync_compare_and_swap*): Set FLAGS_REG. (sync_compare_and_swap_cc*): Delete. * config/s390/s390.c (s390_compare_emitted): Remove. (s390_emit_compare): Handle MODE_CC s390_compare_op0 like s390_compare_emitted used to be handled. Assert that modes match. (s390_emit_compare_and_swap): Use s390_emit_compare, do not refer to sync_compare_and_swap_ccsi. * config/s390/s390.h (s390_compare_emitted): Remove. * config/s390/s390.md (seq): Look for MODE_CC s390_compare_op0 instead of s390_compare_emitted. (stack_protect_test, sync_compare_and_swap_cc): Set s390_compare_op0 instead of s390_compare_emitted. * config/s390/s390.md (cmpcc): New. (sync_compare_and_swapqi, sync_compare_and_swaphi): Clobber CC_REGNUM, do not pretend it's set. (sync_compare_and_swap_cc*): Delete. * config/s390/predicates.md (cc_reg_operand): New. * expr.c (sync_compare_and_swap_cc): Delete. * optabs.h (sync_compare_and_swap_cc): Delete. * optabs.c (prepare_cmp_insn): Ignore which specific CCmode is being used with can_compare_p. (emit_cmp_and_jump_insn_1): Likewise when looking in the optab. (find_cc_set): New. (expand_bool_compare_and_swap): Do not use sync_compare_and_swap_cc, look for a MODE_CC set instead. Use emit_store_flag. (expand_compare_and_swap_loop): Likewise, with some additional complication to avoid a force_reg when useless. Use emit_cmp_and_jump_insns. * genopinit.c (optabs): Delete sync_compare_and_swap_cc. * doc/md.texi (sync_compare_and_swap_cc): Merge with sync_compare_and_swap documentation. java: 2009-04-09 Paolo Bonzini <bonzini@gnu.org> * builtins.c (compareAndSwapLong_builtin, compareAndSwapInt_builtin, compareAndSwapObject_builtin, VMSupportsCS8_builtin): Do not look at sync_compare_and_swap_cc. From-SVN: r145825
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r--gcc/optabs.c170
1 files changed, 73 insertions, 97 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 7057d9f..058cebe 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -4143,11 +4143,15 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
*px = x;
*py = y;
- if (can_compare_p (*pcomparison, mode, purpose))
+ if (GET_MODE_CLASS (mode) == MODE_CC)
+ {
+ gcc_assert (can_compare_p (*pcomparison, CCmode, purpose));
+ return;
+ }
+ else if (can_compare_p (*pcomparison, mode, purpose))
return;
/* Handle a lib call just for the mode we are using. */
-
libfunc = optab_libfunc (cmp_optab, mode);
if (libfunc && !SCALAR_FLOAT_MODE_P (mode))
{
@@ -4231,12 +4235,13 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
/* Try combined insns first. */
do
{
+ enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : wider_mode;
enum insn_code icode;
PUT_MODE (test, wider_mode);
if (label)
{
- icode = optab_handler (cbranch_optab, wider_mode)->insn_code;
+ icode = optab_handler (cbranch_optab, optab_mode)->insn_code;
if (icode != CODE_FOR_nothing
&& insn_data[icode].operand[0].predicate (test, wider_mode))
@@ -4249,7 +4254,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
}
/* Handle some compares against zero. */
- icode = (int) optab_handler (tst_optab, wider_mode)->insn_code;
+ icode = (int) optab_handler (tst_optab, optab_mode)->insn_code;
if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
{
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
@@ -4261,7 +4266,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
/* Handle compares for which there is a directly suitable insn. */
- icode = (int) optab_handler (cmp_optab, wider_mode)->insn_code;
+ icode = (int) optab_handler (cmp_optab, optab_mode)->insn_code;
if (icode != CODE_FOR_nothing)
{
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
@@ -6399,7 +6404,6 @@ init_optabs (void)
sync_new_xor_optab[i] = CODE_FOR_nothing;
sync_new_nand_optab[i] = CODE_FOR_nothing;
sync_compare_and_swap[i] = CODE_FOR_nothing;
- sync_compare_and_swap_cc[i] = CODE_FOR_nothing;
sync_lock_test_and_set[i] = CODE_FOR_nothing;
sync_lock_release[i] = CODE_FOR_nothing;
@@ -6970,6 +6974,21 @@ expand_val_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode);
}
+/* Helper function to find the MODE_CC set in a sync_compare_and_swap
+ pattern. */
+
+static void
+find_cc_set (rtx x, const_rtx pat, void *data)
+{
+ if (REG_P (x) && GET_MODE_CLASS (GET_MODE (x)) == MODE_CC
+ && GET_CODE (pat) == SET)
+ {
+ rtx *p_cc_reg = (rtx *) data;
+ gcc_assert (!*p_cc_reg);
+ *p_cc_reg = x;
+ }
+}
+
/* Expand a compare-and-swap operation and store true into the result if
the operation was successful and false otherwise. Return the result.
Unlike other routines, TARGET is not optional. */
@@ -6979,84 +6998,46 @@ expand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
{
enum machine_mode mode = GET_MODE (mem);
enum insn_code icode;
- rtx subtarget, label0, label1;
+ rtx subtarget, seq, cc_reg;
/* If the target supports a compare-and-swap pattern that simultaneously
sets some flag for success, then use it. Otherwise use the regular
compare-and-swap and follow that immediately with a compare insn. */
- icode = sync_compare_and_swap_cc[mode];
- switch (icode)
- {
- default:
- subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
- NULL_RTX, icode);
- if (subtarget != NULL_RTX)
- break;
-
- /* FALLTHRU */
- case CODE_FOR_nothing:
- icode = sync_compare_and_swap[mode];
- if (icode == CODE_FOR_nothing)
- return NULL_RTX;
-
- /* Ensure that if old_val == mem, that we're not comparing
- against an old value. */
- if (MEM_P (old_val))
- old_val = force_reg (mode, old_val);
+ icode = sync_compare_and_swap[mode];
+ if (icode == CODE_FOR_nothing)
+ return NULL_RTX;
+ do
+ {
+ start_sequence ();
subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
- NULL_RTX, icode);
+ NULL_RTX, icode);
+ cc_reg = NULL_RTX;
if (subtarget == NULL_RTX)
- return NULL_RTX;
-
- emit_cmp_insn (subtarget, old_val, EQ, const0_rtx, mode, true);
- }
-
- /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a
- setcc instruction from the beginning. We don't work too hard here,
- but it's nice to not be stupid about initial code gen either. */
- if (STORE_FLAG_VALUE == 1)
- {
- icode = setcc_gen_code[EQ];
- if (icode != CODE_FOR_nothing)
{
- enum machine_mode cmode = insn_data[icode].operand[0].mode;
- rtx insn;
-
- subtarget = target;
- if (!insn_data[icode].operand[0].predicate (target, cmode))
- subtarget = gen_reg_rtx (cmode);
-
- insn = GEN_FCN (icode) (subtarget);
- if (insn)
- {
- emit_insn (insn);
- if (GET_MODE (target) != GET_MODE (subtarget))
- {
- convert_move (target, subtarget, 1);
- subtarget = target;
- }
- return subtarget;
- }
+ end_sequence ();
+ return NULL_RTX;
}
- }
-
- /* Without an appropriate setcc instruction, use a set of branches to
- get 1 and 0 stored into target. Presumably if the target has a
- STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt. */
- label0 = gen_label_rtx ();
- label1 = gen_label_rtx ();
+ if (have_insn_for (COMPARE, CCmode))
+ note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg);
+ seq = get_insns ();
+ end_sequence ();
- emit_jump_insn (bcc_gen_fctn[EQ] (label0));
- emit_move_insn (target, const0_rtx);
- emit_jump_insn (gen_jump (label1));
- emit_barrier ();
- emit_label (label0);
- emit_move_insn (target, const1_rtx);
- emit_label (label1);
+ /* We might be comparing against an old value. Try again. :-( */
+ if (!cc_reg && MEM_P (old_val))
+ {
+ seq = NULL_RTX;
+ old_val = force_reg (mode, old_val);
+ }
+ }
+ while (!seq);
- return target;
+ emit_insn (seq);
+ if (cc_reg)
+ return emit_store_flag (target, EQ, cc_reg, const0_rtx, VOIDmode, 0, 1);
+ else
+ return emit_store_flag (target, EQ, subtarget, old_val, VOIDmode, 1, 1);
}
/* This is a helper function for the other atomic operations. This function
@@ -7073,7 +7054,7 @@ expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
{
enum machine_mode mode = GET_MODE (mem);
enum insn_code icode;
- rtx label, cmp_reg, subtarget;
+ rtx label, cmp_reg, subtarget, cc_reg;
/* The loop we want to generate looks like
@@ -7100,37 +7081,32 @@ expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
/* If the target supports a compare-and-swap pattern that simultaneously
sets some flag for success, then use it. Otherwise use the regular
compare-and-swap and follow that immediately with a compare insn. */
- icode = sync_compare_and_swap_cc[mode];
- switch (icode)
- {
- default:
- subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
- cmp_reg, icode);
- if (subtarget != NULL_RTX)
- {
- gcc_assert (subtarget == cmp_reg);
- break;
- }
+ icode = sync_compare_and_swap[mode];
+ if (icode == CODE_FOR_nothing)
+ return false;
- /* FALLTHRU */
- case CODE_FOR_nothing:
- icode = sync_compare_and_swap[mode];
- if (icode == CODE_FOR_nothing)
- return false;
+ subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
+ cmp_reg, icode);
+ if (subtarget == NULL_RTX)
+ return false;
- subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
- cmp_reg, icode);
- if (subtarget == NULL_RTX)
- return false;
+ cc_reg = NULL_RTX;
+ if (have_insn_for (COMPARE, CCmode))
+ note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg);
+ if (cc_reg)
+ {
+ cmp_reg = cc_reg;
+ old_reg = const0_rtx;
+ }
+ else
+ {
if (subtarget != cmp_reg)
emit_move_insn (cmp_reg, subtarget);
-
- emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
}
/* ??? Mark this jump predicted not taken? */
- emit_jump_insn (bcc_gen_fctn[NE] (label));
-
+ emit_cmp_and_jump_insns (cmp_reg, old_reg, NE, const0_rtx, GET_MODE (cmp_reg), 1,
+ label);
return true;
}