From 915167f5a5a8f8f5a4107b7fa7df7fe5aae66365 Mon Sep 17 00:00:00 2001 From: Geoffrey Keating Date: Thu, 21 Apr 2005 21:13:41 +0000 Subject: [PATCH] Index: ChangeLog 2005-04-21 Geoffrey Keating * config/rs6000/rs6000-protos.h (rs6000_emit_sync): New. * config/rs6000/rs6000.c (rs6000_emit_vector_compare): Use gen_rtx_* not gen_rtx_fmt_*. (rs6000_emit_vector_select): Likewise. (rs6000_emit_sync): New. * config/rs6000/rs6000.md (GPR, INT, INT1): New mode macros. (larx, stcx, cmp): New mode substitutions. (UNSPEC_SYNC, UNSPEC_SYNC_OP, UNSPEC_SYNC_SWAP, UNSPEC_LWSYNC, UNSPEC_ISYNC): New constants. (rlwinm): Give name. (memory_barrier, isync, lwsync): New insns. (sync_compare_and_swap, sync_lock_test_and_set): New insn. (sync_lock_release): New expander. (sync_add, sync_sub, sync_ior, sync_and, sync_xor, sync_nand, sync_old_add, sync_old_sub, sync_old_ior, sync_old_and, sync_old_xor, sync_old_nand, sync_new_add, sync_new_sub, sync_new_ior, sync_new_and, sync_new_xor, sync_new_nand): New expanders. (sync_add_internal, sync_addshort_internal, sync_sub_internal, sync_andsi_internal, sync_anddi_internal, sync_boolsi_internal, sync_booldi_internal, sync_boolc_internal, sync_boolc_internal2, sync_boolcc_internal): New insns. * doc/md.texi (Standard Names): sync_compare_and_swap's operand 0 is the memory before, not after, the operation. Clarify barrier requirements. Index: testsuite/ChangeLog 2005-04-21 Geoffrey Keating * lib/target-supports.exp (check_effective_target_sync_int_long): Add powerpc*. From-SVN: r98527 --- gcc/ChangeLog | 30 ++ gcc/config/rs6000/rs6000-protos.h | 2 + gcc/config/rs6000/rs6000.c | 195 ++++++++++- gcc/config/rs6000/rs6000.md | 456 +++++++++++++++++++++++++- gcc/doc/md.texi | 30 +- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/lib/target-supports.exp | 5 +- 7 files changed, 698 insertions(+), 25 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 811ff1deb61..b182ad3e093 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2005-04-21 Geoffrey Keating + + * config/rs6000/rs6000-protos.h (rs6000_emit_sync): New. + * config/rs6000/rs6000.c (rs6000_emit_vector_compare): Use + gen_rtx_* not gen_rtx_fmt_*. + (rs6000_emit_vector_select): Likewise. + (rs6000_emit_sync): New. + * config/rs6000/rs6000.md (GPR, INT, INT1): New mode macros. + (larx, stcx, cmp): New mode substitutions. + (UNSPEC_SYNC, UNSPEC_SYNC_OP, UNSPEC_SYNC_SWAP, UNSPEC_LWSYNC, + UNSPEC_ISYNC): New constants. + (rlwinm): Give name. + (memory_barrier, isync, lwsync): New insns. + (sync_compare_and_swap, sync_lock_test_and_set): New insn. + (sync_lock_release): New expander. + (sync_add, sync_sub, sync_ior, sync_and, + sync_xor, sync_nand, sync_old_add, + sync_old_sub, sync_old_ior, sync_old_and, + sync_old_xor, sync_old_nand, sync_new_add, + sync_new_sub, sync_new_ior, sync_new_and, + sync_new_xor, sync_new_nand): New expanders. + (sync_add_internal, sync_addshort_internal, + sync_sub_internal, sync_andsi_internal, sync_anddi_internal, + sync_boolsi_internal, sync_booldi_internal, sync_boolc_internal, + sync_boolc_internal2, sync_boolcc_internal): New insns. + + * doc/md.texi (Standard Names): sync_compare_and_swap's operand 0 + is the memory before, not after, the operation. Clarify + barrier requirements. + 2005-04-21 Nathan Sidwell * cfghooks.h (struct cfg_hooks): Reword comments to avoid 'abort'. diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 72c205bba36..63ffe4fb9fc 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -80,6 +80,8 @@ extern rtx rs6000_emit_set_const (rtx, enum machine_mode, rtx, int); extern int rs6000_emit_cmove (rtx, rtx, rtx, rtx); 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 output_toc (FILE *, rtx, int, enum machine_mode); extern void rs6000_initialize_trampoline (rtx, rtx, rtx); extern rtx rs6000_longcall_ref (rtx); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index e3ef7452e4c..fc4683d388b 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -10620,12 +10620,10 @@ rs6000_emit_vector_compare (enum rtx_code rcode, } } - emit_insn (gen_rtx_fmt_ee (SET, - VOIDmode, - mask, - gen_rtx_fmt_Ei (UNSPEC, dest_mode, - gen_rtvec (2, op0, op1), - vec_cmp_insn))); + emit_insn (gen_rtx_SET (VOIDmode, mask, + gen_rtx_UNSPEC (dest_mode, + gen_rtvec (2, op0, op1), + vec_cmp_insn))); if (dmode != dest_mode) { rtx temp = gen_reg_rtx (dest_mode); @@ -10676,10 +10674,10 @@ rs6000_emit_vector_select (rtx dest, rtx op1, rtx op2, rtx mask) /* For each vector element, select op1 when mask is 1 otherwise select op2. */ - t = gen_rtx_fmt_ee (SET, VOIDmode, temp, - gen_rtx_fmt_Ei (UNSPEC, dest_mode, - gen_rtvec (3, op2, op1, mask), - vsel_insn_index)); + t = gen_rtx_SET (VOIDmode, temp, + gen_rtx_UNSPEC (dest_mode, + gen_rtvec (3, op2, op1, mask), + vsel_insn_index)); emit_insn (t); emit_move_insn (dest, temp); return; @@ -10960,6 +10958,183 @@ rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1) emit_move_insn (dest, target); } +/* Emit instructions to perform a load-reserved/store-conditional operation. + The operation performed is an atomic + (set M (CODE:MODE M OP)) + If not NULL, BEFORE is atomically set to M before the operation, and + AFTER is set to M after the operation (that is, (CODE:MODE M OP)). + If SYNC_P then a memory barrier is emitted before the operation. + Either OP or M may be wrapped in a NOT operation. */ + +void +rs6000_emit_sync (enum rtx_code code, enum machine_mode mode, + rtx m, rtx op, rtx before_param, rtx after_param, + bool sync_p) +{ + enum machine_mode used_mode; + rtx the_op, set_before, set_after, set_atomic, cc_scratch, before, after; + rtx used_m; + rtvec vec; + HOST_WIDE_INT imask = GET_MODE_MASK (mode); + rtx shift = NULL_RTX; + + if (sync_p) + emit_insn (gen_memory_barrier ()); + + if (GET_CODE (m) == NOT) + used_m = XEXP (m, 0); + else + used_m = m; + + /* If this is smaller than SImode, we'll have to use SImode with + adjustments. */ + if (mode == QImode || mode == HImode) + { + rtx newop, oldop; + + if (MEM_ALIGN (used_m) >= 32) + { + int ishift = 0; + if (BYTES_BIG_ENDIAN) + ishift = GET_MODE_BITSIZE (SImode) - GET_MODE_BITSIZE (mode); + + shift = GEN_INT (ishift); + } + else + { + rtx addrSI, aligned_addr; + + addrSI = force_reg (SImode, gen_lowpart_common (SImode, + XEXP (used_m, 0))); + shift = gen_reg_rtx (SImode); + + emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3), + GEN_INT (0x18))); + + aligned_addr = expand_binop (Pmode, and_optab, + XEXP (used_m, 0), + GEN_INT (-4), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + used_m = change_address (used_m, SImode, aligned_addr); + set_mem_align (used_m, 32); + /* It's safe to keep the old alias set of USED_M, because + the operation is atomic and only affects the original + USED_M. */ + if (GET_CODE (m) == NOT) + m = gen_rtx_NOT (SImode, used_m); + else + m = used_m; + } + + if (GET_CODE (op) == NOT) + { + oldop = lowpart_subreg (SImode, XEXP (op, 0), mode); + oldop = gen_rtx_NOT (SImode, oldop); + } + else + oldop = lowpart_subreg (SImode, op, mode); + switch (code) + { + case IOR: + case XOR: + newop = expand_binop (SImode, and_optab, + oldop, GEN_INT (imask), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + emit_insn (gen_ashlsi3 (newop, newop, shift)); + break; + + case AND: + newop = expand_binop (SImode, ior_optab, + oldop, GEN_INT (~imask), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + emit_insn (gen_ashlsi3 (newop, newop, shift)); + break; + + case PLUS: + { + rtx mask; + + newop = expand_binop (SImode, and_optab, + oldop, GEN_INT (imask), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + emit_insn (gen_ashlsi3 (newop, newop, shift)); + + mask = gen_reg_rtx (SImode); + 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); + newop = gen_rtx_IOR (SImode, newop, + gen_rtx_AND (SImode, + gen_rtx_NOT (SImode, mask), + m)); + break; + } + + default: + gcc_unreachable (); + } + + op = newop; + used_mode = SImode; + before = gen_reg_rtx (used_mode); + after = gen_reg_rtx (used_mode); + } + else + { + used_mode = mode; + before = before_param; + after = after_param; + + if (before == NULL_RTX) + before = gen_reg_rtx (used_mode); + if (after == NULL_RTX) + after = gen_reg_rtx (used_mode); + } + + if (code == PLUS && 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); + else + the_op = gen_rtx_fmt_ee (code, used_mode, m, op); + + 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 (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) + vec = gen_rtvec (5, set_after, set_before, set_atomic, cc_scratch, + gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode))); + else + vec = gen_rtvec (4, set_after, set_before, set_atomic, cc_scratch); + emit_insn (gen_rtx_PARALLEL (VOIDmode, vec)); + + /* Shift and mask the return values properly. */ + if (used_mode != mode && before_param) + { + emit_insn (gen_lshrsi3 (before, before, shift)); + convert_move (before_param, before, 1); + } + + if (used_mode != mode && after_param) + { + emit_insn (gen_lshrsi3 (after, after, shift)); + convert_move (after_param, after, 1); + } + + /* The previous sequence will end with a branch that's dependent on + the conditional store, so placing an isync will ensure that no + other instructions (especially, no load or store instructions) + can start before the atomic operation completes. */ + if (sync_p) + emit_insn (gen_isync ()); +} + /* Emit instructions to move SRC to DST. Called by splitters for multi-register moves. It will emit at most one instruction for each register that is accessed; that is, it won't emit li/lis pairs diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index d97d3be1077..aabe7cb6e1d 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -52,6 +52,11 @@ (UNSPEC_FIX_TRUNC_TF 30) ; fadd, rounding towards zero (UNSPEC_MV_CR_GT 31) ; move_from_CR_eq_bit (UNSPEC_STFIWX 32) + (UNSPEC_SYNC 33) + (UNSPEC_SYNC_OP 34) + (UNSPEC_SYNC_SWAP 35) + (UNSPEC_LWSYNC 36) + (UNSPEC_ISYNC 37) ]) ;; @@ -108,10 +113,28 @@ (include "darwin.md") -;; This mode macro allows :P to be used for patterns that operate on -;; pointer-sized quantities. Exactly one of the two alternatives will match. +;; Mode macros + +; This mode macro allows :GPR to be used to indicate the allowable size +; of whole values in GPRs. +(define_mode_macro GPR [SI (DI "TARGET_POWERPC64")]) + +; Any supported integer mode +(define_mode_macro INT [QI HI SI DI TI]) + +; Any supported integer mode that fits in one register +(define_mode_macro INT1 [QI HI SI (DI "TARGET_POWERPC64")]) + +; This mode macro allows :P to be used for patterns that operate on +; pointer-sized quantities. Exactly one of the two alternatives will match. (define_mode_macro P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) +; Various instructions that come in SI and DI forms. +(define_mode_attr larx [(SI "lwarx") (DI "ldarx")]) +(define_mode_attr stcx [(SI "stwcx.") (DI "stdcx.")]) +(define_mode_attr cmp [(SI "cmpw") (DI "cmpd")]) + + ;; Start with fixed-point load and store insns. Here we put only the more ;; complex forms. Basic data transfer is done later. @@ -3742,7 +3765,7 @@ (const_int 0)))] "") -(define_insn "" +(define_insn "rlwinm" [(set (match_operand:SI 0 "gpc_reg_operand" "=r") (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r") (match_operand:SI 2 "const_int_operand" "i")) @@ -14733,6 +14756,433 @@ return INTVAL (operands[1]) ? \"dcbtst %a0\" : \"dcbt %a0\"; }" [(set_attr "type" "load")]) + +; Atomic instructions + +(define_insn "memory_barrier" + [(set (mem:BLK (match_scratch 0 "X")) + (unspec:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPEC_SYNC))] + "" + "{ics|sync}") + +(define_insn "sync_compare_and_swap" + [(set (match_operand:GPR 1 "memory_operand" "+Z") + (unspec:GPR [(match_dup 1) + (match_operand:GPR 2 "reg_or_short_operand" "rI") + (match_operand:GPR 3 "gpc_reg_operand" "r")] + UNSPEC_SYNC_SWAP)) + (set (match_operand:GPR 0 "gpc_reg_operand" "=&r") (match_dup 1)) + (set (mem:BLK (match_scratch 5 "X")) + (unspec:BLK [(mem:BLK (match_scratch 6 "X"))] UNSPEC_SYNC)) + (clobber (match_scratch:CC 4 "=&x"))] + "TARGET_POWERPC" + "sync\n0:\t %0,%y1\n\t%I2 %0,%2\n\tbne- 1f\n\t %3,%y1\n\tbne- 0b\n\t1:\tisync" + [(set_attr "length" "28")]) + +(define_expand "sync_add" + [(use (match_operand:INT1 0 "memory_operand" "")) + (use (match_operand:INT1 1 "add_operand" ""))] + "TARGET_POWERPC" + " +{ + rs6000_emit_sync (PLUS, 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" + " +{ + rs6000_emit_sync (MINUS, mode, operands[0], operands[1], + NULL_RTX, NULL_RTX, true); + DONE; +}") + +(define_expand "sync_ior" + [(use (match_operand:INT1 0 "memory_operand" "")) + (use (match_operand:INT1 1 "logical_operand" ""))] + "TARGET_POWERPC" + " +{ + rs6000_emit_sync (IOR, mode, operands[0], operands[1], + NULL_RTX, NULL_RTX, true); + DONE; +}") + +(define_expand "sync_and" + [(use (match_operand:INT1 0 "memory_operand" "")) + (use (match_operand:INT1 1 "and_operand" ""))] + "TARGET_POWERPC" + " +{ + 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" + " +{ + 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" + " +{ + 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" + " +{ + rs6000_emit_sync (PLUS, 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" + " +{ + rs6000_emit_sync (MINUS, mode, operands[1], operands[2], + operands[0], NULL_RTX, true); + 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" + " +{ + rs6000_emit_sync (IOR, mode, operands[1], operands[2], + operands[0], NULL_RTX, true); + 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" + " +{ + 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" + " +{ + 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" + " +{ + 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" + " +{ + rs6000_emit_sync (PLUS, 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" + " +{ + rs6000_emit_sync (MINUS, mode, operands[1], operands[2], + NULL_RTX, operands[0], true); + 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" + " +{ + rs6000_emit_sync (IOR, mode, operands[1], operands[2], + NULL_RTX, operands[0], true); + 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" + " +{ + 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" + " +{ + 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" + " +{ + rs6000_emit_sync (AND, mode, + gen_rtx_NOT (mode, operands[1]), + operands[2], + NULL_RTX, operands[0], true); + DONE; +}") + +; 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:GPR [(plus:GPR (match_dup 0) (match_dup 1))] + UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 4 "=&x,&x"))] + "TARGET_POWERPC" + "@ + 0:\t %3,%y0\n\tadd%I1 %2,%3,%1\n\t %2,%y0\n\tbne- 0b + 0:\t %3,%y0\n\taddis %2,%3,%v1\n\t %2,%y0\n\tbne- 0b" + [(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") + (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 (plus: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" + "0:\tlwarx %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- 0b" + [(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:GPR [(minus:GPR (match_dup 0) (match_dup 1))] + UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 4 "=&x"))] + "TARGET_POWERPC" + "0:\t %3,%y0\n\tsubf %2,%1,%3\n\t %2,%y0\n\tbne- 0b" + [(set_attr "length" "16")]) + +(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:SI [(and:SI (match_dup 0) (match_dup 1))] + UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 4 "=&x,&x,&x,&x"))] + "TARGET_POWERPC" + "@ + 0:\tlwarx %3,%y0\n\tand %2,%3,%1\n\tstwcx. %2,%y0\n\tbne- 0b + 0:\tlwarx %3,%y0\n\trlwinm %2,%3,0,%m1,%M1\n\tstwcx. %2,%y0\n\tbne- 0b + 0:\tlwarx %3,%y0\n\tandi. %2,%3,%b1\n\tstwcx. %2,%y0\n\tbne- 0b + 0:\tlwarx %3,%y0\n\tandis. %2,%3,%u1\n\tstwcx. %2,%y0\n\tbne- 0b" + [(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:DI [(and:DI (match_dup 0) (match_dup 1))] + UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 4 "=&x,&x,&x,&x,&x"))] + "TARGET_POWERPC64" + "@ + 0:\tldarx %3,%y0\n\tand %2,%3,%1\n\tstdcx. %2,%y0\n\tbne- 0b + 0:\tldarx %3,%y0\n\trldic%B1 %2,%3,0,%S1\n\tstdcx. %2,%y0\n\tbne- 0b + 0:\tldarx %3,%y0\n\trlwinm %2,%3,0,%m1,%M1\n\tstdcx. %2,%y0\n\tbne- 0b + 0:\tldarx %3,%y0\n\tandi. %2,%3,%b1\n\tstdcx. %2,%y0\n\tbne- 0b + 0:\tldarx %3,%y0\n\tandis. %2,%3,%b1\n\tstdcx. %2,%y0\n\tbne- 0b" + [(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:SI [(match_dup 4)] UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 5 "=&x,&x,&x"))] + "TARGET_POWERPC" + "@ + 0:\tlwarx %3,%y0\n\t%q4 %2,%3,%1\n\tstwcx. %2,%y0\n\tbne- 0b + 0:\tlwarx %3,%y0\n\t%q4i %2,%3,%b1\n\tstwcx. %2,%y0\n\tbne- 0b + 0:\tlwarx %3,%y0\n\t%q4is %2,%3,%u1\n\tstwcx. %2,%y0\n\tbne- 0b" + [(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:DI [(match_dup 4)] UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 5 "=&x,&x,&x"))] + "TARGET_POWERPC64" + "@ + 0:\tldarx %3,%y0\n\t%q4 %2,%3,%1\n\tstdcx. %2,%y0\n\tbne- 0b + 0:\tldarx %3,%y0\n\t%q4i %2,%3,%b1\n\tstdcx. %2,%y0\n\tbne- 0b + 0:\tldarx %3,%y0\n\t%q4is %2,%3,%u1\n\tstdcx. %2,%y0\n\tbne- 0b" + [(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:GPR [(match_dup 4)] UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 5 "=&x"))] + "TARGET_POWERPC" + "0:\t %3,%y0\n\t%q4 %2,%1,%3\n\t %2,%y0\n\tbne- 0b" + [(set_attr "length" "16")]) + +(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:GPR [(match_dup 4)] UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 5 "=&x"))] + "TARGET_POWERPC" + "0:\t %3,%y0\n\t%q4 %2,%3,%1\n\t %2,%y0\n\tbne- 0b" + [(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:GPR [(match_dup 4)] UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 5 "=&x"))] + "TARGET_POWERPC" + "0:\t %3,%y0\n\t%q4 %2,%1,%3\n\t %2,%y0\n\tbne- 0b" + [(set_attr "length" "16")]) + +(define_insn "isync" + [(set (mem:BLK (match_scratch 0 "X")) + (unspec:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPEC_ISYNC))] + "TARGET_POWERPC" + "isync") + +(define_insn "sync_lock_test_and_set" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=&r") + (match_operand:GPR 1 "memory_operand" "+Z")) + (set (match_dup 1) (unspec:GPR [(match_operand:GPR 2 "gpc_reg_operand" "r")] + UNSPEC_SYNC_OP)) + (clobber (match_scratch:CC 3 "=&x")) + (set (mem:BLK (match_scratch 4 "X")) + (unspec:BLK [(mem:BLK (match_scratch 5 "X"))] UNSPEC_ISYNC))] + "TARGET_POWERPC" + "0:\t %0,%y1\n\t %2,%y1\n\tbne- 0b\n\tisync" + [(set_attr "length" "16")]) + +(define_expand "sync_lock_release" + [(use (match_operand:INT 0 "memory_operand"))] + "" + " +{ + emit_insn (gen_lwsync ()); + emit_move_insn (operands[0], CONST0_RTX (mode)); + DONE; +}") + +(define_insn "lwsync" + [(set (mem:BLK (match_scratch 0 "X")) + (unspec:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPEC_LWSYNC))] + "" + "lwsync") + + (include "altivec.md") (include "spe.md") diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 42936116071..b29d7e02f98 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -3952,14 +3952,16 @@ operation. Operand 1 is the memory on which the atomic operation is performed. Operand 2 is the ``old'' value to be compared against the current contents of the memory location. Operand 3 is the ``new'' value to store in the memory if the compare succeeds. Operand 0 is the result -of the operation; it should contain the current contents of the memory -after the operation. If the compare succeeds, this should obviously be -a copy of operand 3. +of the operation; it should contain the contents of the memory +before the operation. If the compare succeeds, this should obviously be +a copy of operand 2. This pattern must show that both operand 0 and operand 1 are modified. -This pattern must issue any memory barrier instructions such that the -pattern as a whole acts as a full barrier. +This pattern must issue any memory barrier instructions such that all +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}} @@ -3991,8 +3993,10 @@ Operand 1 is the second operand to the binary operator. The ``nand'' operation is @code{op0 & ~op1}. -This pattern must issue any memory barrier instructions such that the -pattern as a whole acts as a full barrier. +This pattern must issue any memory barrier instructions such that all +memory operations before the atomic operation occur before the atomic +operation and all memory operations after the atomic operation occur +after the atomic operation. If these patterns are not defined, the operation will be constructed from a compare-and-swap operation, if defined. @@ -4013,8 +4017,10 @@ Operand 0 is the result value, operand 1 is the memory on which the atomic operation is performed, and operand 2 is the second operand to the binary operator. -This pattern must issue any memory barrier instructions such that the -pattern as a whole acts as a full barrier. +This pattern must issue any memory barrier instructions such that all +memory operations before the atomic operation occur before the atomic +operation and all memory operations after the atomic operation occur +after the atomic operation. If these patterns are not defined, the operation will be constructed from a compare-and-swap operation, if defined. @@ -4052,7 +4058,8 @@ an atomic test-and-set bit operation. The result operand should contain The true contents of the memory operand are implementation defined. This pattern must issue any memory barrier instructions such that the -pattern as a whole acts as an acquire barrier. +pattern as a whole acts as an acquire barrier, that is all memory +operations after the pattern do not occur until the lock is acquired. If this pattern is not defined, the operation will be constructed from a compare-and-swap operation, if defined. @@ -4065,7 +4072,8 @@ This pattern, if defined, releases a lock set by that contains the lock. This pattern must issue any memory barrier instructions such that the -pattern as a whole acts as a release barrier. +pattern as a whole acts as a release barrier, that is the lock is +released only after all previous memory operations have completed. If this pattern is not defined, then a @code{memory_barrier} pattern will be emitted, followed by a store of zero to the memory operand. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 35e33cb6cea..61c9bf8c8bd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-04-21 Geoffrey Keating + + * lib/target-supports.exp (check_effective_target_sync_int_long): + Add powerpc*. + 2005-04-21 Richard Sandiford * gcc.target/mips/branch-1.c: New test. diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index ab9953f8bed..4356aba3cbc 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -883,10 +883,13 @@ proc check_effective_target_sync_int_long { } { verbose "check_effective_target_sync_int_long: using cached result" 2 } else { set et_sync_int_long_saved 0 +# This is intentionally powerpc but not rs6000, rs6000 doesn't have the +# load-reserved/store-conditional instructions. if { [istarget ia64-*-*] || [istarget i?86-*-*] || [istarget x86_64-*-*] - || [istarget alpha*-*-*] } { + || [istarget alpha*-*-*] + || [istarget powerpc*-*-*] } { set et_sync_int_long_saved 1 } } -- 2.30.2