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
This commit is contained in:
Paolo Bonzini 2009-04-09 10:57:03 +00:00 committed by Paolo Bonzini
parent bf080c96e0
commit 4a77c72b6b
14 changed files with 192 additions and 278 deletions

View file

@ -1,3 +1,40 @@
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.
2009-04-09 Jan Hubicka <jh@suse.cz> 2009-04-09 Jan Hubicka <jh@suse.cz>
* except.c (find_prev_try): Break out from .... * except.c (find_prev_try): Break out from ....

View file

@ -1083,6 +1083,17 @@
DONE; DONE;
}) })
(define_expand "cmpcc"
[(set (reg:CC FLAGS_REG)
(compare:CC (match_operand 0 "flags_reg_operand" "")
(match_operand 1 "general_operand" "")))]
""
{
ix86_compare_op0 = operands[0];
ix86_compare_op1 = operands[1];
DONE;
})
;; FP compares, step 1: ;; FP compares, step 1:
;; Set the FP condition codes. ;; Set the FP condition codes.
;; ;;

View file

@ -70,7 +70,11 @@
(match_operand:CASMODE 2 "register_operand" "") (match_operand:CASMODE 2 "register_operand" "")
(match_operand:CASMODE 3 "register_operand" "")] (match_operand:CASMODE 3 "register_operand" "")]
UNSPECV_CMPXCHG)) UNSPECV_CMPXCHG))
(clobber (reg:CC FLAGS_REG))])] (set (reg:CCZ FLAGS_REG)
(compare:CCZ
(unspec_volatile:CASMODE
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
(match_dup 2)))])]
"TARGET_CMPXCHG" "TARGET_CMPXCHG"
{ {
if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode) if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
@ -109,7 +113,11 @@
(match_operand:IMODE 2 "register_operand" "a") (match_operand:IMODE 2 "register_operand" "a")
(match_operand:IMODE 3 "register_operand" "<modeconstraint>")] (match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
UNSPECV_CMPXCHG)) UNSPECV_CMPXCHG))
(clobber (reg:CC FLAGS_REG))] (set (reg:CCZ FLAGS_REG)
(compare:CCZ
(unspec_volatile:IMODE
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
(match_dup 2)))]
"TARGET_CMPXCHG" "TARGET_CMPXCHG"
"lock{%;| }cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}") "lock{%;| }cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
@ -123,7 +131,12 @@
(match_operand:<DCASHMODE> 3 "register_operand" "b") (match_operand:<DCASHMODE> 3 "register_operand" "b")
(match_operand:<DCASHMODE> 4 "register_operand" "c")] (match_operand:<DCASHMODE> 4 "register_operand" "c")]
UNSPECV_CMPXCHG)) UNSPECV_CMPXCHG))
(clobber (reg:CC FLAGS_REG))] (set (reg:CCZ FLAGS_REG)
(compare:CCZ
(unspec_volatile:DCASMODE
[(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
UNSPECV_CMPXCHG)
(match_dup 2)))]
"" ""
"lock{%;| }cmpxchg<doublemodesuffix>b\t%1") "lock{%;| }cmpxchg<doublemodesuffix>b\t%1")
@ -137,105 +150,6 @@
;; just enumerate all regs possible here, which (as this is !TARGET_64BIT) ;; just enumerate all regs possible here, which (as this is !TARGET_64BIT)
;; are just esi and edi. ;; are just esi and edi.
(define_insn "*sync_double_compare_and_swapdi_pic" (define_insn "*sync_double_compare_and_swapdi_pic"
[(set (match_operand:DI 0 "register_operand" "=A")
(match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m"))
(set (match_dup 1)
(unspec_volatile:DI
[(match_dup 1)
(match_operand:DI 2 "register_operand" "A")
(match_operand:SI 3 "register_operand" "SD")
(match_operand:SI 4 "register_operand" "c")]
UNSPECV_CMPXCHG))
(clobber (reg:CC FLAGS_REG))]
"!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic"
"xchg{l}\t%%ebx, %3\;lock{%;| }cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3")
(define_expand "sync_compare_and_swap_cc<mode>"
[(parallel
[(set (match_operand:CASMODE 0 "register_operand" "")
(match_operand:CASMODE 1 "memory_operand" ""))
(set (match_dup 1)
(unspec_volatile:CASMODE
[(match_dup 1)
(match_operand:CASMODE 2 "register_operand" "")
(match_operand:CASMODE 3 "register_operand" "")]
UNSPECV_CMPXCHG))
(set (match_dup 4)
(compare:CCZ
(unspec_volatile:CASMODE
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
(match_dup 2)))])]
"TARGET_CMPXCHG"
{
operands[4] = gen_rtx_REG (CCZmode, FLAGS_REG);
ix86_compare_op0 = operands[4];
ix86_compare_op1 = const0_rtx;
if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
{
enum machine_mode hmode = <MODE>mode == DImode ? SImode : DImode;
rtx low = simplify_gen_subreg (hmode, operands[3], <MODE>mode, 0);
rtx high = simplify_gen_subreg (hmode, operands[3], <MODE>mode,
GET_MODE_SIZE (hmode));
low = force_reg (hmode, low);
high = force_reg (hmode, high);
if (<MODE>mode == DImode)
{
if (flag_pic && !cmpxchg8b_pic_memory_operand (operands[1], DImode))
operands[1] = replace_equiv_address (operands[1],
force_reg (Pmode,
XEXP (operands[1],
0)));
emit_insn (gen_sync_double_compare_and_swap_ccdi
(operands[0], operands[1], operands[2], low, high));
}
else if (<MODE>mode == TImode)
emit_insn (gen_sync_double_compare_and_swap_ccti
(operands[0], operands[1], operands[2], low, high));
else
gcc_unreachable ();
DONE;
}
})
(define_insn "*sync_compare_and_swap_cc<mode>"
[(set (match_operand:IMODE 0 "register_operand" "=a")
(match_operand:IMODE 1 "memory_operand" "+m"))
(set (match_dup 1)
(unspec_volatile:IMODE
[(match_dup 1)
(match_operand:IMODE 2 "register_operand" "a")
(match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
UNSPECV_CMPXCHG))
(set (reg:CCZ FLAGS_REG)
(compare:CCZ
(unspec_volatile:IMODE
[(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG)
(match_dup 2)))]
"TARGET_CMPXCHG"
"lock{%;| }cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
(define_insn "sync_double_compare_and_swap_cc<mode>"
[(set (match_operand:DCASMODE 0 "register_operand" "=A")
(match_operand:DCASMODE 1 "memory_operand" "+m"))
(set (match_dup 1)
(unspec_volatile:DCASMODE
[(match_dup 1)
(match_operand:DCASMODE 2 "register_operand" "A")
(match_operand:<DCASHMODE> 3 "register_operand" "b")
(match_operand:<DCASHMODE> 4 "register_operand" "c")]
UNSPECV_CMPXCHG))
(set (reg:CCZ FLAGS_REG)
(compare:CCZ
(unspec_volatile:DCASMODE
[(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)]
UNSPECV_CMPXCHG)
(match_dup 2)))]
""
"lock{%;| }cmpxchg<doublemodesuffix>b\t%1")
;; See above for the explanation of using the constraint "SD" for
;; operand 3.
(define_insn "*sync_double_compare_and_swap_ccdi_pic"
[(set (match_operand:DI 0 "register_operand" "=A") [(set (match_operand:DI 0 "register_operand" "=A")
(match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m")) (match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m"))
(set (match_dup 1) (set (match_dup 1)

View file

@ -172,6 +172,11 @@
return (s390_branch_condition_mask (op) >= 0); return (s390_branch_condition_mask (op) >= 0);
}) })
;; Return true if op is the cc register.
(define_predicate "cc_reg_operand"
(and (match_code "reg")
(match_test "REGNO (op) == CC_REGNUM")))
(define_predicate "s390_signed_integer_comparison" (define_predicate "s390_signed_integer_comparison"
(match_code "eq, ne, lt, gt, le, ge") (match_code "eq, ne, lt, gt, le, ge")
{ {

View file

@ -224,13 +224,10 @@ struct processor_costs z10_cost =
extern int reload_completed; extern int reload_completed;
/* Save information from a "cmpxx" operation until the branch or scc is /* Save information from a "cmpxx" operation until the branch or scc is
emitted. */ emitted. A pair of a MODE_CC register and a const0_rtx if a compare
has been emitted already. */
rtx s390_compare_op0, s390_compare_op1; rtx s390_compare_op0, s390_compare_op1;
/* Save the result of a compare_and_swap until the branch or scc is
emitted. */
rtx s390_compare_emitted = NULL_RTX;
/* Structure used to hold the components of a S/390 memory /* Structure used to hold the components of a S/390 memory
address. A legitimate address on S/390 is of the general address. A legitimate address on S/390 is of the general
form form
@ -814,23 +811,23 @@ rtx
s390_emit_compare (enum rtx_code code, rtx op0, rtx op1) s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
{ {
enum machine_mode mode = s390_select_ccmode (code, op0, op1); enum machine_mode mode = s390_select_ccmode (code, op0, op1);
rtx ret = NULL_RTX; rtx cc;
/* Do not output a redundant compare instruction if a compare_and_swap /* Do not output a redundant compare instruction if a compare_and_swap
pattern already computed the result and the machine modes are compatible. */ pattern already computed the result and the machine modes are compatible. */
if (s390_compare_emitted if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
&& (s390_cc_modes_compatible (GET_MODE (s390_compare_emitted), mode) {
== GET_MODE (s390_compare_emitted))) gcc_assert (s390_cc_modes_compatible (GET_MODE (op0), mode)
ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx); == GET_MODE (op0));
cc = op0;
}
else else
{ {
rtx cc = gen_rtx_REG (mode, CC_REGNUM); cc = gen_rtx_REG (mode, CC_REGNUM);
emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1))); emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1)));
ret = gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);
} }
s390_compare_emitted = NULL_RTX;
return ret; return gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);
} }
/* Emit a SImode compare and swap instruction setting MEM to NEW_RTX if OLD /* Emit a SImode compare and swap instruction setting MEM to NEW_RTX if OLD
@ -841,14 +838,8 @@ s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
static rtx static rtx
s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem, rtx cmp, rtx new_rtx) s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem, rtx cmp, rtx new_rtx)
{ {
rtx ret; emit_insn (gen_sync_compare_and_swapsi (old, mem, cmp, new_rtx));
return s390_emit_compare (code, gen_rtx_REG (CCZ1mode, CC_REGNUM), const0_rtx);
emit_insn (gen_sync_compare_and_swap_ccsi (old, mem, cmp, new_rtx));
ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx);
s390_compare_emitted = NULL_RTX;
return ret;
} }
/* Emit a jump instruction to TARGET. If COND is NULL_RTX, emit an /* Emit a jump instruction to TARGET. If COND is NULL_RTX, emit an

View file

@ -817,7 +817,7 @@ do { \
/* Define the information needed to generate branch and scc insns. This is /* Define the information needed to generate branch and scc insns. This is
stored from the compare operation. Note that we can't use "rtx" here stored from the compare operation. Note that we can't use "rtx" here
since it hasn't been defined! */ since it hasn't been defined! */
extern struct rtx_def *s390_compare_op0, *s390_compare_op1, *s390_compare_emitted; extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
/* Relative costs of operations. */ /* Relative costs of operations. */

View file

@ -515,6 +515,16 @@
DONE; DONE;
}) })
(define_expand "cmpcc"
[(set (reg:CC CC_REGNUM)
(compare:CC (match_operand 0 "cc_reg_operand" "")
(match_operand 1 "general_operand" "")))]
""
{
s390_compare_op0 = operands[0];
s390_compare_op1 = operands[1];
DONE;
})
; Test-under-Mask instructions ; Test-under-Mask instructions
@ -5122,7 +5132,7 @@
(clobber (reg:CC CC_REGNUM))])] (clobber (reg:CC CC_REGNUM))])]
"" ""
{ {
if (!s390_compare_emitted || GET_MODE (s390_compare_emitted) != CCZ1mode) if (GET_MODE (s390_compare_op0) != CCZ1mode)
FAIL; FAIL;
operands[1] = s390_emit_compare (NE, s390_compare_op0, s390_compare_op1); operands[1] = s390_emit_compare (NE, s390_compare_op0, s390_compare_op1);
PUT_MODE (operands[1], SImode); PUT_MODE (operands[1], SImode);
@ -8242,33 +8252,11 @@
(match_operand:HQI 2 "general_operand" "") (match_operand:HQI 2 "general_operand" "")
(match_operand:HQI 3 "general_operand" "")] (match_operand:HQI 3 "general_operand" "")]
UNSPECV_CAS)) UNSPECV_CAS))
(set (reg:CCZ1 CC_REGNUM) (clobber (reg:CC CC_REGNUM))])]
(compare:CCZ1 (match_dup 1) (match_dup 2)))])]
"" ""
"s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1], "s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1],
operands[2], operands[3]); DONE;") operands[2], operands[3]); DONE;")
(define_expand "sync_compare_and_swap_cc<mode>"
[(parallel
[(set (match_operand:TDSI 0 "register_operand" "")
(match_operand:TDSI 1 "memory_operand" ""))
(set (match_dup 1)
(unspec_volatile:TDSI
[(match_dup 1)
(match_operand:TDSI 2 "register_operand" "")
(match_operand:TDSI 3 "register_operand" "")]
UNSPECV_CAS))
(set (match_dup 4)
(compare:CCZ1 (match_dup 1) (match_dup 2)))])]
""
{
/* Emulate compare. */
operands[4] = gen_rtx_REG (CCZ1mode, CC_REGNUM);
s390_compare_op0 = operands[1];
s390_compare_op1 = operands[2];
s390_compare_emitted = operands[4];
})
; cds, cdsg ; cds, cdsg
(define_insn "*sync_compare_and_swap<mode>" (define_insn "*sync_compare_and_swap<mode>"
[(set (match_operand:DP 0 "register_operand" "=r") [(set (match_operand:DP 0 "register_operand" "=r")
@ -8682,17 +8670,14 @@
= gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (),
GEN_INT (TARGET_THREAD_SSP_OFFSET))); GEN_INT (TARGET_THREAD_SSP_OFFSET)));
#endif #endif
s390_compare_op0 = operands[0];
s390_compare_op1 = operands[1];
s390_compare_emitted = gen_rtx_REG (CCZmode, CC_REGNUM);
if (TARGET_64BIT) if (TARGET_64BIT)
emit_insn (gen_stack_protect_testdi (operands[0], operands[1])); emit_insn (gen_stack_protect_testdi (operands[0], operands[1]));
else else
emit_insn (gen_stack_protect_testsi (operands[0], operands[1])); emit_insn (gen_stack_protect_testsi (operands[0], operands[1]));
s390_compare_op0 = gen_rtx_REG (CCZmode, CC_REGNUM);
s390_compare_op1 = const0_rtx;
emit_jump_insn (gen_beq (operands[2])); emit_jump_insn (gen_beq (operands[2]));
DONE; DONE;
}) })

