From 9f0076e54791675113e8916105fee88992a7bcbb Mon Sep 17 00:00:00 2001 From: David Edelsohn Date: Fri, 15 Jul 2005 01:44:38 +0000 Subject: [PATCH] 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): Same. (sync_lock_test_and_set): Same. (sync_, sync_nand): Only use rs6000_emit_sync for QImode and HImode, and not PPC405. (sync_old_, sync_old_nand): Same. (sync_new_, sync_new_nand): Same. (sync_{si,di}_internal): New. (sync_nand{si,di}_internal): New. (sync_old_{si,di}_internal): New. (sync_old_nand{si,di}_internal): New (sync_new_{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_internal): Delete. (sync_addshort_internal): Use unspec instead of unspec_volatile. (sync_sub_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_internal): Delete. (sync_boolcshort_internal): Use unspec instead of unspec_volatile. (sync_boolc_internal2): Delete. (sync_boolcc_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 --- gcc/ChangeLog | 44 +++ gcc/config/rs6000/rs6000-protos.h | 1 + gcc/config/rs6000/rs6000.c | 63 ++- gcc/config/rs6000/rs6000.md | 22 +- gcc/config/rs6000/sync.md | 632 +++++++++++++++++------------- 5 files changed, 462 insertions(+), 300 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c549b288208..68dec8a96c4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,47 @@ +2005-07-14 David Edelsohn + + * 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): Same. + (sync_lock_test_and_set): Same. + (sync_, sync_nand): Only use rs6000_emit_sync + for QImode and HImode, and not PPC405. + (sync_old_, sync_old_nand): Same. + (sync_new_, sync_new_nand): Same. + (sync_{si,di}_internal): New. + (sync_nand{si,di}_internal): New. + (sync_old_{si,di}_internal): New. + (sync_old_nand{si,di}_internal): New + (sync_new_{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_internal): Delete. + (sync_addshort_internal): Use unspec instead of unspec_volatile. + (sync_sub_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_internal): Delete. + (sync_boolcshort_internal): Use unspec instead of unspec_volatile. + (sync_boolc_internal2): Delete. + (sync_boolcc_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 * config/mips/mips.c (mips_canonicalize_comparison): Cast diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 20bdded1cca..14dd8e64553 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -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); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 1527e85253d..432fee78ef3 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -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. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 1381f7d7865..3cc613a82ed 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -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 ]) diff --git a/gcc/config/rs6000/sync.md b/gcc/config/rs6000/sync.md index cef64787b14..7678cf70a8e 100644 --- a/gcc/config/rs6000/sync.md +++ b/gcc/config/rs6000/sync.md @@ -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" [(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" - [(use (match_operand:INT1 0 "memory_operand" "")) - (use (match_operand:INT1 1 "add_operand" ""))] - "TARGET_POWERPC && !PPC405_ERRATUM77" +(define_expand "sync_" + [(parallel [(set (match_operand:INT1 0 "memory_operand" "") + (unspec:INT1 + [(FETCHOP:INT1 (match_dup 0) + (match_operand:INT1 1 "" ""))] + UNSPEC_ATOMIC)) + (clobber (scratch:INT1)) + (clobber (scratch:CC))])] + "TARGET_POWERPC" " { - rs6000_emit_sync (PLUS, mode, operands[0], operands[1], - NULL_RTX, NULL_RTX, true); - DONE; + if (mode != SImode && mode != DImode) + { + if (PPC405_ERRATUM77) + FAIL; + rs6000_emit_sync (, mode, operands[0], operands[1], + NULL_RTX, NULL_RTX, true); + DONE; + } }") -(define_expand "sync_sub" - [(use (match_operand:GPR 0 "memory_operand" "")) - (use (match_operand:GPR 1 "gpc_reg_operand" ""))] - "TARGET_POWERPC && !PPC405_ERRATUM77" - " +(define_insn_and_split "*sync_si_internal" + [(set (match_operand:SI 0 "memory_operand" "+Z") + (unspec:SI + [(FETCHOP:SI (match_dup 0) + (match_operand:SI 1 "" ""))] + 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, operands[0], operands[1], - NULL_RTX, NULL_RTX, true); + rs6000_split_atomic_op (, operands[0], operands[1], + NULL_RTX, NULL_RTX, operands[2]); DONE; -}") +}) -(define_expand "sync_ior" - [(use (match_operand:INT1 0 "memory_operand" "")) - (use (match_operand:INT1 1 "logical_operand" ""))] - "TARGET_POWERPC && !PPC405_ERRATUM77" - " +(define_insn_and_split "*sync_di_internal" + [(set (match_operand:DI 0 "memory_operand" "+Z") + (unspec:DI + [(FETCHOP:DI (match_dup 0) + (match_operand:DI 1 "" ""))] + 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, operands[0], operands[1], - NULL_RTX, NULL_RTX, true); + rs6000_split_atomic_op (, operands[0], operands[1], + NULL_RTX, NULL_RTX, operands[2]); DONE; -}") - -(define_expand "sync_and" - [(use (match_operand:INT1 0 "memory_operand" "")) - (use (match_operand:INT1 1 "and_operand" ""))] - "TARGET_POWERPC && !PPC405_ERRATUM77" - " -{ - rs6000_emit_sync (AND, mode, operands[0], operands[1], - NULL_RTX, NULL_RTX, true); - DONE; -}") - -(define_expand "sync_xor" - [(use (match_operand:INT1 0 "memory_operand" "")) - (use (match_operand:INT1 1 "logical_operand" ""))] - "TARGET_POWERPC && !PPC405_ERRATUM77" - " -{ - rs6000_emit_sync (XOR, mode, operands[0], operands[1], - NULL_RTX, NULL_RTX, true); - DONE; -}") +}) (define_expand "sync_nand" - [(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, - gen_rtx_NOT (mode, operands[0]), - operands[1], - NULL_RTX, NULL_RTX, true); - DONE; + if (mode != SImode && mode != DImode) + { + if (PPC405_ERRATUM77) + FAIL; + rs6000_emit_sync (AND, mode, + gen_rtx_NOT (mode, operands[0]), + operands[1], + NULL_RTX, NULL_RTX, true); + DONE; + } }") -(define_expand "sync_old_add" - [(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_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, 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_" + [(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 "" ""))] + UNSPEC_ATOMIC)) + (clobber (scratch:INT1)) + (clobber (scratch:CC))])] + "TARGET_POWERPC" + " +{ + if (mode != SImode && mode != DImode) + { + if (PPC405_ERRATUM77) + FAIL; + rs6000_emit_sync (, mode, operands[1], operands[2], + operands[0], NULL_RTX, true); + DONE; + } }") -(define_expand "sync_old_sub" - [(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_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 "" ""))] + 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, operands[1], operands[2], - operands[0], NULL_RTX, true); + rs6000_split_atomic_op (, operands[1], operands[2], + operands[0], NULL_RTX, operands[3]); DONE; -}") +}) -(define_expand "sync_old_ior" - [(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_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 "" ""))] + 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, operands[1], operands[2], - operands[0], NULL_RTX, true); + rs6000_split_atomic_op (, operands[1], operands[2], + operands[0], NULL_RTX, operands[3]); DONE; -}") - -(define_expand "sync_old_and" - [(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, operands[1], operands[2], - operands[0], NULL_RTX, true); - DONE; -}") - -(define_expand "sync_old_xor" - [(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, operands[1], operands[2], - operands[0], NULL_RTX, true); - DONE; -}") +}) (define_expand "sync_old_nand" - [(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, - gen_rtx_NOT (mode, operands[1]), - operands[2], - operands[0], NULL_RTX, true); - DONE; + if (mode != SImode && mode != DImode) + { + if (PPC405_ERRATUM77) + FAIL; + rs6000_emit_sync (AND, mode, + gen_rtx_NOT (mode, operands[1]), + operands[2], + operands[0], NULL_RTX, true); + DONE; + } }") -(define_expand "sync_new_add" - [(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_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_" + [(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "") + (FETCHOP:INT1 + (match_operand:INT1 1 "memory_operand" "") + (match_operand:INT1 2 "" ""))) + (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, operands[1], operands[2], - NULL_RTX, operands[0], true); - DONE; + if (mode != SImode && mode != DImode) + { + if (PPC405_ERRATUM77) + FAIL; + rs6000_emit_sync (, mode, operands[1], operands[2], + NULL_RTX, operands[0], true); + DONE; + } }") -(define_expand "sync_new_sub" - [(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_si_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r") + (FETCHOP:SI + (match_operand:SI 1 "memory_operand" "+Z") + (match_operand:SI 2 "" ""))) + (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, operands[1], operands[2], - NULL_RTX, operands[0], true); + rs6000_split_atomic_op (, operands[1], operands[2], + NULL_RTX, operands[0], operands[3]); DONE; -}") +}) -(define_expand "sync_new_ior" - [(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_di_internal" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r") + (FETCHOP:DI + (match_operand:DI 1 "memory_operand" "+Z") + (match_operand:DI 2 "" ""))) + (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, operands[1], operands[2], - NULL_RTX, operands[0], true); + rs6000_split_atomic_op (, operands[1], operands[2], + NULL_RTX, operands[0], operands[3]); DONE; -}") - -(define_expand "sync_new_and" - [(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, operands[1], operands[2], - NULL_RTX, operands[0], true); - DONE; -}") - -(define_expand "sync_new_xor" - [(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, operands[1], operands[2], - NULL_RTX, operands[0], true); - DONE; -}") +}) (define_expand "sync_new_nand" - [(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, - gen_rtx_NOT (mode, operands[1]), - operands[2], - NULL_RTX, operands[0], true); - DONE; + if (mode != SImode && mode != DImode) + { + if (PPC405_ERRATUM77) + FAIL; + rs6000_emit_sync (AND, mode, + gen_rtx_NOT (mode, operands[1]), + operands[2], + NULL_RTX, operands[0], true); + DONE; + } }") +(define_insn_and_split "*sync_new_nand_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 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_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" - "@ - %3,%y0\n\tadd%I1 %2,%3,%1\n\t %2,%y0\n\tbne- $-12 - %3,%y0\n\taddis %2,%3,%v1\n\t %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_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" - " %3,%y0\n\tsubf %2,%1,%3\n\t %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_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" - " %3,%y0\n\t%q4 %2,%1,%3\n\t %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_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" - " %3,%y0\n\t%q4 %2,%3,%1\n\t %2,%y0\n\tbne- $-12" - [(set_attr "length" "16")]) - -(define_insn "*sync_boolcc_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" - " %3,%y0\n\t%q4 %2,%1,%3\n\t %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")])