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:
parent
bf080c96e0
commit
4a77c72b6b
14 changed files with 192 additions and 278 deletions
|
@ -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>
|
||||
|
||||
* except.c (find_prev_try): Break out from ....
|
||||
|
|
|
@ -1083,6 +1083,17 @@
|
|||
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:
|
||||
;; Set the FP condition codes.
|
||||
;;
|
||||
|
|
|
@ -70,7 +70,11 @@
|
|||
(match_operand:CASMODE 2 "register_operand" "")
|
||||
(match_operand:CASMODE 3 "register_operand" "")]
|
||||
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"
|
||||
{
|
||||
if ((<MODE>mode == DImode && !TARGET_64BIT) || <MODE>mode == TImode)
|
||||
|
@ -109,7 +113,11 @@
|
|||
(match_operand:IMODE 2 "register_operand" "a")
|
||||
(match_operand:IMODE 3 "register_operand" "<modeconstraint>")]
|
||||
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"
|
||||
"lock{%;| }cmpxchg{<modesuffix>}\t{%3, %1|%1, %3}")
|
||||
|
||||
|
@ -123,7 +131,12 @@
|
|||
(match_operand:<DCASHMODE> 3 "register_operand" "b")
|
||||
(match_operand:<DCASHMODE> 4 "register_operand" "c")]
|
||||
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")
|
||||
|
||||
|
@ -137,105 +150,6 @@
|
|||
;; just enumerate all regs possible here, which (as this is !TARGET_64BIT)
|
||||
;; are just esi and edi.
|
||||
(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")
|
||||
(match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m"))
|
||||
(set (match_dup 1)
|
||||
|
|
|
@ -172,6 +172,11 @@
|
|||
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"
|
||||
(match_code "eq, ne, lt, gt, le, ge")
|
||||
{
|
||||
|
|
|
@ -224,13 +224,10 @@ struct processor_costs z10_cost =
|
|||
extern int reload_completed;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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
|
||||
address. A legitimate address on S/390 is of the general
|
||||
form
|
||||
|
@ -814,23 +811,23 @@ rtx
|
|||
s390_emit_compare (enum rtx_code code, rtx op0, rtx 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
|
||||
pattern already computed the result and the machine modes are compatible. */
|
||||
if (s390_compare_emitted
|
||||
&& (s390_cc_modes_compatible (GET_MODE (s390_compare_emitted), mode)
|
||||
== GET_MODE (s390_compare_emitted)))
|
||||
ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx);
|
||||
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
|
||||
{
|
||||
gcc_assert (s390_cc_modes_compatible (GET_MODE (op0), mode)
|
||||
== GET_MODE (op0));
|
||||
cc = op0;
|
||||
}
|
||||
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)));
|
||||
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
|
||||
|
@ -841,14 +838,8 @@ s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
|
|||
static 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_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_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 a jump instruction to TARGET. If COND is NULL_RTX, emit an
|
||||
|
|
|
@ -817,7 +817,7 @@ do { \
|
|||
/* 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
|
||||
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. */
|
||||
|
|
|
@ -515,6 +515,16 @@
|
|||
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
|
||||
|
||||
|
@ -5122,7 +5132,7 @@
|
|||
(clobber (reg:CC CC_REGNUM))])]
|
||||
""
|
||||
{
|
||||
if (!s390_compare_emitted || GET_MODE (s390_compare_emitted) != CCZ1mode)
|
||||
if (GET_MODE (s390_compare_op0) != CCZ1mode)
|
||||
FAIL;
|
||||
operands[1] = s390_emit_compare (NE, s390_compare_op0, s390_compare_op1);
|
||||
PUT_MODE (operands[1], SImode);
|
||||
|
@ -8242,33 +8252,11 @@
|
|||
(match_operand:HQI 2 "general_operand" "")
|
||||
(match_operand:HQI 3 "general_operand" "")]
|
||||
UNSPECV_CAS))
|
||||
(set (reg:CCZ1 CC_REGNUM)
|
||||
(compare:CCZ1 (match_dup 1) (match_dup 2)))])]
|
||||
(clobber (reg:CC CC_REGNUM))])]
|
||||
""
|
||||
"s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1],
|
||||
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
|
||||
(define_insn "*sync_compare_and_swap<mode>"
|
||||
[(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_INT (TARGET_THREAD_SSP_OFFSET)));
|
||||
#endif
|
||||
s390_compare_op0 = operands[0];
|
||||
s390_compare_op1 = operands[1];
|
||||
s390_compare_emitted = gen_rtx_REG (CCZmode, CC_REGNUM);
|
||||
|
||||
if (TARGET_64BIT)
|
||||
emit_insn (gen_stack_protect_testdi (operands[0], operands[1]));
|
||||
else
|
||||
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]));
|
||||
|
||||
DONE;
|
||||
})
|
||||
|
||||
|
|
|
@ -5091,19 +5091,15 @@ memory operations before the atomic operation occur before the atomic
|
|||
operation and all memory operations after the atomic operation occur
|
||||
after the atomic operation.
|
||||
|
||||
@cindex @code{sync_compare_and_swap_cc@var{mode}} instruction pattern
|
||||
@item @samp{sync_compare_and_swap_cc@var{mode}}
|
||||
|
||||
This pattern is just like @code{sync_compare_and_swap@var{mode}}, except
|
||||
it should act as if compare part of the compare-and-swap were issued via
|
||||
@code{cmp@var{m}}. This comparison will only be used with @code{EQ} and
|
||||
@code{NE} branches and @code{setcc} operations.
|
||||
|
||||
Some targets do expose the success or failure of the compare-and-swap
|
||||
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}}.
|
||||
For targets where the success or failure of the compare-and-swap
|
||||
operation is available via the status flags, it is possible
|
||||
to avoid a separate compare operation and issue the subsequent
|
||||
setcc or branch immediately after the compare-and-swap. To this
|
||||
end, GCC will look for a @code{MODE_CC} set in the output of
|
||||
@code{sync_compare_and_swap@var{mode}}; if the machine description
|
||||
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
|
||||
@code{MODE_CC} set and use it as the first operand of @code{cmpcc}.
|
||||
|
||||
@cindex @code{sync_add@var{mode}} instruction pattern
|
||||
@cindex @code{sync_sub@var{mode}} instruction pattern
|
||||
|
|
|
@ -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_nand_optab[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_release[NUM_MACHINE_MODES];
|
||||
|
||||
|
|
|
@ -234,7 +234,6 @@ static const char * const optabs[] =
|
|||
"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_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_release[$A] = CODE_FOR_$(sync_lock_release$I$a$)",
|
||||
"optab_handler (vec_set_optab, $A)->insn_code = CODE_FOR_$(vec_set$a$)",
|
||||
|
|
|
@ -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>
|
||||
|
||||
* java-gimplify.c (java_gimplify_expr): Do not manually gimplify
|
||||
|
|
|
@ -304,8 +304,7 @@ compareAndSwapInt_builtin (tree method_return_type ATTRIBUTE_UNUSED,
|
|||
tree orig_call)
|
||||
{
|
||||
enum machine_mode mode = TYPE_MODE (int_type_node);
|
||||
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing
|
||||
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
{
|
||||
tree addr, stmt;
|
||||
UNMARSHAL5 (orig_call);
|
||||
|
@ -324,8 +323,7 @@ compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED,
|
|||
tree orig_call)
|
||||
{
|
||||
enum machine_mode mode = TYPE_MODE (long_type_node);
|
||||
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing
|
||||
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
{
|
||||
tree addr, stmt;
|
||||
UNMARSHAL5 (orig_call);
|
||||
|
@ -343,8 +341,7 @@ compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED,
|
|||
tree orig_call)
|
||||
{
|
||||
enum machine_mode mode = TYPE_MODE (ptr_type_node);
|
||||
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing
|
||||
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
{
|
||||
tree addr, stmt;
|
||||
int builtin;
|
||||
|
@ -422,8 +419,7 @@ VMSupportsCS8_builtin (tree method_return_type,
|
|||
{
|
||||
enum machine_mode mode = TYPE_MODE (long_type_node);
|
||||
gcc_assert (method_return_type == boolean_type_node);
|
||||
if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing
|
||||
|| sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
|
||||
return boolean_true_node;
|
||||
else
|
||||
return boolean_false_node;
|
||||
|
|
174
gcc/optabs.c
174
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)
|
||||
icode = sync_compare_and_swap[mode];
|
||||
if (icode == CODE_FOR_nothing)
|
||||
return NULL_RTX;
|
||||
|
||||
do
|
||||
{
|
||||
default:
|
||||
start_sequence ();
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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 ();
|
||||
|
||||
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;
|
||||
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)
|
||||
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;
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -670,7 +670,6 @@ extern enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
|
|||
|
||||
/* Atomic compare and swap. */
|
||||
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. */
|
||||
extern enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
|
||||
|
|
Loading…
Add table
Reference in a new issue