View file

@ -5091,19 +5091,15 @@ memory operations before the atomic operation occur before the atomic
operation and all memory operations after the atomic operation occur operation and all memory operations after the atomic operation occur
after the atomic operation. after the atomic operation.
@cindex @code{sync_compare_and_swap_cc@var{mode}} instruction pattern For targets where the success or failure of the compare-and-swap
@item @samp{sync_compare_and_swap_cc@var{mode}} operation is available via the status flags, it is possible
to avoid a separate compare operation and issue the subsequent
This pattern is just like @code{sync_compare_and_swap@var{mode}}, except setcc or branch immediately after the compare-and-swap. To this
it should act as if compare part of the compare-and-swap were issued via end, GCC will look for a @code{MODE_CC} set in the output of
@code{cmp@var{m}}. This comparison will only be used with @code{EQ} and @code{sync_compare_and_swap@var{mode}}; if the machine description
@code{NE} branches and @code{setcc} operations. includes such a set, the target should also define a special @code{cmpcc}
instruction. GCC will then be able to take the destination of the
Some targets do expose the success or failure of the compare-and-swap @code{MODE_CC} set and use it as the first operand of @code{cmpcc}.
operation via the status flags. Ideally we wouldn't need a separate
named pattern in order to take advantage of this, but the combine pass
does not handle patterns with multiple sets, which is required by
definition for @code{sync_compare_and_swap@var{mode}}.
@cindex @code{sync_add@var{mode}} instruction pattern @cindex @code{sync_add@var{mode}} instruction pattern
@cindex @code{sync_sub@var{mode}} instruction pattern @cindex @code{sync_sub@var{mode}} instruction pattern

