Commit 9f0076e5 by David Edelsohn Committed by David Edelsohn

rs6000.md (UNSPEC_SYNC, [...]): New.

        * config/rs6000/rs6000.md (UNSPEC_SYNC, UNSPEC_LWSYNC,
        UNSPEC_ISYNC, UNSPEC_SYNC_OP, UNSPEC_ATOMIC, UNSPEC_CMPXCHG,
        UNSPEC_XCHG, UNSPEC_AND): New.
        (UNSPECV_ATOMIC, UNSPECV_SYNC, UNSPECV_SYNC_OP, UNSPECV_CMPXCHG,
        UNSPECV_LWSYNC, UNSPECV_ISYNC): Delete.
        * config/rs6000/sync.md (FETCHOP): New code macro.
        (fetchop_name, fetchop_pred, fetchopsi_constr, fetchopdi_constr):
        New code attrs.
        (memory_barrier, sync_internal): Use unspec instead of unspec_volatile.
        (sync_compare_and_swap<mode>): Same.
        (sync_lock_test_and_set<mode>): Same.
        (sync_<fetchop><mode>, sync_nand<mode>): Only use rs6000_emit_sync
        for QImode and HImode, and not PPC405.
        (sync_old_<fetchop><mode>, sync_old_nand<mode>): Same.
        (sync_new_<fetchop><mode>, sync_new_nand<mode>): Same.
        (sync_<fetchop>{si,di}_internal): New.
        (sync_nand{si,di}_internal): New.
        (sync_old_<fetchop>{si,di}_internal): New.
        (sync_old_nand{si,di}_internal): New
        (sync_new_<fetchop>{si,di}_internal): New.
        (sync_new_nand{si,di}_internal): New.
        (atomic_and{si,di}): New.
        (sync_new_nand{si,di}_internal): New.
        (atomic_and{si,di}): New.
        (sync_add<mode>_internal): Delete.
        (sync_addshort_internal): Use unspec instead of unspec_volatile.
        (sync_sub<mode>_internal): Delte.
        (sync_subshort_internal): New.
        (sync_andsi_internal): Use unspec instead of unspec_volatile.
        (sync_anddi_internal): Delete.
        (sync_boolsi_internal): Use unspec instead of unspec_volatile.
        (sync_booldi_internal): Delete.
        (sync_boolc<mode>_internal): Delete.
        (sync_boolcshort_internal): Use unspec instead of unspec_volatile.
        (sync_boolc<mode>_internal2): Delete.
        (sync_boolcc<mode>_internal): Delete.
        (isync, lwsync): Use unspec instead of unspec_volatile.
        * config/rs6000/rs6000.c (rs6000_emit_sync): Implement MINUS.
        Revert UNSPEC_VOLATILE.
        (rs6000_split_atomic_op): New.
        * config/rs6000/rs6000-protos.h (rs6000_split_atomic_op): Declare.

