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
This commit is contained in:
David Edelsohn 2005-07-15 01:44:38 +00:00 committed by David Edelsohn
parent 81189fe7ba
commit 9f0076e547
5 changed files with 462 additions and 300 deletions

View File

@ -1,3 +1,47 @@
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>
* config/mips/mips.c (mips_canonicalize_comparison): Cast

View File

@ -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_sync (enum rtx_code, enum machine_mode,
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_lock_test_and_set (rtx, rtx, rtx, rtx);
extern void rs6000_emit_swdivsf (rtx, rtx, rtx);

View File

@ -11560,6 +11560,7 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
}
else
oldop = lowpart_subreg (SImode, op, mode);
switch (code)
{
case IOR:
@ -11578,6 +11579,7 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
break;
case PLUS:
case MINUS:
{
rtx mask;
@ -11590,8 +11592,11 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
emit_move_insn (mask, GEN_INT (imask));
emit_insn (gen_ashlsi3 (mask, mask, shift));
newop = gen_rtx_AND (SImode, gen_rtx_PLUS (SImode, m, newop),
mask);
if (code == PLUS)
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,
gen_rtx_AND (SImode,
gen_rtx_NOT (SImode, mask),
@ -11633,7 +11638,8 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode 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. */
else if (GET_CODE (op) == NOT && GET_CODE (m) != NOT)
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,
set_after = gen_rtx_SET (VOIDmode, after, the_op);
set_before = gen_rtx_SET (VOIDmode, before, used_m);
set_atomic = gen_rtx_SET (VOIDmode, used_m,
gen_rtx_UNSPEC_VOLATILE (used_mode,
gen_rtvec (1, the_op),
UNSPECV_SYNC_OP));
gen_rtx_UNSPEC (used_mode,
gen_rtvec (1, the_op),
UNSPEC_SYNC_OP));
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,
gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode)));
else
@ -11716,12 +11722,55 @@ emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
else if (mode == DImode)
fn = gen_store_conditional_di;
/* Emit sync before stwcx. to address PPC405 Erratum. */
if (PPC405_ERRATUM77)
emit_insn (gen_memory_barrier ());
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
to operate. OLDVAL is the old value to be compared. NEWVAL is the new
value to be stored. SCRATCH is a scratch GPR. */

View File