View file

@ -234,7 +234,6 @@ enum insn_code sync_new_and_optab[NUM_MACHINE_MODES];
enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES]; enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES];
enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES]; enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES]; enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES]; enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
enum insn_code sync_lock_release[NUM_MACHINE_MODES]; enum insn_code sync_lock_release[NUM_MACHINE_MODES];

View file

@ -234,7 +234,6 @@ static const char * const optabs[] =
"sync_new_xor_optab[$A] = CODE_FOR_$(sync_new_xor$I$a$)", "sync_new_xor_optab[$A] = CODE_FOR_$(sync_new_xor$I$a$)",
"sync_new_nand_optab[$A] = CODE_FOR_$(sync_new_nand$I$a$)", "sync_new_nand_optab[$A] = CODE_FOR_$(sync_new_nand$I$a$)",
"sync_compare_and_swap[$A] = CODE_FOR_$(sync_compare_and_swap$I$a$)", "sync_compare_and_swap[$A] = CODE_FOR_$(sync_compare_and_swap$I$a$)",
"sync_compare_and_swap_cc[$A] = CODE_FOR_$(sync_compare_and_swap_cc$I$a$)",
"sync_lock_test_and_set[$A] = CODE_FOR_$(sync_lock_test_and_set$I$a$)", "sync_lock_test_and_set[$A] = CODE_FOR_$(sync_lock_test_and_set$I$a$)",
"sync_lock_release[$A] = CODE_FOR_$(sync_lock_release$I$a$)", "sync_lock_release[$A] = CODE_FOR_$(sync_lock_release$I$a$)",
"optab_handler (vec_set_optab, $A)->insn_code = CODE_FOR_$(vec_set$a$)", "optab_handler (vec_set_optab, $A)->insn_code = CODE_FOR_$(vec_set$a$)",