From-SVN: r102049
parent 81189fe7
2005-07-14 David Edelsohn <edelsohn@gnu.org>
* config/rs6000/rs6000.md (UNSPEC_SYNC, UNSPEC_LWSYNC,
UNSPEC_ISYNC, UNSPEC_SYNC_OP, UNSPEC_ATOMIC, UNSPEC_CMPXCHG,
UNSPEC_XCHG, UNSPEC_AND): New.
(UNSPECV_ATOMIC, UNSPECV_SYNC, UNSPECV_SYNC_OP, UNSPECV_CMPXCHG,
UNSPECV_LWSYNC, UNSPECV_ISYNC): Delete.
* config/rs6000/sync.md (FETCHOP): New code macro.
(fetchop_name, fetchop_pred, fetchopsi_constr, fetchopdi_constr):
New code attrs.
(memory_barrier, sync_internal): Use unspec instead of unspec_volatile.
(sync_compare_and_swap<mode>): Same.
(sync_lock_test_and_set<mode>): Same.
(sync_<fetchop><mode>, sync_nand<mode>): Only use rs6000_emit_sync
for QImode and HImode, and not PPC405.
(sync_old_<fetchop><mode>, sync_old_nand<mode>): Same.
(sync_new_<fetchop><mode>, sync_new_nand<mode>): Same.
(sync_<fetchop>{si,di}_internal): New.
(sync_nand{si,di}_internal): New.
(sync_old_<fetchop>{si,di}_internal): New.
(sync_old_nand{si,di}_internal): New
(sync_new_<fetchop>{si,di}_internal): New.
(sync_new_nand{si,di}_internal): New.
(atomic_and{si,di}): New.
(sync_new_nand{si,di}_internal): New.
(atomic_and{si,di}): New.
(sync_add<mode>_internal): Delete.
(sync_addshort_internal): Use unspec instead of unspec_volatile.
(sync_sub<mode>_internal): Delte.
(sync_subshort_internal): New.
(sync_andsi_internal): Use unspec instead of unspec_volatile.
(sync_anddi_internal): Delete.
(sync_boolsi_internal): Use unspec instead of unspec_volatile.
(sync_booldi_internal): Delete.
(sync_boolc<mode>_internal): Delete.
(sync_boolcshort_internal): Use unspec instead of unspec_volatile.
(sync_boolc<mode>_internal2): Delete.
(sync_boolcc<mode>_internal): Delete.
(isync, lwsync): Use unspec instead of unspec_volatile.
* config/rs6000/rs6000.c (rs6000_emit_sync): Implement MINUS.
Revert UNSPEC_VOLATILE.
(rs6000_split_atomic_op): New.
* config/rs6000/rs6000-protos.h (rs6000_split_atomic_op): Declare.
2005-07-14 Eric Christopher <echristo@redhat.com> 2005-07-14 Eric Christopher <echristo@redhat.com>
* config/mips/mips.c (mips_canonicalize_comparison): Cast * config/mips/mips.c (mips_canonicalize_comparison): Cast
......
...@@ -82,6 +82,7 @@ extern int rs6000_emit_vector_cond_expr (rtx, rtx, rtx, rtx, rtx, rtx); ...@@ -82,6 +82,7 @@ extern int rs6000_emit_vector_cond_expr (rtx, rtx, rtx, rtx, rtx, rtx);
extern void rs6000_emit_minmax (rtx, enum rtx_code, rtx, rtx); extern void rs6000_emit_minmax (rtx, enum rtx_code, rtx, rtx);
extern void rs6000_emit_sync (enum rtx_code, enum machine_mode, extern void rs6000_emit_sync (enum rtx_code, enum machine_mode,
rtx, rtx, rtx, rtx, bool); rtx, rtx, rtx, rtx, bool);
extern void rs6000_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
extern void rs6000_split_compare_and_swap (rtx, rtx, rtx, rtx, rtx); extern void rs6000_split_compare_and_swap (rtx, rtx, rtx, rtx, rtx);
extern void rs6000_split_lock_test_and_set (rtx, rtx, rtx, rtx); extern void rs6000_split_lock_test_and_set (rtx, rtx, rtx, rtx);
extern void rs6000_emit_swdivsf (rtx, rtx, rtx); extern void rs6000_emit_swdivsf (rtx, rtx, rtx);
......
...@@ -11560,6 +11560,7 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode, ...@@ -11560,6 +11560,7 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
} }
else else
oldop = lowpart_subreg (SImode, op, mode); oldop = lowpart_subreg (SImode, op, mode);
switch (code) switch (code)
{ {
case IOR: case IOR:
...@@ -11578,6 +11579,7 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode, ...@@ -11578,6 +11579,7 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
break; break;
case PLUS: case PLUS:
case MINUS:
{ {
rtx mask; rtx mask;
...@@ -11590,8 +11592,11 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode, ...@@ -11590,8 +11592,11 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
emit_move_insn (mask, GEN_INT (imask)); emit_move_insn (mask, GEN_INT (imask));
emit_insn (gen_ashlsi3 (mask, mask, shift)); emit_insn (gen_ashlsi3 (mask, mask, shift));
newop = gen_rtx_AND (SImode, gen_rtx_PLUS (SImode, m, newop), if (code == PLUS)
mask); newop = gen_rtx_PLUS (SImode, m, newop);
else
newop = gen_rtx_MINUS (SImode, m, newop);
newop = gen_rtx_AND (SImode, newop, mask);
newop = gen_rtx_IOR (SImode, newop, newop = gen_rtx_IOR (SImode, newop,
gen_rtx_AND (SImode, gen_rtx_AND (SImode,
gen_rtx_NOT (SImode, mask), gen_rtx_NOT (SImode, mask),
...@@ -11633,7 +11638,8 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode, ...@@ -11633,7 +11638,8 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
after = gen_reg_rtx (used_mode); after = gen_reg_rtx (used_mode);
} }
if ((code == PLUS || GET_CODE (m) == NOT) && used_mode != mode) if ((code == PLUS || code == MINUS || GET_CODE (m) == NOT)
&& used_mode != mode)
the_op = op; /* Computed above. */ the_op = op; /* Computed above. */
else if (GET_CODE (op) == NOT && GET_CODE (m) != NOT) else if (GET_CODE (op) == NOT && GET_CODE (m) != NOT)
the_op = gen_rtx_fmt_ee (code, used_mode, op, m); the_op = gen_rtx_fmt_ee (code, used_mode, op, m);
...@@ -11643,12 +11649,12 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode, ...@@ -11643,12 +11649,12 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
set_after = gen_rtx_SET (VOIDmode, after, the_op); set_after = gen_rtx_SET (VOIDmode, after, the_op);
set_before = gen_rtx_SET (VOIDmode, before, used_m); set_before = gen_rtx_SET (VOIDmode, before, used_m);
set_atomic = gen_rtx_SET (VOIDmode, used_m, set_atomic = gen_rtx_SET (VOIDmode, used_m,
gen_rtx_UNSPEC_VOLATILE (used_mode, gen_rtx_UNSPEC (used_mode,
gen_rtvec (1, the_op), gen_rtvec (1, the_op),
UNSPECV_SYNC_OP)); UNSPEC_SYNC_OP));
cc_scratch = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (CCmode)); cc_scratch = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (CCmode));
if (code == PLUS && used_mode != mode) if ((code == PLUS || code == MINUS) && used_mode != mode)
vec = gen_rtvec (5, set_after, set_before, set_atomic, cc_scratch, vec = gen_rtvec (5, set_after, set_before, set_atomic, cc_scratch,
gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode))); gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode)));
else else
...@@ -11716,12 +11722,55 @@ emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val) ...@@ -11716,12 +11722,55 @@ emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
else if (mode == DImode) else if (mode == DImode)
fn = gen_store_conditional_di; fn = gen_store_conditional_di;
/* Emit sync before stwcx. to address PPC405 Erratum. */
if (PPC405_ERRATUM77) if (PPC405_ERRATUM77)
emit_insn (gen_memory_barrier ()); emit_insn (gen_memory_barrier ());
emit_insn (fn (res, mem, val)); emit_insn (fn (res, mem, val));
} }
/* Expand an an atomic fetch-and-operate pattern. CODE is the binary operation
to perform. MEM is the memory on which to operate. VAL is the second
operand of the binary operator. BEFORE and AFTER are optional locations to
return the value of MEM either before of after the operation. SCRATCH is
a scratch register. */
void
rs6000_split_atomic_op (enum rtx_code code, rtx mem, rtx val,
rtx before, rtx after, rtx scratch)
{
enum machine_mode mode = GET_MODE (mem);
rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
emit_insn (gen_memory_barrier ());
label = gen_label_rtx ();
emit_label (label);
label = gen_rtx_LABEL_REF (VOIDmode, label);
if (before == NULL_RTX)
before = scratch;
emit_load_locked (mode, before, mem);
if (code == NOT)
x = gen_rtx_AND (mode, gen_rtx_NOT (mode, before), val);
else if (code == AND)
x = gen_rtx_UNSPEC (mode, gen_rtvec (2, before, val), UNSPEC_AND);
else
x = gen_rtx_fmt_ee (code, mode, before, val);
if (after != NULL_RTX)
emit_insn (gen_rtx_SET (VOIDmode, after, copy_rtx (x)));
emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
emit_store_conditional (mode, cond, mem, scratch);
x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
emit_unlikely_jump (x, label);
emit_insn (gen_isync ());
}
/* Expand an atomic compare and swap operation. MEM is the memory on which /* Expand an atomic compare and swap operation. MEM is the memory on which
to operate. OLDVAL is the old value to be compared. NEWVAL is the new to operate. OLDVAL is the old value to be compared. NEWVAL is the new
value to be stored. SCRATCH is a scratch GPR. */ value to be stored. SCRATCH is a scratch GPR. */
......
...@@ -52,10 +52,18 @@ ...@@ -52,10 +52,18 @@
(UNSPEC_FIX_TRUNC_TF 30) ; fadd, rounding towards zero (UNSPEC_FIX_TRUNC_TF 30) ; fadd, rounding towards zero
(UNSPEC_MV_CR_GT 31) ; move_from_CR_eq_bit (UNSPEC_MV_CR_GT 31) ; move_from_CR_eq_bit
(UNSPEC_STFIWX 32) (UNSPEC_STFIWX 32)
(UNSPEC_POPCNTB 38) (UNSPEC_POPCNTB 33)
(UNSPEC_FRES 39) (UNSPEC_FRES 34)
(UNSPEC_SP_SET 40) (UNSPEC_SP_SET 35)
(UNSPEC_SP_TEST 41) (UNSPEC_SP_TEST 36)
(UNSPEC_SYNC 37)
(UNSPEC_LWSYNC 38)
(UNSPEC_ISYNC 39)
(UNSPEC_SYNC_OP 40)
(UNSPEC_ATOMIC 41)
(UNSPEC_CMPXCHG 42)
(UNSPEC_XCHG 43)
(UNSPEC_AND 44)
]) ])
;; ;;
...@@ -66,12 +74,6 @@ ...@@ -66,12 +74,6 @@
[(UNSPECV_BLOCK 0) [(UNSPECV_BLOCK 0)
(UNSPECV_LL 1) ; load-locked (UNSPECV_LL 1) ; load-locked
(UNSPECV_SC 2) ; store-conditional (UNSPECV_SC 2) ; store-conditional
(UNSPECV_ATOMIC 3)
(UNSPECV_SYNC 4)
(UNSPECV_SYNC_OP 5)
(UNSPECV_CMPXCHG 6)
(UNSPECV_LWSYNC 7)
(UNSPECV_ISYNC 8)
(UNSPECV_EH_RR 9) ; eh_reg_restore (UNSPECV_EH_RR 9) ; eh_reg_restore
]) ])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment