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
This commit is contained in:
Richard Henderson 2005-04-18 09:13:00 -07:00 committed by Richard Henderson
parent 46c94db618
commit 0b196b187b
8 changed files with 513 additions and 11 deletions

View File

@ -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

View File

@ -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);

View File

@ -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:

View File

@ -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.

View File

@ -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")

View File

@ -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")

View File

@ -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

319
gcc/config/alpha/sync.md Normal file
View File

@ -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")])