diff options
author | Paolo Bonzini <bonzini@gnu.org> | 2009-04-09 10:57:03 +0000 |
---|---|---|
committer | Paolo Bonzini <bonzini@gcc.gnu.org> | 2009-04-09 10:57:03 +0000 |
commit | 4a77c72b6b82fe31fa897ef5ced8579b706c9dfc (patch) | |
tree | ece9481c78c8bf125765823a7704da2edc3e28dd /gcc/optabs.c | |
parent | bf080c96e02d9b10dd18d7e900ed0c84d0d214af (diff) | |
download | gcc-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.c | 170 |
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; } |