@ -52,10 +52,18 @@
(UNSPEC_FIX_TRUNC_TF 30) ; fadd, rounding towards zero
(UNSPEC_MV_CR_GT 31) ; move_from_CR_eq_bit
(UNSPEC_STFIWX 32)
(UNSPEC_POPCNTB 38)
(UNSPEC_FRES 39)
(UNSPEC_SP_SET 40)
(UNSPEC_SP_TEST 41)
(UNSPEC_POPCNTB 33)
(UNSPEC_FRES 34)
(UNSPEC_SP_SET 35)
(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 @@
[(UNSPECV_BLOCK 0)
(UNSPECV_LL 1) ; load-locked
(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
])

View File

@ -22,9 +22,20 @@
(define_mode_attr larx [(SI "lwarx") (DI "ldarx")])
(define_mode_attr stcx [(SI "stwcx.") (DI "stdcx.")])
(define_code_macro FETCHOP [plus minus ior xor and])
(define_code_attr fetchop_name
[(plus "add") (minus "sub") (ior "ior") (xor "xor") (and "and")])
(define_code_attr fetchop_pred
[(plus "add_operand") (minus "gpc_reg_operand")
(ior "logical_operand") (xor "logical_operand") (and "and_operand")])
(define_code_attr fetchopsi_constr
[(plus "rIL") (minus "r") (ior "rKL") (xor "rKL") (and "rTKL")])
(define_code_attr fetchopdi_constr
[(plus "rIL") (minus "r") (ior "rKJF") (xor "rKJF") (and "rSTKJ")])
(define_expand "memory_barrier"
[(set (mem:BLK (match_dup 0))
(unspec_volatile:BLK [(mem:BLK (match_dup 0))] UNSPECV_SYNC))]
(unspec:BLK [(mem:BLK (match_dup 0))] UNSPEC_SYNC))]
""
{
operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
@ -33,7 +44,7 @@
(define_insn "*sync_internal"
[(set (match_operand:BLK 0 "" "")
(unspec_volatile:BLK [(match_operand:BLK 1 "" "")] UNSPECV_SYNC))]
(unspec:BLK [(match_operand:BLK 1 "" "")] UNSPEC_SYNC))]
""
"{dcs|sync}"
[(set_attr "type" "sync")])
@ -59,10 +70,10 @@
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
(match_operand:GPR 1 "memory_operand" "+Z"))
(set (match_dup 1)
(unspec_volatile:GPR
(unspec:GPR
[(match_operand:GPR 2 "reg_or_short_operand" "rI")
(match_operand:GPR 3 "gpc_reg_operand" "r")]
UNSPECV_CMPXCHG))
UNSPEC_CMPXCHG))
(clobber (match_scratch:GPR 4 "=&r"))
(clobber (match_scratch:CC 5 "=&x"))]
"TARGET_POWERPC"
@ -77,11 +88,11 @@
(define_insn_and_split "sync_lock_test_and_set<mode>"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
(match_operand:GPR 1 "memory_operand" "+Z"))
(match_operand:GPR 1 "memory_operand" "+Z"))
(set (match_dup 1)
(unspec_volatile:GPR
(unspec:GPR
[(match_operand:GPR 2 "reg_or_short_operand" "rL")]
UNSPECV_CMPXCHG))
UNSPEC_XCHG))
(clobber (match_scratch:GPR 3 "=&r"))
(clobber (match_scratch:CC 4 "=&x"))]
"TARGET_POWERPC"
@ -94,243 +105,362 @@
DONE;
})
(define_expand "sync_add<mode>"
[(use (match_operand:INT1 0 "memory_operand" ""))
(use (match_operand:INT1 1 "add_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
(define_expand "sync_<fetchop_name><mode>"
[(parallel [(set (match_operand:INT1 0 "memory_operand" "")
(unspec:INT1
[(FETCHOP:INT1 (match_dup 0)
(match_operand:INT1 1 "<fetchop_pred>" ""))]
UNSPEC_ATOMIC))
(clobber (scratch:INT1))
(clobber (scratch:CC))])]
"TARGET_POWERPC"
"
{
rs6000_emit_sync (PLUS, <MODE>mode, operands[0], operands[1],
NULL_RTX, NULL_RTX, true);
DONE;
if (<MODE>mode != SImode && <MODE>mode != DImode)
{
if (PPC405_ERRATUM77)
FAIL;
rs6000_emit_sync (<CODE>, <MODE>mode, operands[0], operands[1],
NULL_RTX, NULL_RTX, true);
DONE;
}
}")
(define_expand "sync_sub<mode>"
[(use (match_operand:GPR 0 "memory_operand" ""))
(use (match_operand:GPR 1 "gpc_reg_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
(define_insn_and_split "*sync_<fetchop_name>si_internal"
[(set (match_operand:SI 0 "memory_operand" "+Z")
(unspec:SI
[(FETCHOP:SI (match_dup 0)
(match_operand:SI 1 "<fetchop_pred>" "<fetchopsi_constr>"))]
UNSPEC_ATOMIC))
(clobber (match_scratch:SI 2 "=&r"))
(clobber (match_scratch:CC 3 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_emit_sync (MINUS, <MODE>mode, operands[0], operands[1],
NULL_RTX, NULL_RTX, true);
rs6000_split_atomic_op (<CODE>, operands[0], operands[1],
NULL_RTX, NULL_RTX, operands[2]);
DONE;
}")
})
(define_expand "sync_ior<mode>"
[(use (match_operand:INT1 0 "memory_operand" ""))
(use (match_operand:INT1 1 "logical_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
(define_insn_and_split "*sync_<fetchop_name>di_internal"
[(set (match_operand:DI 0 "memory_operand" "+Z")
(unspec:DI
[(FETCHOP:DI (match_dup 0)
(match_operand:DI 1 "<fetchop_pred>" "<fetchopdi_constr>"))]
UNSPEC_ATOMIC))
(clobber (match_scratch:DI 2 "=&r"))
(clobber (match_scratch:CC 3 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_emit_sync (IOR, <MODE>mode, operands[0], operands[1],
NULL_RTX, NULL_RTX, true);
rs6000_split_atomic_op (<CODE>, operands[0], operands[1],
NULL_RTX, NULL_RTX, operands[2]);
DONE;
}")
(define_expand "sync_and<mode>"
[(use (match_operand:INT1 0 "memory_operand" ""))
(use (match_operand:INT1 1 "and_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
{
rs6000_emit_sync (AND, <MODE>mode, operands[0], operands[1],
NULL_RTX, NULL_RTX, true);
DONE;
}")
(define_expand "sync_xor<mode>"
[(use (match_operand:INT1 0 "memory_operand" ""))
(use (match_operand:INT1 1 "logical_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
{
rs6000_emit_sync (XOR, <MODE>mode, operands[0], operands[1],
NULL_RTX, NULL_RTX, true);
DONE;
}")
})
(define_expand "sync_nand<mode>"
[(use (match_operand:INT1 0 "memory_operand" ""))
(use (match_operand:INT1 1 "gpc_reg_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
[(parallel [(set (match_operand:INT1 0 "memory_operand" "")
(unspec:INT1
[(and:INT1 (not:INT1 (match_dup 0))
(match_operand:INT1 1 "gpc_reg_operand" ""))]
UNSPEC_ATOMIC))
(clobber (scratch:INT1))
(clobber (scratch:CC))])]
"TARGET_POWERPC"
"
{
rs6000_emit_sync (AND, <MODE>mode,
gen_rtx_NOT (<MODE>mode, operands[0]),
operands[1],
NULL_RTX, NULL_RTX, true);
DONE;
if (<MODE>mode != SImode && <MODE>mode != DImode)
{
if (PPC405_ERRATUM77)
FAIL;
rs6000_emit_sync (AND, <MODE>mode,
gen_rtx_NOT (<MODE>mode, operands[0]),
operands[1],
NULL_RTX, NULL_RTX, true);
DONE;
}
}")
(define_expand "sync_old_add<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "add_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
(define_insn_and_split "*sync_nand<mode>_internal"
[(set (match_operand:GPR 0 "memory_operand" "+Z")
(unspec:GPR
[(and:GPR (not:GPR (match_dup 0))
(match_operand:GPR 1 "gpc_reg_operand" "r"))]
UNSPEC_ATOMIC))
(clobber (match_scratch:GPR 2 "=&r"))
(clobber (match_scratch:CC 3 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_emit_sync (PLUS, <MODE>mode, operands[1], operands[2],
operands[0], NULL_RTX, true);
rs6000_split_atomic_op (NOT, operands[0], operands[1],
NULL_RTX, NULL_RTX, operands[2]);
DONE;
})
(define_expand "sync_old_<fetchop_name><mode>"
[(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
(match_operand:INT1 1 "memory_operand" ""))
(set (match_dup 1)
(unspec:INT1
[(FETCHOP:INT1 (match_dup 1)
(match_operand:INT1 2 "<fetchop_pred>" ""))]
UNSPEC_ATOMIC))
(clobber (scratch:INT1))
(clobber (scratch:CC))])]
"TARGET_POWERPC"
"
{
if (<MODE>mode != SImode && <MODE>mode != DImode)
{
if (PPC405_ERRATUM77)
FAIL;
rs6000_emit_sync (<CODE>, <MODE>mode, operands[1], operands[2],
operands[0], NULL_RTX, true);
DONE;
}
}")
(define_expand "sync_old_sub<mode>"
[(use (match_operand:GPR 0 "gpc_reg_operand" ""))
(use (match_operand:GPR 1 "memory_operand" ""))
(use (match_operand:GPR 2 "gpc_reg_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
(define_insn_and_split "*sync_old_<fetchop_name>si_internal"
[(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
(match_operand:SI 1 "memory_operand" "+Z"))
(set (match_dup 1)
(unspec:SI
[(FETCHOP:SI (match_dup 1)
(match_operand:SI 2 "<fetchop_pred>" "<fetchopsi_constr>"))]
UNSPEC_ATOMIC))
(clobber (match_scratch:SI 3 "=&r"))
(clobber (match_scratch:CC 4 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_emit_sync (MINUS, <MODE>mode, operands[1], operands[2],
operands[0], NULL_RTX, true);
rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
operands[0], NULL_RTX, operands[3]);
DONE;
}")
})
(define_expand "sync_old_ior<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "logical_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
(define_insn_and_split "*sync_old_<fetchop_name>di_internal"
[(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
(match_operand:DI 1 "memory_operand" "+Z"))
(set (match_dup 1)
(unspec:DI
[(FETCHOP:DI (match_dup 1)
(match_operand:DI 2 "<fetchop_pred>" "<fetchopdi_constr>"))]
UNSPEC_ATOMIC))
(clobber (match_scratch:DI 3 "=&r"))
(clobber (match_scratch:CC 4 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_emit_sync (IOR, <MODE>mode, operands[1], operands[2],
operands[0], NULL_RTX, true);
rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
operands[0], NULL_RTX, operands[3]);
DONE;
}")
(define_expand "sync_old_and<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "and_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
{
rs6000_emit_sync (AND, <MODE>mode, operands[1], operands[2],
operands[0], NULL_RTX, true);
DONE;
}")
(define_expand "sync_old_xor<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "logical_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
{
rs6000_emit_sync (XOR, <MODE>mode, operands[1], operands[2],
operands[0], NULL_RTX, true);
DONE;
}")
})
(define_expand "sync_old_nand<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "gpc_reg_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
[(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
(match_operand:INT1 1 "memory_operand" ""))
(set (match_dup 1)
(unspec:INT1
[(and:INT1 (not:INT1 (match_dup 1))
(match_operand:INT1 2 "gpc_reg_operand" ""))]
UNSPEC_ATOMIC))
(clobber (scratch:INT1))
(clobber (scratch:CC))])]
"TARGET_POWERPC"
"
{
rs6000_emit_sync (AND, <MODE>mode,
gen_rtx_NOT (<MODE>mode, operands[1]),
operands[2],
operands[0], NULL_RTX, true);
DONE;
if (<MODE>mode != SImode && <MODE>mode != DImode)
{
if (PPC405_ERRATUM77)
FAIL;
rs6000_emit_sync (AND, <MODE>mode,
gen_rtx_NOT (<MODE>mode, operands[1]),
operands[2],
operands[0], NULL_RTX, true);
DONE;
}
}")
(define_expand "sync_new_add<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "add_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
(define_insn_and_split "*sync_old_nand<mode>_internal"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
(match_operand:GPR 1 "memory_operand" "+Z"))
(set (match_dup 1)
(unspec:GPR
[(and:GPR (not:GPR (match_dup 1))
(match_operand:GPR 2 "gpc_reg_operand" "r"))]
UNSPEC_ATOMIC))
(clobber (match_scratch:GPR 3 "=&r"))
(clobber (match_scratch:CC 4 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_split_atomic_op (NOT, operands[1], operands[2],
operands[0], NULL_RTX, operands[3]);
DONE;
})
(define_expand "sync_new_<fetchop_name><mode>"
[(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
(FETCHOP:INT1
(match_operand:INT1 1 "memory_operand" "")
(match_operand:INT1 2 "<fetchop_pred>" "")))
(set (match_dup 1)
(unspec:INT1
[(FETCHOP:INT1 (match_dup 1) (match_dup 2))]
UNSPEC_ATOMIC))
(clobber (scratch:INT1))
(clobber (scratch:CC))])]
"TARGET_POWERPC"
"
{
rs6000_emit_sync (PLUS, <MODE>mode, operands[1], operands[2],
NULL_RTX, operands[0], true);
DONE;
if (<MODE>mode != SImode && <MODE>mode != DImode)
{
if (PPC405_ERRATUM77)
FAIL;
rs6000_emit_sync (<CODE>, <MODE>mode, operands[1], operands[2],
NULL_RTX, operands[0], true);
DONE;
}
}")
(define_expand "sync_new_sub<mode>"
[(use (match_operand:GPR 0 "gpc_reg_operand" ""))
(use (match_operand:GPR 1 "memory_operand" ""))
(use (match_operand:GPR 2 "gpc_reg_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
(define_insn_and_split "*sync_new_<fetchop_name>si_internal"
[(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
(FETCHOP:SI
(match_operand:SI 1 "memory_operand" "+Z")
(match_operand:SI 2 "<fetchop_pred>" "<fetchopsi_constr>")))
(set (match_dup 1)
(unspec:SI
[(FETCHOP:SI (match_dup 1) (match_dup 2))]
UNSPEC_ATOMIC))
(clobber (match_scratch:SI 3 "=&r"))
(clobber (match_scratch:CC 4 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_emit_sync (MINUS, <MODE>mode, operands[1], operands[2],
NULL_RTX, operands[0], true);
rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
NULL_RTX, operands[0], operands[3]);
DONE;
}")
})
(define_expand "sync_new_ior<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "logical_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
(define_insn_and_split "*sync_new_<fetchop_name>di_internal"
[(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
(FETCHOP:DI
(match_operand:DI 1 "memory_operand" "+Z")
(match_operand:DI 2 "<fetchop_pred>" "<fetchopdi_constr>")))
(set (match_dup 1)
(unspec:DI
[(FETCHOP:DI (match_dup 1) (match_dup 2))]
UNSPEC_ATOMIC))
(clobber (match_scratch:DI 3 "=&r"))
(clobber (match_scratch:CC 4 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_emit_sync (IOR, <MODE>mode, operands[1], operands[2],
NULL_RTX, operands[0], true);
rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
NULL_RTX, operands[0], operands[3]);
DONE;
}")
(define_expand "sync_new_and<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "and_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
{
rs6000_emit_sync (AND, <MODE>mode, operands[1], operands[2],
NULL_RTX, operands[0], true);
DONE;
}")
(define_expand "sync_new_xor<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "logical_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"
{
rs6000_emit_sync (XOR, <MODE>mode, operands[1], operands[2],
NULL_RTX, operands[0], true);
DONE;
}")
})
(define_expand "sync_new_nand<mode>"
[(use (match_operand:INT1 0 "gpc_reg_operand" ""))
(use (match_operand:INT1 1 "memory_operand" ""))
(use (match_operand:INT1 2 "gpc_reg_operand" ""))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
[(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
(and:INT1
(not:INT1 (match_operand:INT1 1 "memory_operand" ""))
(match_operand:INT1 2 "gpc_reg_operand" "")))
(set (match_dup 1)
(unspec:INT1
[(and:INT1 (not:INT1 (match_dup 1)) (match_dup 2))]
UNSPEC_ATOMIC))
(clobber (scratch:INT1))
(clobber (scratch:CC))])]
"TARGET_POWERPC"
"
{
rs6000_emit_sync (AND, <MODE>mode,
gen_rtx_NOT (<MODE>mode, operands[1]),
operands[2],
NULL_RTX, operands[0], true);
DONE;
if (<MODE>mode != SImode && <MODE>mode != DImode)
{
if (PPC405_ERRATUM77)
FAIL;
rs6000_emit_sync (AND, <MODE>mode,
gen_rtx_NOT (<MODE>mode, operands[1]),
operands[2],
NULL_RTX, operands[0], true);
DONE;
}
}")
(define_insn_and_split "*sync_new_nand<mode>_internal"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
(and:GPR
(not:GPR (match_operand:GPR 1 "memory_operand" "+Z"))
(match_operand:GPR 2 "gpc_reg_operand" "r")))
(set (match_dup 1)
(unspec:GPR
[(and:GPR (not:GPR (match_dup 1)) (match_dup 2))]
UNSPEC_ATOMIC))
(clobber (match_scratch:GPR 3 "=&r"))
(clobber (match_scratch:CC 4 "=&x"))]
"TARGET_POWERPC"
"#"
"&& reload_completed"
[(const_int 0)]
{
rs6000_split_atomic_op (NOT, operands[1], operands[2],
NULL_RTX, operands[0], operands[3]);
DONE;
})
; and<mode> without cr0 clobber to avoid generation of additional clobber
; in atomic splitters causing internal consistency failure.
; cr0 already clobbered by larx/stcx.
(define_insn "*atomic_andsi"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
(unspec:SI [(match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
(match_operand:SI 2 "and_operand" "?r,T,K,L")]
UNSPEC_AND))]
""
"@
and %0,%1,%2
{rlinm|rlwinm} %0,%1,0,%m2,%M2
{andil.|andi.} %0,%1,%b2
{andiu.|andis.} %0,%1,%u2"
[(set_attr "type" "*,*,compare,compare")])
(define_insn "*atomic_anddi"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r")
(unspec:DI [(match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r")
(match_operand:DI 2 "and_operand" "?r,S,T,K,J")]
UNSPEC_AND))]
"TARGET_POWERPC64"
"@
and %0,%1,%2
rldic%B2 %0,%1,0,%S2
rlwinm %0,%1,0,%m2,%M2
andi. %0,%1,%b2
andis. %0,%1,%u2"
[(set_attr "type" "*,*,*,compare,compare")
(set_attr "length" "4,4,4,4,4")])
; the sync_*_internal patterns all have these operands:
; 0 - memory location
; 1 - operand
; 2 - value in memory after operation
; 3 - value in memory immediately before operation
(define_insn "*sync_add<mode>_internal"
[(set (match_operand:GPR 2 "gpc_reg_operand" "=&r,&r")
(plus:GPR (match_operand:GPR 0 "memory_operand" "+Z,Z")
(match_operand:GPR 1 "add_operand" "rI,L")))
(set (match_operand:GPR 3 "gpc_reg_operand" "=&b,&b") (match_dup 0))
(set (match_dup 0)
(unspec_volatile:GPR [(plus:GPR (match_dup 0) (match_dup 1))]
UNSPECV_SYNC_OP))
(clobber (match_scratch:CC 4 "=&x,&x"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"@
<larx> %3,%y0\n\tadd%I1 %2,%3,%1\n\t<stcx> %2,%y0\n\tbne- $-12
<larx> %3,%y0\n\taddis %2,%3,%v1\n\t<stcx> %2,%y0\n\tbne- $-12"
[(set_attr "length" "16,16")])
(define_insn "*sync_addshort_internal"
[(set (match_operand:SI 2 "gpc_reg_operand" "=&r")
(ior:SI (and:SI (plus:SI (match_operand:SI 0 "memory_operand" "+Z")
@ -338,38 +468,43 @@
(match_operand:SI 4 "gpc_reg_operand" "r"))
(and:SI (not:SI (match_dup 4)) (match_dup 0))))
(set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0))
(set (match_dup 0)
(unspec_volatile:SI [(ior:SI (and:SI (plus:SI (match_dup 0) (match_dup 1))
(set (match_dup 0)
(unspec:SI [(ior:SI (and:SI (plus:SI (match_dup 0) (match_dup 1))
(match_dup 4))
(and:SI (not:SI (match_dup 4)) (match_dup 0)))]
UNSPECV_SYNC_OP))
UNSPEC_SYNC_OP))
(clobber (match_scratch:CC 5 "=&x"))
(clobber (match_scratch:SI 6 "=&r"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"lwarx %3,%y0\n\tadd%I1 %2,%3,%1\n\tandc %6,%3,%4\n\tand %2,%2,%4\n\tor %2,%2,%6\n\tstwcx. %2,%y0\n\tbne- $-24"
[(set_attr "length" "28")])
(define_insn "*sync_sub<mode>_internal"
[(set (match_operand:GPR 2 "gpc_reg_operand" "=&r")
(minus:GPR (match_operand:GPR 0 "memory_operand" "+Z")
(match_operand:GPR 1 "gpc_reg_operand" "r")))
(set (match_operand:GPR 3 "gpc_reg_operand" "=&b") (match_dup 0))
(set (match_dup 0)
(unspec_volatile:GPR [(minus:GPR (match_dup 0) (match_dup 1))]
UNSPECV_SYNC_OP))
(clobber (match_scratch:CC 4 "=&x"))]
(define_insn "*sync_subshort_internal"
[(set (match_operand:SI 2 "gpc_reg_operand" "=&r")
(ior:SI (and:SI (minus:SI (match_operand:SI 0 "memory_operand" "+Z")
(match_operand:SI 1 "add_operand" "rI"))
(match_operand:SI 4 "gpc_reg_operand" "r"))
(and:SI (not:SI (match_dup 4)) (match_dup 0))))
(set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0))
(set (match_dup 0)
(unspec:SI [(ior:SI (and:SI (minus:SI (match_dup 0) (match_dup 1))
(match_dup 4))
(and:SI (not:SI (match_dup 4)) (match_dup 0)))]
UNSPEC_SYNC_OP))
(clobber (match_scratch:CC 5 "=&x"))
(clobber (match_scratch:SI 6 "=&r"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"<larx> %3,%y0\n\tsubf %2,%1,%3\n\t<stcx> %2,%y0\n\tbne- $-12"
[(set_attr "length" "16")])
"lwarx %3,%y0\n\tsubf %2,%1,%3\n\tandc %6,%3,%4\n\tand %2,%2,%4\n\tor %2,%2,%6\n\tstwcx. %2,%y0\n\tbne- $-24"
[(set_attr "length" "28")])
(define_insn "*sync_andsi_internal"
[(set (match_operand:SI 2 "gpc_reg_operand" "=&r,&r,&r,&r")
(and:SI (match_operand:SI 0 "memory_operand" "+Z,Z,Z,Z")
(match_operand:SI 1 "and_operand" "r,T,K,L")))
(set (match_operand:SI 3 "gpc_reg_operand" "=&b,&b,&b,&b") (match_dup 0))
(set (match_dup 0)
(unspec_volatile:SI [(and:SI (match_dup 0) (match_dup 1))]
UNSPECV_SYNC_OP))
(set (match_dup 0)
(unspec:SI [(and:SI (match_dup 0) (match_dup 1))]
UNSPEC_SYNC_OP))
(clobber (match_scratch:CC 4 "=&x,&x,&x,&x"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"@
@ -379,31 +514,13 @@
lwarx %3,%y0\n\tandis. %2,%3,%u1\n\tstwcx. %2,%y0\n\tbne- $-12"
[(set_attr "length" "16,16,16,16")])
(define_insn "*sync_anddi_internal"
[(set (match_operand:DI 2 "gpc_reg_operand" "=&r,&r,&r,&r,&r")
(and:DI (match_operand:DI 0 "memory_operand" "+Z,Z,Z,Z,Z")
(match_operand:DI 1 "and_operand" "r,S,T,K,J")))
(set (match_operand:DI 3 "gpc_reg_operand" "=&b,&b,&b,&b,&b") (match_dup 0))
(set (match_dup 0)
(unspec_volatile:DI [(and:DI (match_dup 0) (match_dup 1))]
UNSPECV_SYNC_OP))
(clobber (match_scratch:CC 4 "=&x,&x,&x,&x,&x"))]
"TARGET_POWERPC64"
"@
ldarx %3,%y0\n\tand %2,%3,%1\n\tstdcx. %2,%y0\n\tbne- $-12
ldarx %3,%y0\n\trldic%B1 %2,%3,0,%S1\n\tstdcx. %2,%y0\n\tbne- $-12
ldarx %3,%y0\n\trlwinm %2,%3,0,%m1,%M1\n\tstdcx. %2,%y0\n\tbne- $-12
ldarx %3,%y0\n\tandi. %2,%3,%b1\n\tstdcx. %2,%y0\n\tbne- $-12
ldarx %3,%y0\n\tandis. %2,%3,%b1\n\tstdcx. %2,%y0\n\tbne- $-12"
[(set_attr "length" "16,16,16,16,16")])
(define_insn "*sync_boolsi_internal"
[(set (match_operand:SI 2 "gpc_reg_operand" "=&r,&r,&r")
(match_operator:SI 4 "boolean_or_operator"
[(match_operand:SI 0 "memory_operand" "+Z,Z,Z")
(match_operand:SI 1 "logical_operand" "r,K,L")]))
(set (match_operand:SI 3 "gpc_reg_operand" "=&b,&b,&b") (match_dup 0))
(set (match_dup 0) (unspec_volatile:SI [(match_dup 4)] UNSPECV_SYNC_OP))
(set (match_dup 0) (unspec:SI [(match_dup 4)] UNSPEC_SYNC_OP))
(clobber (match_scratch:CC 5 "=&x,&x,&x"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"@
@ -412,33 +529,6 @@
lwarx %3,%y0\n\t%q4is %2,%3,%u1\n\tstwcx. %2,%y0\n\tbne- $-12"
[(set_attr "length" "16,16,16")])
(define_insn "*sync_booldi_internal"
[(set (match_operand:DI 2 "gpc_reg_operand" "=&r,&r,&r")
(match_operator:DI 4 "boolean_or_operator"
[(match_operand:DI 0 "memory_operand" "+Z,Z,Z")
(match_operand:DI 1 "logical_operand" "r,K,JF")]))
(set (match_operand:DI 3 "gpc_reg_operand" "=&b,&b,&b") (match_dup 0))
(set (match_dup 0) (unspec_volatile:DI [(match_dup 4)] UNSPECV_SYNC_OP))
(clobber (match_scratch:CC 5 "=&x,&x,&x"))]
"TARGET_POWERPC64"
"@
ldarx %3,%y0\n\t%q4 %2,%3,%1\n\tstdcx. %2,%y0\n\tbne- $-12
ldarx %3,%y0\n\t%q4i %2,%3,%b1\n\tstdcx. %2,%y0\n\tbne- $-12
ldarx %3,%y0\n\t%q4is %2,%3,%u1\n\tstdcx. %2,%y0\n\tbne- $-12"
[(set_attr "length" "16,16,16")])
(define_insn "*sync_boolc<mode>_internal"
[(set (match_operand:GPR 2 "gpc_reg_operand" "=&r")
(match_operator:GPR 4 "boolean_operator"
[(not:GPR (match_operand:GPR 0 "memory_operand" "+Z"))
(match_operand:GPR 1 "gpc_reg_operand" "r")]))
(set (match_operand:GPR 3 "gpc_reg_operand" "=&b") (match_dup 0))
(set (match_dup 0) (unspec_volatile:GPR [(match_dup 4)] UNSPECV_SYNC_OP))
(clobber (match_scratch:CC 5 "=&x"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"<larx> %3,%y0\n\t%q4 %2,%1,%3\n\t<stcx> %2,%y0\n\tbne- $-12"
[(set_attr "length" "16")])
; This pattern could also take immediate values of operand 1,
; since the non-NOT version of the operator is used; but this is not
; very useful, since in practice operand 1 is a full 32-bit value.
@ -450,39 +540,15 @@
(match_operand:SI 5 "logical_operand" "rK"))
(match_operand:SI 1 "gpc_reg_operand" "r")]))
(set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0))
(set (match_dup 0) (unspec_volatile:SI [(match_dup 4)] UNSPECV_SYNC_OP))
(set (match_dup 0) (unspec:SI [(match_dup 4)] UNSPEC_SYNC_OP))
(clobber (match_scratch:CC 6 "=&x"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"lwarx %3,%y0\n\txor%I2 %2,%3,%5\n\t%q4 %2,%2,%1\n\tstwcx. %2,%y0\n\tbne- $-16"
[(set_attr "length" "20")])
(define_insn "*sync_boolc<mode>_internal2"
[(set (match_operand:GPR 2 "gpc_reg_operand" "=&r")
(match_operator:GPR 4 "boolean_operator"
[(not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r"))
(match_operand:GPR 0 "memory_operand" "+Z")]))
(set (match_operand:GPR 3 "gpc_reg_operand" "=&b") (match_dup 0))
(set (match_dup 0) (unspec_volatile:GPR [(match_dup 4)] UNSPECV_SYNC_OP))
(clobber (match_scratch:CC 5 "=&x"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"<larx> %3,%y0\n\t%q4 %2,%3,%1\n\t<stcx> %2,%y0\n\tbne- $-12"
[(set_attr "length" "16")])
(define_insn "*sync_boolcc<mode>_internal"
[(set (match_operand:GPR 2 "gpc_reg_operand" "=&r")
(match_operator:GPR 4 "boolean_operator"
[(not:GPR (match_operand:GPR 0 "memory_operand" "+Z"))
(not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r"))]))
(set (match_operand:GPR 3 "gpc_reg_operand" "=&b") (match_dup 0))
(set (match_dup 0) (unspec_volatile:GPR [(match_dup 4)] UNSPECV_SYNC_OP))
(clobber (match_scratch:CC 5 "=&x"))]
"TARGET_POWERPC && !PPC405_ERRATUM77"
"<larx> %3,%y0\n\t%q4 %2,%1,%3\n\t<stcx> %2,%y0\n\tbne- $-12"
[(set_attr "length" "16")])
(define_insn "isync"
[(set (mem:BLK (match_scratch 0 "X"))
(unspec_volatile:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPECV_ISYNC))]
(unspec_volatile:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPEC_ISYNC))]
""
"{ics|isync}"
[(set_attr "type" "isync")])
@ -501,7 +567,7 @@
; Some AIX assemblers don't accept lwsync, so we use a .long.
(define_insn "lwsync"
[(set (mem:BLK (match_scratch 0 "X"))
(unspec_volatile:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPECV_LWSYNC))]
(unspec_volatile:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPEC_LWSYNC))]
""
".long 0x7c2004ac"
[(set_attr "type" "sync")])