* 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
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
for constants.
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);
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 ());
+}
\f
/* 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. */
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:
case TYPE_FADD:
case TYPE_FDIV:
case TYPE_FMUL:
+ case TYPE_ST_C:
+ case TYPE_MB:
return EV4_IB1;
default:
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:
(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
(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.
[(set_attr "type" "jsr")
(set_attr "length" "8")])
\f
-;; 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")
"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"))
"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")
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")))]
"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")))]
"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")
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"))))]
"unpkbw %r1,%0"
[(set_attr "type" "mvi")])
\f
+(include "sync.md")
+\f
;; The call patterns are at the end of the file because their
;; wildcard operand0 interferes with nice recognition.
; 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.
(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")
(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
(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")
; 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")
; 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
--- /dev/null
+;; 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")])