View file

@ -1,3 +1,9 @@
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.
2009-03-31 Richard Guenther <rguenther@suse.de> 2009-03-31 Richard Guenther <rguenther@suse.de>
* java-gimplify.c (java_gimplify_expr): Do not manually gimplify * java-gimplify.c (java_gimplify_expr): Do not manually gimplify

View file

@ -304,8 +304,7 @@ compareAndSwapInt_builtin (tree method_return_type ATTRIBUTE_UNUSED,
tree orig_call) tree orig_call)
{ {
enum machine_mode mode = TYPE_MODE (int_type_node); enum machine_mode mode = TYPE_MODE (int_type_node);
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
{ {
tree addr, stmt; tree addr, stmt;
UNMARSHAL5 (orig_call); UNMARSHAL5 (orig_call);
@ -324,8 +323,7 @@ compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED,
tree orig_call) tree orig_call)
{ {
enum machine_mode mode = TYPE_MODE (long_type_node); enum machine_mode mode = TYPE_MODE (long_type_node);
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
{ {
tree addr, stmt; tree addr, stmt;
UNMARSHAL5 (orig_call); UNMARSHAL5 (orig_call);
@ -343,8 +341,7 @@ compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED,
tree orig_call) tree orig_call)
{ {
enum machine_mode mode = TYPE_MODE (ptr_type_node); enum machine_mode mode = TYPE_MODE (ptr_type_node);
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
{ {
tree addr, stmt; tree addr, stmt;
int builtin; int builtin;
@ -422,8 +419,7 @@ VMSupportsCS8_builtin (tree method_return_type,
{ {
enum machine_mode mode = TYPE_MODE (long_type_node); enum machine_mode mode = TYPE_MODE (long_type_node);
gcc_assert (method_return_type == boolean_type_node); gcc_assert (method_return_type == boolean_type_node);
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
return boolean_true_node; return boolean_true_node;
else else
return boolean_false_node; return boolean_false_node;

View file

@ -4143,11 +4143,15 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
*px = x; *px = x;
*py = y; *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; return;
/* Handle a lib call just for the mode we are using. */ /* Handle a lib call just for the mode we are using. */
libfunc = optab_libfunc (cmp_optab, mode); libfunc = optab_libfunc (cmp_optab, mode);
if (libfunc && !SCALAR_FLOAT_MODE_P (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. */ /* Try combined insns first. */
do do
{ {
enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : wider_mode;
enum insn_code icode; enum insn_code icode;
PUT_MODE (test, wider_mode); PUT_MODE (test, wider_mode);
if (label) 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 if (icode != CODE_FOR_nothing
&& insn_data[icode].operand[0].predicate (test, wider_mode)) && 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. */ /* 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) if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
{ {
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 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. */ /* 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) if (icode != CODE_FOR_nothing)
{ {
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp); 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_xor_optab[i] = CODE_FOR_nothing;
sync_new_nand_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[i] = CODE_FOR_nothing;
sync_compare_and_swap_cc[i] = CODE_FOR_nothing;
sync_lock_test_and_set[i] = CODE_FOR_nothing; sync_lock_test_and_set[i] = CODE_FOR_nothing;
sync_lock_release[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); 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 /* Expand a compare-and-swap operation and store true into the result if
the operation was successful and false otherwise. Return the result. the operation was successful and false otherwise. Return the result.
Unlike other routines, TARGET is not optional. */ 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 machine_mode mode = GET_MODE (mem);
enum insn_code icode; enum insn_code icode;
rtx subtarget, label0, label1; rtx subtarget, seq, cc_reg;
/* If the target supports a compare-and-swap pattern that simultaneously /* If the target supports a compare-and-swap pattern that simultaneously
sets some flag for success, then use it. Otherwise use the regular sets some flag for success, then use it. Otherwise use the regular
compare-and-swap and follow that immediately with a compare insn. */ compare-and-swap and follow that immediately with a compare insn. */
icode = sync_compare_and_swap_cc[mode]; icode = sync_compare_and_swap[mode];
switch (icode) if (icode == CODE_FOR_nothing)
return NULL_RTX;
do
{ {
default: start_sequence ();
subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val, subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
NULL_RTX, icode); NULL_RTX, icode);
if (subtarget != NULL_RTX) cc_reg = 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);
subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
NULL_RTX, icode);
if (subtarget == 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; end_sequence ();
rtx insn; return NULL_RTX;
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;
}
} }
if (have_insn_for (COMPARE, CCmode))
note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg);
seq = get_insns ();
end_sequence ();
/* 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);
/* Without an appropriate setcc instruction, use a set of branches to emit_insn (seq);
get 1 and 0 stored into target. Presumably if the target has a if (cc_reg)
STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt. */ return emit_store_flag (target, EQ, cc_reg, const0_rtx, VOIDmode, 0, 1);
else
label0 = gen_label_rtx (); return emit_store_flag (target, EQ, subtarget, old_val, VOIDmode, 1, 1);
label1 = gen_label_rtx ();
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);
return target;
} }
/* This is a helper function for the other atomic operations. This function /* 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 machine_mode mode = GET_MODE (mem);
enum insn_code icode; enum insn_code icode;
rtx label, cmp_reg, subtarget; rtx label, cmp_reg, subtarget, cc_reg;
/* The loop we want to generate looks like /* 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 /* If the target supports a compare-and-swap pattern that simultaneously
sets some flag for success, then use it. Otherwise use the regular sets some flag for success, then use it. Otherwise use the regular
compare-and-swap and follow that immediately with a compare insn. */ compare-and-swap and follow that immediately with a compare insn. */
icode = sync_compare_and_swap_cc[mode]; icode = sync_compare_and_swap[mode];
switch (icode) 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;
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
{ {
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;
}
/* 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;
if (subtarget != cmp_reg) if (subtarget != cmp_reg)
emit_move_insn (cmp_reg, subtarget); emit_move_insn (cmp_reg, subtarget);
emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
} }
/* ??? Mark this jump predicted not taken? */ /* ??? 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; return true;
} }

View file

@ -670,7 +670,6 @@ extern enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
/* Atomic compare and swap. */ /* Atomic compare and swap. */
extern enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES]; extern enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
extern enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
/* Atomic exchange with acquire semantics. */ /* Atomic exchange with acquire semantics. */
extern enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES]; extern enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];