From 0b196b187b335a83b98c9dcad22b75ba84c455b9 Mon Sep 17 00:00:00 2001 From: Richard Henderson <rth@redhat.com> Date: Mon, 18 Apr 2005 09:13:00 -0700 Subject: [PATCH] alpha.c (alpha_split_atomic_op): New. * config/alpha/alpha.c (alpha_split_atomic_op): New. (alphaev5_insn_pipe): Add LD_L, ST_C, MB types. (alphaev4_insn_pipe): Likewise. Correct IST and LDSYM pipes. * config/alpha/alpha-protos.h: Update. * config/alpha/alpha.md (UNSPECV_MB, UNSPECV_LL, UNSPECV_SC): New. (UNSPECV_ATOMIC, UNSPECV_CMPXCHG, UNSPECV_XCHG): New. (attr type): Add ld_l, st_c, mb. (andsi_internal, andnotsi3, iorsi_internal, one_cmplsi_internal, iornotsi3, xorsi_internal, xornotsi3): New. * config/alpha/ev4.md (ev4_ld): Add ld_l. (ev4_ist_c, ev4_mb): New. * config/alpha/ev5.md (ev5_st): Add st_c, mb. (ev5_ld_l): New. * config/alpha/ev6.md (ev6_ild): Add ld_l. (ev6_ist): Add st_c. (ev6_mb): New. * config/alpha/sync.md: New file. From-SVN: r98328 --- gcc/ChangeLog | 20 ++ gcc/config/alpha/alpha-protos.h | 1 + gcc/config/alpha/alpha.c | 68 ++++++- gcc/config/alpha/alpha.md | 81 +++++++- gcc/config/alpha/ev4.md | 17 +- gcc/config/alpha/ev5.md | 9 +- gcc/config/alpha/ev6.md | 9 +- gcc/config/alpha/sync.md | 319 ++++++++++++++++++++++++++++++++ 8 files changed, 513 insertions(+), 11 deletions(-) create mode 100644 gcc/config/alpha/sync.md diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eb81e48020a3..335f5ffaf682 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2005-04-18 Richard Henderson <rth@redhat.com> + + * config/alpha/alpha.c (alpha_split_atomic_op): New. + (alphaev5_insn_pipe): Add LD_L, ST_C, MB types. + (alphaev4_insn_pipe): Likewise. Correct IST and LDSYM pipes. + * config/alpha/alpha-protos.h: Update. + * config/alpha/alpha.md (UNSPECV_MB, UNSPECV_LL, UNSPECV_SC): New. + (UNSPECV_ATOMIC, UNSPECV_CMPXCHG, UNSPECV_XCHG): New. + (attr type): Add ld_l, st_c, mb. + (andsi_internal, andnotsi3, iorsi_internal, one_cmplsi_internal, + iornotsi3, xorsi_internal, xornotsi3): New. + * config/alpha/ev4.md (ev4_ld): Add ld_l. + (ev4_ist_c, ev4_mb): New. + * config/alpha/ev5.md (ev5_st): Add st_c, mb. + (ev5_ld_l): New. + * config/alpha/ev6.md (ev6_ild): Add ld_l. + (ev6_ist): Add st_c. + (ev6_mb): New. + * config/alpha/sync.md: New file. + 2005-04-18 Richard Henderson <rth@redhat.com> * builtins.c (expand_builtin_sync_operation): Fold nand to and diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index 6c2be06c02f8..dc2b027108bf 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -101,6 +101,7 @@ extern rtx alpha_emit_setcc (enum rtx_code); extern int alpha_split_conditional_move (enum rtx_code, rtx, rtx, rtx, rtx); extern void alpha_emit_xfloating_arith (enum rtx_code, rtx[]); extern void alpha_emit_xfloating_cvt (enum rtx_code, rtx[]); +extern void alpha_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx); #endif extern rtx alpha_need_linkage (const char *, int); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 71ba4496f174..895189b2770e 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -4469,6 +4469,64 @@ alpha_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx), emit_insn ((*gen) (op0, op1, op2)); } + +/* 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 +alpha_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, cond, x; + rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1); + + emit_insn (gen_memory_barrier ()); + + label = gen_label_rtx (); + emit_label (label); + label = gen_rtx_LABEL_REF (DImode, label); + + if (before == NULL) + before = scratch; + + if (mode == SImode) + emit_insn (gen_load_locked_si (before, mem)); + else if (mode == DImode) + emit_insn (gen_load_locked_di (before, mem)); + else + gcc_unreachable (); + + if (code == NOT) + { + x = gen_rtx_NOT (mode, val); + x = gen_rtx_AND (mode, x, before); + } + else + x = gen_rtx_fmt_ee (code, mode, before, val); + + emit_insn (gen_rtx_SET (VOIDmode, scratch, x)); + if (after) + emit_insn (gen_rtx_SET (VOIDmode, after, copy_rtx (x))); + + cond = gen_rtx_REG (DImode, REGNO (scratch)); + if (mode == SImode) + emit_insn (gen_store_conditional_si (cond, mem, scratch)); + else if (mode == DImode) + emit_insn (gen_store_conditional_di (cond, mem, scratch)); + else + gcc_unreachable (); + + x = gen_rtx_EQ (DImode, cond, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx); + x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x)); + REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX); + + emit_insn (gen_memory_barrier ()); +} /* Adjust the cost of a scheduling dependency. Return the new cost of a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ @@ -8479,21 +8537,22 @@ alphaev4_insn_pipe (rtx insn) switch (get_attr_type (insn)) { case TYPE_ILD: + case TYPE_LDSYM: case TYPE_FLD: + case TYPE_LD_L: return EV4_IBX; - case TYPE_LDSYM: case TYPE_IADD: case TYPE_ILOG: case TYPE_ICMOV: case TYPE_ICMP: - case TYPE_IST: case TYPE_FST: case TYPE_SHIFT: case TYPE_IMUL: case TYPE_FBR: return EV4_IB0; + case TYPE_IST: case TYPE_MISC: case TYPE_IBR: case TYPE_JSR: @@ -8503,6 +8562,8 @@ alphaev4_insn_pipe (rtx insn) case TYPE_FADD: case TYPE_FDIV: case TYPE_FMUL: + case TYPE_ST_C: + case TYPE_MB: return EV4_IB1; default: @@ -8535,6 +8596,9 @@ alphaev5_insn_pipe (rtx insn) case TYPE_IMUL: case TYPE_MISC: case TYPE_MVI: + case TYPE_LD_L: + case TYPE_ST_C: + case TYPE_MB: return EV5_E0; case TYPE_IBR: diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md index 208161ba9b75..644b5b0653f1 100644 --- a/gcc/config/alpha/alpha.md +++ b/gcc/config/alpha/alpha.md @@ -76,6 +76,12 @@ (UNSPECV_SET_TP 12) (UNSPECV_RPCC 13) (UNSPECV_SETJMPR_ER 14) ; builtin_setjmp_receiver fragment + (UNSPECV_MB 15) + (UNSPECV_LL 16) ; load-locked + (UNSPECV_SC 17) ; store-conditional + (UNSPECV_ATOMIC 18) + (UNSPECV_CMPXCHG 19) + (UNSPECV_XCHG 20) ]) ;; Where necessary, the suffixes _le and _be are used to distinguish between @@ -97,7 +103,8 @@ (define_attr "type" "ild,fld,ldsym,ist,fst,ibr,callpal,fbr,jsr,iadd,ilog,shift,icmov,fcmov, - icmp,imul,fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi,none" + icmp,imul,fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,mb,ld_l,st_c, + multi,none" (const_string "iadd")) ;; Describe a user's asm statement. @@ -1100,7 +1107,20 @@ [(set_attr "type" "jsr") (set_attr "length" "8")]) -;; Next are the basic logical operations. These only exist in DImode. +;; Next are the basic logical operations. We only expose the DImode operations +;; to the rtl expanders, but SImode versions exist for combine as well as for +;; the atomic operation splitters. + +(define_insn "*andsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (and:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ,rJ") + (match_operand:SI 2 "and_operand" "rI,N,MH")))] + "" + "@ + and %r1,%2,%0 + bic %r1,%N2,%0 + zapnot %r1,%m2,%0" + [(set_attr "type" "ilog,ilog,shift")]) (define_insn "anddi3" [(set (match_operand:DI 0 "register_operand" "=r,r,r") @@ -1275,6 +1295,14 @@ "zapnot %1,15,%0" [(set_attr "type" "shift")]) +(define_insn "*andnotsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (not:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")) + (match_operand:SI 2 "reg_or_0_operand" "rJ")))] + "" + "bic %r2,%1,%0" + [(set_attr "type" "ilog")]) + (define_insn "andnotdi3" [(set (match_operand:DI 0 "register_operand" "=r") (and:DI (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")) @@ -1283,6 +1311,16 @@ "bic %r2,%1,%0" [(set_attr "type" "ilog")]) +(define_insn "*iorsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ior:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:SI 2 "or_operand" "rI,N")))] + "" + "@ + bis %r1,%2,%0 + ornot %r1,%N2,%0" + [(set_attr "type" "ilog")]) + (define_insn "iordi3" [(set (match_operand:DI 0 "register_operand" "=r,r") (ior:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ") @@ -1293,6 +1331,13 @@ ornot %r1,%N2,%0" [(set_attr "type" "ilog")]) +(define_insn "*one_cmplsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")))] + "" + "ornot $31,%1,%0" + [(set_attr "type" "ilog")]) + (define_insn "one_cmpldi2" [(set (match_operand:DI 0 "register_operand" "=r") (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")))] @@ -1300,7 +1345,15 @@ "ornot $31,%1,%0" [(set_attr "type" "ilog")]) -(define_insn "*iornot" +(define_insn "*iornotsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (not:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")) + (match_operand:SI 2 "reg_or_0_operand" "rJ")))] + "" + "ornot %r2,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*iornotdi3" [(set (match_operand:DI 0 "register_operand" "=r") (ior:DI (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")) (match_operand:DI 2 "reg_or_0_operand" "rJ")))] @@ -1308,6 +1361,16 @@ "ornot %r2,%1,%0" [(set_attr "type" "ilog")]) +(define_insn "*xorsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (xor:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:SI 2 "or_operand" "rI,N")))] + "" + "@ + xor %r1,%2,%0 + eqv %r1,%N2,%0" + [(set_attr "type" "ilog")]) + (define_insn "xordi3" [(set (match_operand:DI 0 "register_operand" "=r,r") (xor:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ") @@ -1318,7 +1381,15 @@ eqv %r1,%N2,%0" [(set_attr "type" "ilog")]) -(define_insn "*xornot" +(define_insn "*xornotsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (xor:SI (match_operand:SI 1 "register_operand" "%rJ") + (match_operand:SI 2 "register_operand" "rI"))))] + "" + "eqv %r1,%2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*xornotdi3" [(set (match_operand:DI 0 "register_operand" "=r") (not:DI (xor:DI (match_operand:DI 1 "register_operand" "%rJ") (match_operand:DI 2 "register_operand" "rI"))))] @@ -7705,6 +7776,8 @@ "unpkbw %r1,%0" [(set_attr "type" "mvi")]) +(include "sync.md") + ;; The call patterns are at the end of the file because their ;; wildcard operand0 interferes with nice recognition. diff --git a/gcc/config/alpha/ev4.md b/gcc/config/alpha/ev4.md index cba847e91304..52f25561c565 100644 --- a/gcc/config/alpha/ev4.md +++ b/gcc/config/alpha/ev4.md @@ -39,7 +39,7 @@ ; in user-specified memory latency, so return 1 here. (define_insn_reservation "ev4_ld" 1 (and (eq_attr "tune" "ev4") - (eq_attr "type" "ild,fld,ldsym")) + (eq_attr "type" "ild,fld,ldsym,ld_l")) "ev4_ib01+ev4_abox") ; Stores can issue before the data (but not address) is ready. @@ -48,11 +48,26 @@ (eq_attr "type" "ist")) "ev4_ib1+ev4_abox") +; ??? Separate from ev4_ist because store_data_bypass_p can't handle +; the patterns with multiple sets, like store-conditional. +(define_insn_reservation "ev4_ist_c" 1 + (and (eq_attr "tune" "ev4") + (eq_attr "type" "st_c")) + "ev4_ib1+ev4_abox") + (define_insn_reservation "ev4_fst" 1 (and (eq_attr "tune" "ev4") (eq_attr "type" "fst")) "ev4_ib0+ev4_abox") +; Memory barrier blocks ABOX insns until it's acknowledged by the external +; memory bus. This may be *quite* slow. Setting this to 4 cycles gets +; about all the benefit without making the DFA too large. +(define_insn_reservation "ev4_mb" 4 + (and (eq_attr "tune" "ev4") + (eq_attr "type" "mb")) + "ev4_ib1+ev4_abox,ev4_abox*3") + ; Branches have no delay cost, but do tie up the unit for two cycles. (define_insn_reservation "ev4_ibr" 2 (and (eq_attr "tune" "ev4") diff --git a/gcc/config/alpha/ev5.md b/gcc/config/alpha/ev5.md index d4b0b9573c17..b61cfe8e8f0b 100644 --- a/gcc/config/alpha/ev5.md +++ b/gcc/config/alpha/ev5.md @@ -43,7 +43,7 @@ (define_insn_reservation "ev5_st" 1 (and (eq_attr "tune" "ev5") - (eq_attr "type" "ist,fst")) + (eq_attr "type" "ist,fst,st_c,mb")) "ev5_e0+ev5_st") ; Loads from L0 complete in two cycles. adjust_cost still factors @@ -53,6 +53,11 @@ (eq_attr "type" "ild,fld,ldsym")) "ev5_e01+ev5_ld") +(define_insn_reservation "ev5_ld_l" 1 + (and (eq_attr "tune" "ev5") + (eq_attr "type" "ld_l")) + "ev5_e0+ev5_ld") + ; Integer branches slot only to E1. (define_insn_reservation "ev5_ibr" 1 (and (eq_attr "tune" "ev5") @@ -129,7 +134,7 @@ ; Model this instead with increased latency on the input instruction. (define_bypass 3 - "ev5_ld,ev5_shift,ev5_mvi,ev5_cmov,ev5_iadd,ev5_ilogcmp" + "ev5_ld,ev5_ld_l,ev5_shift,ev5_mvi,ev5_cmov,ev5_iadd,ev5_ilogcmp" "ev5_imull,ev5_imulq,ev5_imulh") (define_bypass 9 "ev5_imull" "ev5_imull,ev5_imulq,ev5_imulh") diff --git a/gcc/config/alpha/ev6.md b/gcc/config/alpha/ev6.md index 0f39fa2af9a4..6ddadca54f29 100644 --- a/gcc/config/alpha/ev6.md +++ b/gcc/config/alpha/ev6.md @@ -53,14 +53,19 @@ ; adjust_cost still factors in user-specified memory latency, so return 1 here. (define_insn_reservation "ev6_ild" 1 (and (eq_attr "tune" "ev6") - (eq_attr "type" "ild,ldsym")) + (eq_attr "type" "ild,ldsym,ld_l")) "ev6_l") (define_insn_reservation "ev6_ist" 1 (and (eq_attr "tune" "ev6") - (eq_attr "type" "ist")) + (eq_attr "type" "ist,st_c")) "ev6_l") +(define_insn_reservation "ev6_mb" 1 + (and (eq_attr "tune" "ev6") + (eq_attr "type" "mb")) + "ev6_l1") + ; FP loads take at least 4 clocks. adjust_cost still factors ; in user-specified memory latency, so return 2 here. (define_insn_reservation "ev6_fld" 2 diff --git a/gcc/config/alpha/sync.md b/gcc/config/alpha/sync.md new file mode 100644 index 000000000000..755a3f3e2e9b --- /dev/null +++ b/gcc/config/alpha/sync.md @@ -0,0 +1,319 @@ +;; GCC machine description for Alpha synchronization instructions. +;; Copyright (C) 2005 +;; Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +(define_mode_macro I48MODE [SI DI]) +(define_mode_attr modesuffix [(SI "l") (DI "q")]) + +(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 "reg_or_8bit_operand") + (ior "or_operand") (xor "or_operand") (and "and_operand")]) +(define_code_attr fetchop_constr + [(plus "rKL") (minus "rI") (ior "rIN") (xor "rIN") (and "riNHM")]) + + +(define_expand "memory_barrier" + [(set (mem:BLK (match_dup 0)) + (unspec_volatile:BLK [(mem:BLK (match_dup 0))] UNSPECV_MB))] + "" +{ + operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (DImode)); + MEM_VOLATILE_P (operands[0]) = 1; +}) + +(define_insn "*mb_internal" + [(set (match_operand:BLK 0 "" "") + (unspec_volatile:BLK [(match_operand:BLK 1 "" "")] UNSPECV_MB))] + "" + "mb" + [(set_attr "type" "mb")]) + +(define_insn "load_locked_<mode>" + [(set (match_operand:I48MODE 0 "register_operand" "=r") + (unspec_volatile:I48MODE + [(match_operand:I48MODE 1 "memory_operand" "m")] + UNSPECV_LL))] + "" + "ld<modesuffix>_l %0,%1" + [(set_attr "type" "ld_l")]) + +(define_insn "store_conditional_<mode>" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(const_int 0)] UNSPECV_SC)) + (set (match_operand:I48MODE 1 "memory_operand" "=m") + (match_operand:I48MODE 2 "reg_or_0_operand" "0"))] + "" + "st<modesuffix>_c %0,%1" + [(set_attr "type" "st_c")]) + +;; The Alpha Architecture Handbook says that it is UNPREDICTABLE whether +;; the lock is cleared by a TAKEN branch. If we were to honor that, it +;; would mean that we could not expand a ll/sc sequence until after the +;; final basic-block reordering pass. Fortunately, it appears that no +;; Alpha implementation ever built actually clears the lock on branches, +;; taken or not. + +(define_insn_and_split "sync_<fetchop_name><mode>" + [(set (match_operand:I48MODE 0 "memory_operand" "+m") + (unspec_volatile:I48MODE + [(FETCHOP:I48MODE (match_dup 0) + (match_operand:I48MODE 1 "<fetchop_pred>" "<fetchop_constr>"))] + UNSPECV_ATOMIC)) + (clobber (match_scratch:I48MODE 2 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_atomic_op (<CODE>, operands[0], operands[1], + NULL, NULL, operands[2]); + DONE; +} + [(set_attr "type" "multi")]) + +(define_insn_and_split "sync_nand<mode>" + [(set (match_operand:I48MODE 0 "memory_operand" "+m") + (unspec_volatile:I48MODE + [(and:I48MODE + (not:I48MODE + (match_operand:I48MODE 1 "reg_or_8bit_operand" "rI")) + (match_dup 0))] + UNSPECV_ATOMIC)) + (clobber (match_scratch:I48MODE 2 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_atomic_op (NOT, operands[0], operands[1], + NULL, NULL, operands[2]); + DONE; +} + [(set_attr "type" "multi")]) + +(define_insn_and_split "sync_old_<fetchop_name><mode>" + [(set (match_operand:I48MODE 0 "register_operand" "=&r") + (match_operand:I48MODE 1 "memory_operand" "+m")) + (set (match_dup 1) + (unspec_volatile:I48MODE + [(FETCHOP:I48MODE (match_dup 1) + (match_operand:I48MODE 2 "<fetchop_pred>" "<fetchop_constr>"))] + UNSPECV_ATOMIC)) + (clobber (match_scratch:I48MODE 3 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_atomic_op (<CODE>, operands[1], operands[2], + operands[0], NULL, operands[3]); + DONE; +} + [(set_attr "type" "multi")]) + +(define_insn_and_split "sync_old_nand<mode>" + [(set (match_operand:I48MODE 0 "register_operand" "=&r") + (match_operand:I48MODE 1 "memory_operand" "+m")) + (set (match_dup 1) + (unspec_volatile:I48MODE + [(and:I48MODE + (not:I48MODE + (match_operand:I48MODE 2 "reg_or_8bit_operand" "rI")) + (match_dup 1))] + UNSPECV_ATOMIC)) + (clobber (match_scratch:I48MODE 3 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_atomic_op (NOT, operands[1], operands[2], + operands[0], NULL, operands[3]); + DONE; +} + [(set_attr "type" "multi")]) + +(define_insn_and_split "sync_new_<fetchop_name><mode>" + [(set (match_operand:I48MODE 0 "register_operand" "=&r") + (FETCHOP:I48MODE + (match_operand:I48MODE 1 "memory_operand" "+m") + (match_operand:I48MODE 2 "<fetchop_pred>" "<fetchop_constr>"))) + (set (match_dup 1) + (unspec_volatile:I48MODE + [(FETCHOP:I48MODE (match_dup 1) (match_dup 2))] + UNSPECV_ATOMIC)) + (clobber (match_scratch:I48MODE 3 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_atomic_op (<CODE>, operands[1], operands[2], + NULL, operands[0], operands[3]); + DONE; +} + [(set_attr "type" "multi")]) + +(define_insn_and_split "sync_new_nand<mode>" + [(set (match_operand:I48MODE 0 "register_operand" "=&r") + (and:I48MODE + (not:I48MODE + (match_operand:I48MODE 2 "reg_or_8bit_operand" "rI")) + (match_operand:I48MODE 1 "memory_operand" "+m"))) + (set (match_dup 1) + (unspec_volatile:I48MODE + [(and:I48MODE (not:I48MODE (match_dup 2)) (match_dup 1))] + UNSPECV_ATOMIC)) + (clobber (match_scratch:I48MODE 3 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_atomic_op (NOT, operands[1], operands[2], + NULL, operands[0], operands[3]); + DONE; +} + [(set_attr "type" "multi")]) + +(define_expand "sync_compare_and_swap<mode>" + [(parallel + [(set (match_operand:I48MODE 0 "register_operand" "") + (match_operand:I48MODE 1 "memory_operand" "")) + (set (match_dup 1) + (unspec_volatile:I48MODE + [(match_operand:I48MODE 2 "reg_or_8bit_operand" "") + (match_operand:I48MODE 3 "add_operand" "rKL")] + UNSPECV_CMPXCHG)) + (clobber (match_scratch:I48MODE 4 "=&r"))])] + "" +{ + if (<MODE>mode == SImode) + operands[2] = convert_modes (DImode, SImode, operands[2], 0); +}) + +(define_insn_and_split "*sync_compare_and_swap<mode>" + [(set (match_operand:I48MODE 0 "register_operand" "=&r") + (match_operand:I48MODE 1 "memory_operand" "+m")) + (set (match_dup 1) + (unspec_volatile:I48MODE + [(match_operand:DI 2 "reg_or_8bit_operand" "rI") + (match_operand:I48MODE 3 "add_operand" "rKL")] + UNSPECV_CMPXCHG)) + (clobber (match_scratch:I48MODE 4 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx retval, mem, oldval, newval, scratch; + rtx cond, label1, label2, x; + rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1); + + retval = operands[0]; + mem = operands[1]; + oldval = operands[2]; + newval = operands[3]; + scratch = operands[4]; + cond = gen_lowpart (DImode, scratch); + + emit_insn (gen_memory_barrier ()); + + label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); + label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); + emit_label (XEXP (label1, 0)); + + emit_insn (gen_load_locked_<mode> (retval, mem)); + + x = gen_lowpart (DImode, retval); + x = gen_rtx_EQ (DImode, x, oldval); + if (oldval != const0_rtx) + { + emit_insn (gen_rtx_SET (VOIDmode, cond, x)); + x = gen_rtx_EQ (DImode, cond, const0_rtx); + } + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label2, pc_rtx); + x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x)); + REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX); + + emit_move_insn (scratch, newval); + emit_move_insn (retval, newval); + + emit_insn (gen_store_conditional_<mode> (cond, mem, scratch)); + + x = gen_rtx_EQ (DImode, cond, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label1, pc_rtx); + x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x)); + REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX); + + emit_label (XEXP (label2, 0)); + emit_insn (gen_memory_barrier ()); + DONE; +} + [(set_attr "type" "multi")]) + +(define_insn_and_split "sync_lock_test_and_set<mode>" + [(set (match_operand:I48MODE 0 "register_operand" "=&r") + (match_operand:I48MODE 1 "memory_operand" "+m")) + (set (match_dup 1) + (unspec_volatile:I48MODE + [(match_operand:I48MODE 2 "add_operand" "rKL")] + UNSPECV_XCHG)) + (clobber (match_scratch:I48MODE 3 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx retval, mem, val, scratch; + rtx cond, label1, label2, x; + rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1); + + retval = operands[0]; + mem = operands[1]; + val = operands[2]; + scratch = operands[3]; + cond = gen_lowpart (DImode, scratch); + + emit_insn (gen_memory_barrier ()); + + label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); + label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); + emit_label (XEXP (label1, 0)); + + emit_insn (gen_load_locked_<mode> (retval, mem)); + + emit_move_insn (scratch, val); + + emit_insn (gen_store_conditional_<mode> (cond, mem, scratch)); + + x = gen_rtx_EQ (DImode, cond, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label1, pc_rtx); + x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x)); + REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX); + + emit_label (XEXP (label2, 0)); + emit_insn (gen_memory_barrier ()); + DONE; +} + [(set_attr "type" "multi")])