From: David Daney Date: Tue, 20 May 2008 23:13:13 +0000 (+0000) Subject: mips.md (UNSPEC_SYNC_NEW_OP_12, [...]): New define_constants. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=06d1961718e14e5f9661d8885e15a63ce65add07;p=gcc.git mips.md (UNSPEC_SYNC_NEW_OP_12, [...]): New define_constants. 2008-05-20 David Daney * config/mips/mips.md (UNSPEC_SYNC_NEW_OP_12, UNSPEC_SYNC_OLD_OP_12, UNSPEC_SYNC_EXCHANGE_12): New define_constants. (UNSPEC_SYNC_EXCHANGE, UNSPEC_MEMORY_BARRIER, UNSPEC_SET_GOT_VERSION, UNSPEC_UPDATE_GOT_VERSION): Renumber. (optab, insn): Add 'plus' and 'minus' to define_code_attr. (atomic_hiqi_op): New define_code_iterator. (sync_compare_and_swap): Call mips_expand_atomic_qihi instead of mips_expand_compare_and_swap_12. (compare_and_swap_12): Use MIPS_COMPARE_AND_SWAP_12 instead of MIPS_COMPARE_AND_SWAP_12_0. Pass argument to MIPS_COMPARE_AND_SWAP_12. (sync_, sync_old_, sync_new_, sync_nand, sync_old_nand, sync_new_nand): New define_expands for HI and QI mode operands. (sync__12, sync_old__12, sync_new__12, sync_nand_12, sync_old_nand_12, sync_new_nand_12): New insns. (sync_lock_test_and_set): New define_expand for HI and QI modes. (test_and_set_12): New insn. (sync_old_add, sync_new_add, sync_old_, sync_new_, sync_old_nand, sync_new_nand, sync_lock_test_and_set): Add early clobber to operand 0 for SI and DI mode insns. * config/mips/mips-protos.h (mips_gen_fn_6, mips_gen_fn_5, mips_gen_fn_4): New typedefs. (mips_gen_fn_ptrs): Define new union type. (mips_expand_compare_and_swap_12): Remove declaration. (mips_expand_atomic_qihi): Declare function. * config/mips/mips.c (mips_expand_compare_and_swap_12): Rename to... (mips_expand_atomic_qihi): ... this. Use new generator function parameter. * config/mips/mips.h (MIPS_COMPARE_AND_SWAP_12): Add OPS parameter. (MIPS_COMPARE_AND_SWAP_12_0): Delete macro. (MIPS_COMPARE_AND_SWAP_12_ZERO_OP, MIPS_COMPARE_AND_SWAP_12_NONZERO_OP, MIPS_SYNC_OP_12, MIPS_SYNC_OP_12_NOT_NOP, MIPS_SYNC_OP_12_NOT_NOT, MIPS_SYNC_OLD_OP_12, MIPS_SYNC_OLD_OP_12_NOT_NOP, MIPS_SYNC_OLD_OP_12_NOT_NOP_REG, MIPS_SYNC_OLD_OP_12_NOT_NOT, MIPS_SYNC_OLD_OP_12_NOT_NOT_REG, MIPS_SYNC_NEW_OP_12, MIPS_SYNC_NEW_OP_12_NOT_NOP, MIPS_SYNC_NEW_OP_12_NOT_NOT, MIPS_SYNC_EXCHANGE_12, MIPS_SYNC_EXCHANGE_12_ZERO_OP, MIPS_SYNC_EXCHANGE_12_NONZERO_OP): New macros. From-SVN: r135684 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 41e28d4981d..f354031add9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,53 @@ +2008-05-20 David Daney + + * config/mips/mips.md (UNSPEC_SYNC_NEW_OP_12, + UNSPEC_SYNC_OLD_OP_12, + UNSPEC_SYNC_EXCHANGE_12): New define_constants. + (UNSPEC_SYNC_EXCHANGE, UNSPEC_MEMORY_BARRIER, + UNSPEC_SET_GOT_VERSION, + UNSPEC_UPDATE_GOT_VERSION): Renumber. + (optab, insn): Add 'plus' and 'minus' to define_code_attr. + (atomic_hiqi_op): New define_code_iterator. + (sync_compare_and_swap): Call + mips_expand_atomic_qihi instead of + mips_expand_compare_and_swap_12. + (compare_and_swap_12): Use MIPS_COMPARE_AND_SWAP_12 instead of + MIPS_COMPARE_AND_SWAP_12_0. Pass argument to + MIPS_COMPARE_AND_SWAP_12. + (sync_, sync_old_, + sync_new_, sync_nand, sync_old_nand, + sync_new_nand): New define_expands for HI and QI mode + operands. + (sync__12, sync_old__12, sync_new__12, + sync_nand_12, sync_old_nand_12, sync_new_nand_12): New insns. + (sync_lock_test_and_set): New define_expand for HI and QI + modes. + (test_and_set_12): New insn. + (sync_old_add, sync_new_add, sync_old_, + sync_new_, sync_old_nand, + sync_new_nand, sync_lock_test_and_set): Add early + clobber to operand 0 for SI and DI mode insns. + * config/mips/mips-protos.h (mips_gen_fn_6, mips_gen_fn_5, + mips_gen_fn_4): New typedefs. + (mips_gen_fn_ptrs): Define new union type. + (mips_expand_compare_and_swap_12): Remove declaration. + (mips_expand_atomic_qihi): Declare function. + * config/mips/mips.c (mips_expand_compare_and_swap_12): Rename to... + (mips_expand_atomic_qihi): ... this. Use new generator function + parameter. + * config/mips/mips.h (MIPS_COMPARE_AND_SWAP_12): Add OPS parameter. + (MIPS_COMPARE_AND_SWAP_12_0): Delete macro. + (MIPS_COMPARE_AND_SWAP_12_ZERO_OP, + MIPS_COMPARE_AND_SWAP_12_NONZERO_OP, + MIPS_SYNC_OP_12, MIPS_SYNC_OP_12_NOT_NOP, + MIPS_SYNC_OP_12_NOT_NOT, MIPS_SYNC_OLD_OP_12, + MIPS_SYNC_OLD_OP_12_NOT_NOP, MIPS_SYNC_OLD_OP_12_NOT_NOP_REG, + MIPS_SYNC_OLD_OP_12_NOT_NOT, MIPS_SYNC_OLD_OP_12_NOT_NOT_REG, + MIPS_SYNC_NEW_OP_12, MIPS_SYNC_NEW_OP_12_NOT_NOP, + MIPS_SYNC_NEW_OP_12_NOT_NOT, MIPS_SYNC_EXCHANGE_12, + MIPS_SYNC_EXCHANGE_12_ZERO_OP, + MIPS_SYNC_EXCHANGE_12_NONZERO_OP): New macros. + 2008-05-20 H.J. Lu * config/i386/i386.c (ix86_expand_vector_init_one_nonzero): Add diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index fbac8fcfd07..db65aab93c9 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -292,6 +292,14 @@ extern bool mips_use_ins_ext_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT); extern const char *mips16e_output_save_restore (rtx, HOST_WIDE_INT); extern bool mips16e_save_restore_pattern_p (rtx, HOST_WIDE_INT, struct mips16e_save_restore_info *); -extern void mips_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx); +union mips_gen_fn_ptrs +{ + rtx (*fn_6) (rtx, rtx, rtx, rtx, rtx, rtx); + rtx (*fn_5) (rtx, rtx, rtx, rtx, rtx); + rtx (*fn_4) (rtx, rtx, rtx, rtx); +}; + +extern void mips_expand_atomic_qihi (union mips_gen_fn_ptrs, + rtx, rtx, rtx, rtx); #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 218953385b3..6cb0d293dda 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -5873,14 +5873,29 @@ mips_expand_synci_loop (rtx begin, rtx end) emit_jump_insn (gen_condjump (cmp_result, label)); } -/* Expand a QI or HI mode compare_and_swap. The operands are the same - as for the generator function. */ +/* Expand a QI or HI mode atomic memory operation. + + GENERATOR contains a pointer to the gen_* function that generates + the SI mode underlying atomic operation using masks that we + calculate. + + RESULT is the return register for the operation. Its value is NULL + if unused. + + MEM is the location of the atomic access. + + OLDVAL is the first operand for the operation. + + NEWVAL is the optional second operand for the operation. Its value + is NULL if unused. */ void -mips_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval) +mips_expand_atomic_qihi (union mips_gen_fn_ptrs generator, + rtx result, rtx mem, rtx oldval, rtx newval) { rtx orig_addr, memsi_addr, memsi, shift, shiftsi, unshifted_mask; - rtx unshifted_mask_reg, mask, inverted_mask, res; + rtx unshifted_mask_reg, mask, inverted_mask, si_op; + rtx res = NULL; enum machine_mode mode; mode = GET_MODE (mem); @@ -5927,7 +5942,7 @@ mips_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval) } /* Do the same for the new value. */ - if (newval != const0_rtx) + if (newval && newval != const0_rtx) { newval = convert_modes (SImode, mode, newval, true); newval = force_reg (SImode, newval); @@ -5935,14 +5950,24 @@ mips_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval) } /* Do the SImode atomic access. */ - res = gen_reg_rtx (SImode); - emit_insn (gen_compare_and_swap_12 (res, memsi, mask, inverted_mask, - oldval, newval)); - - /* Shift and convert the result. */ - mips_emit_binary (AND, res, res, mask); - mips_emit_binary (LSHIFTRT, res, res, shiftsi); - mips_emit_move (result, gen_lowpart (GET_MODE (result), res)); + if (result) + res = gen_reg_rtx (SImode); + if (newval) + si_op = generator.fn_6 (res, memsi, mask, inverted_mask, oldval, newval); + else if (result) + si_op = generator.fn_5 (res, memsi, mask, inverted_mask, oldval); + else + si_op = generator.fn_4 (memsi, mask, inverted_mask, oldval); + + emit_insn (si_op); + + if (result) + { + /* Shift and convert the result. */ + mips_emit_binary (AND, res, res, mask); + mips_emit_binary (LSHIFTRT, res, res, shiftsi); + mips_emit_move (result, gen_lowpart (GET_MODE (result), res)); + } } /* Return true if it is possible to use left/right accesses for a diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 9f59f1a2550..765552778b5 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -1,6 +1,6 @@ /* Definitions of target machine for GNU compiler. MIPS version. Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. Contributed by A. Lichnewsky (lich@inria.inria.fr). Changed by Michael Meissner (meissner@osf.org). @@ -2908,41 +2908,32 @@ while (0) /* Return an asm string that atomically: - Given that %2 contains a bit mask and %3 the inverted mask and - that %4 and %5 have already been ANDed with $2. + that %4 and %5 have already been ANDed with %2. - Compares the bits in memory reference %1 selected by mask %2 to register %4 and, if they are equal, changes the selected bits in memory to %5. - Sets register %0 to the old value of memory reference %1. - */ -#define MIPS_COMPARE_AND_SWAP_12 \ - "%(%<%[%|sync\n" \ - "1:\tll\t%0,%1\n" \ - "\tand\t%@,%0,%2\n" \ - "\tbne\t%@,%z4,2f\n" \ - "\tand\t%@,%0,%3\n" \ - "\tor\t%@,%@,%5\n" \ - "\tsc\t%@,%1\n" \ - "\tbeq\t%@,%.,1b\n" \ - "\tnop\n" \ - "\tsync%-%]%>%)\n" \ - "2:\n" -/* Like MIPS_COMPARE_AND_SWAP_12, except %5 is a constant zero, - so the OR can be omitted. */ -#define MIPS_COMPARE_AND_SWAP_12_0 \ + OPS are the instructions needed to OR %5 with %@. */ +#define MIPS_COMPARE_AND_SWAP_12(OPS) \ "%(%<%[%|sync\n" \ "1:\tll\t%0,%1\n" \ "\tand\t%@,%0,%2\n" \ "\tbne\t%@,%z4,2f\n" \ "\tand\t%@,%0,%3\n" \ + OPS \ "\tsc\t%@,%1\n" \ "\tbeq\t%@,%.,1b\n" \ "\tnop\n" \ "\tsync%-%]%>%)\n" \ "2:\n" +#define MIPS_COMPARE_AND_SWAP_12_ZERO_OP "" +#define MIPS_COMPARE_AND_SWAP_12_NONZERO_OP "\tor\t%@,%@,%5\n" + + /* Return an asm string that atomically: - Sets memory reference %0 to %0 INSN %1. @@ -2958,6 +2949,97 @@ while (0) "\tnop\n" \ "\tsync%-%]%>%)" +/* Return an asm string that atomically: + + - Given that %1 contains a bit mask and %2 the inverted mask and + that %3 has already been ANDed with %1. + + - Sets the selected bits of memory reference %0 to %0 INSN %3. + + - Uses scratch register %4. + + NOT_OP are the optional instructions to do a bit-wise not + operation in conjunction with an AND INSN to generate a sync_nand + operation. */ +#define MIPS_SYNC_OP_12(INSN, NOT_OP) \ + "%(%<%[%|sync\n" \ + "1:\tll\t%4,%0\n" \ + "\tand\t%@,%4,%2\n" \ + NOT_OP \ + "\t" INSN "\t%4,%4,%z3\n" \ + "\tand\t%4,%4,%1\n" \ + "\tor\t%@,%@,%4\n" \ + "\tsc\t%@,%0\n" \ + "\tbeq\t%@,%.,1b\n" \ + "\tnop\n" \ + "\tsync%-%]%>%)" + +#define MIPS_SYNC_OP_12_NOT_NOP "" +#define MIPS_SYNC_OP_12_NOT_NOT "\tnor\t%4,%4,%.\n" + +/* Return an asm string that atomically: + + - Given that %2 contains a bit mask and %3 the inverted mask and + that %4 has already been ANDed with %2. + + - Sets the selected bits of memory reference %1 to %1 INSN %4. + + - Sets %0 to the original value of %1. + + - Uses scratch register %5. + + NOT_OP are the optional instructions to do a bit-wise not + operation in conjunction with an AND INSN to generate a sync_nand + operation. + + REG is used in conjunction with NOT_OP and is used to select the + register operated on by the INSN. */ +#define MIPS_SYNC_OLD_OP_12(INSN, NOT_OP, REG) \ + "%(%<%[%|sync\n" \ + "1:\tll\t%0,%1\n" \ + "\tand\t%@,%0,%3\n" \ + NOT_OP \ + "\t" INSN "\t%5," REG ",%z4\n" \ + "\tand\t%5,%5,%2\n" \ + "\tor\t%@,%@,%5\n" \ + "\tsc\t%@,%1\n" \ + "\tbeq\t%@,%.,1b\n" \ + "\tnop\n" \ + "\tsync%-%]%>%)" + +#define MIPS_SYNC_OLD_OP_12_NOT_NOP "" +#define MIPS_SYNC_OLD_OP_12_NOT_NOP_REG "%0" +#define MIPS_SYNC_OLD_OP_12_NOT_NOT "\tnor\t%5,%0,%.\n" +#define MIPS_SYNC_OLD_OP_12_NOT_NOT_REG "%5" + +/* Return an asm string that atomically: + + - Given that %2 contains a bit mask and %3 the inverted mask and + that %4 has already been ANDed with %2. + + - Sets the selected bits of memory reference %1 to %1 INSN %4. + + - Sets %0 to the new value of %1. + + NOT_OP are the optional instructions to do a bit-wise not + operation in conjunction with an AND INSN to generate a sync_nand + operation. */ +#define MIPS_SYNC_NEW_OP_12(INSN, NOT_OP) \ + "%(%<%[%|sync\n" \ + "1:\tll\t%0,%1\n" \ + "\tand\t%@,%0,%3\n" \ + NOT_OP \ + "\t" INSN "\t%0,%0,%z4\n" \ + "\tand\t%0,%0,%2\n" \ + "\tor\t%@,%@,%0\n" \ + "\tsc\t%@,%1\n" \ + "\tbeq\t%@,%.,1b\n" \ + "\tnop\n" \ + "\tsync%-%]%>%)" + +#define MIPS_SYNC_NEW_OP_12_NOT_NOP "" +#define MIPS_SYNC_NEW_OP_12_NOT_NOT "\tnor\t%0,%0,%.\n" + /* Return an asm string that atomically: - Sets memory reference %1 to %1 INSN %2. @@ -3065,6 +3147,33 @@ while (0) "\tnop\n" \ "\tsync%-%]%>%)" +/* Return an asm string that atomically: + + - Given that %2 contains an inclusive mask, %3 and exclusive mask + and %4 has already been ANDed with the inclusive mask. + + - Sets bits selected by the inclusive mask of memory reference %1 + to %4. + + - Sets register %0 to the old value of memory reference %1. + + OPS are the instructions needed to OR %4 with %@. + + Operand %2 is unused, but needed as to give the test_and_set_12 + insn the five operands expected by the expander. */ +#define MIPS_SYNC_EXCHANGE_12(OPS) \ + "%(%<%[%|\n" \ + "1:\tll\t%0,%1\n" \ + "\tand\t%@,%0,%3\n" \ + OPS \ + "\tsc\t%@,%1\n" \ + "\tbeq\t%@,%.,1b\n" \ + "\tnop\n" \ + "\tsync%-%]%>%)" + +#define MIPS_SYNC_EXCHANGE_12_ZERO_OP "" +#define MIPS_SYNC_EXCHANGE_12_NONZERO_OP "\tor\t%@,%@,%4\n" + #ifndef USED_FOR_TARGET extern const enum reg_class mips_regno_to_class[]; extern bool mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER]; diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index a423529b330..2b789eef8b6 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -1,6 +1,6 @@ ;; Mips.md Machine Description for MIPS based processors ;; Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, -;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 +;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 ;; Free Software Foundation, Inc. ;; Contributed by A. Lichnewsky, lich@inria.inria.fr ;; Changes by Michael Meissner, meissner@osf.org @@ -57,10 +57,13 @@ (UNSPEC_COMPARE_AND_SWAP_12 38) (UNSPEC_SYNC_OLD_OP 39) (UNSPEC_SYNC_NEW_OP 40) - (UNSPEC_SYNC_EXCHANGE 41) - (UNSPEC_MEMORY_BARRIER 42) - (UNSPEC_SET_GOT_VERSION 43) - (UNSPEC_UPDATE_GOT_VERSION 44) + (UNSPEC_SYNC_NEW_OP_12 41) + (UNSPEC_SYNC_OLD_OP_12 42) + (UNSPEC_SYNC_EXCHANGE 43) + (UNSPEC_SYNC_EXCHANGE_12 44) + (UNSPEC_MEMORY_BARRIER 45) + (UNSPEC_SET_GOT_VERSION 46) + (UNSPEC_UPDATE_GOT_VERSION 47) (UNSPEC_ADDRESS_FIRST 100) @@ -639,7 +642,9 @@ (lshiftrt "lshr") (ior "ior") (xor "xor") - (and "and")]) + (and "and") + (plus "add") + (minus "sub")]) ;; expands to the name of the insn that implements a particular code. (define_code_attr insn [(ashift "sll") @@ -647,7 +652,9 @@ (lshiftrt "srl") (ior "or") (xor "xor") - (and "and")]) + (and "and") + (plus "addu") + (minus "subu")]) ;; is the c.cond.fmt condition associated with a particular code. (define_code_attr fcond [(unordered "un") @@ -671,6 +678,8 @@ ;; a particular code to operate in immediate values. (define_code_attr immediate_insn [(ior "ori") (xor "xori") (and "andi")]) +;; Atomic HI and QI operations +(define_code_iterator atomic_hiqi_op [plus minus ior xor and]) ;; ......................... ;; @@ -4455,12 +4464,14 @@ (match_operand:SHORT 3 "general_operand")] "GENERATE_LL_SC" { - mips_expand_compare_and_swap_12 (operands[0], operands[1], - operands[2], operands[3]); + union mips_gen_fn_ptrs generator; + generator.fn_6 = gen_compare_and_swap_12; + mips_expand_atomic_qihi (generator, + operands[0], operands[1], operands[2], operands[3]); DONE; }) -;; Helper insn for mips_expand_compare_and_swap_12. +;; Helper insn for mips_expand_atomic_qihi. (define_insn "compare_and_swap_12" [(set (match_operand:SI 0 "register_operand" "=&d,&d") (match_operand:SI 1 "memory_operand" "+R,R")) @@ -4473,9 +4484,9 @@ "GENERATE_LL_SC" { if (which_alternative == 0) - return MIPS_COMPARE_AND_SWAP_12; + return MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_NONZERO_OP); else - return MIPS_COMPARE_AND_SWAP_12_0; + return MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_ZERO_OP); } [(set_attr "length" "40,36")]) @@ -4483,8 +4494,8 @@ [(set (match_operand:GPR 0 "memory_operand" "+R,R") (unspec_volatile:GPR [(plus:GPR (match_dup 0) - (match_operand:GPR 1 "arith_operand" "I,d"))] - UNSPEC_SYNC_OLD_OP))] + (match_operand:GPR 1 "arith_operand" "I,d"))] + UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" { if (which_alternative == 0) @@ -4494,6 +4505,220 @@ } [(set_attr "length" "28")]) +(define_expand "sync_" + [(set (match_operand:SHORT 0 "memory_operand") + (unspec_volatile:SHORT + [(atomic_hiqi_op:SHORT (match_dup 0) + (match_operand:SHORT 1 "general_operand"))] + UNSPEC_SYNC_OLD_OP))] + "GENERATE_LL_SC" +{ + union mips_gen_fn_ptrs generator; + generator.fn_4 = gen_sync__12; + mips_expand_atomic_qihi (generator, + NULL, operands[0], operands[1], NULL); + DONE; +}) + +;; Helper insn for sync_ +(define_insn "sync__12" + [(set (match_operand:SI 0 "memory_operand" "+R") + (unspec_volatile:SI + [(match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d") + (atomic_hiqi_op:SI (match_dup 0) + (match_operand:SI 3 "register_operand" "dJ"))] + UNSPEC_SYNC_OLD_OP_12)) + (clobber (match_scratch:SI 4 "=&d"))] + "GENERATE_LL_SC" +{ + return MIPS_SYNC_OP_12 ("", MIPS_SYNC_OP_12_NOT_NOP); +} + [(set_attr "length" "40")]) + +(define_expand "sync_old_" + [(parallel [ + (set (match_operand:SHORT 0 "register_operand") + (match_operand:SHORT 1 "memory_operand")) + (set (match_dup 1) + (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT + (match_dup 1) + (match_operand:SHORT 2 "general_operand"))] + UNSPEC_SYNC_OLD_OP))])] + "GENERATE_LL_SC" +{ + union mips_gen_fn_ptrs generator; + generator.fn_5 = gen_sync_old__12; + mips_expand_atomic_qihi (generator, + operands[0], operands[1], operands[2], NULL); + DONE; +}) + +;; Helper insn for sync_old_ +(define_insn "sync_old__12" + [(set (match_operand:SI 0 "register_operand" "=&d") + (match_operand:SI 1 "memory_operand" "+R")) + (set (match_dup 1) + (unspec_volatile:SI + [(match_operand:SI 2 "register_operand" "d") + (match_operand:SI 3 "register_operand" "d") + (atomic_hiqi_op:SI (match_dup 0) + (match_operand:SI 4 "register_operand" "dJ"))] + UNSPEC_SYNC_OLD_OP_12)) + (clobber (match_scratch:SI 5 "=&d"))] + "GENERATE_LL_SC" +{ + return MIPS_SYNC_OLD_OP_12 ("", MIPS_SYNC_OLD_OP_12_NOT_NOP, + MIPS_SYNC_OLD_OP_12_NOT_NOP_REG); +} + [(set_attr "length" "40")]) + +(define_expand "sync_new_" + [(parallel [ + (set (match_operand:SHORT 0 "register_operand") + (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT + (match_operand:SHORT 1 "memory_operand") + (match_operand:SHORT 2 "general_operand"))] + UNSPEC_SYNC_NEW_OP)) + (set (match_dup 1) + (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)] + UNSPEC_SYNC_NEW_OP))])] + "GENERATE_LL_SC" +{ + union mips_gen_fn_ptrs generator; + generator.fn_5 = gen_sync_new__12; + mips_expand_atomic_qihi (generator, + operands[0], operands[1], operands[2], NULL); + DONE; +}) + +;; Helper insn for sync_new_ +(define_insn "sync_new__12" + [(set (match_operand:SI 0 "register_operand" "=&d") + (unspec_volatile:SI + [(match_operand:SI 1 "memory_operand" "+R") + (match_operand:SI 2 "register_operand" "d") + (match_operand:SI 3 "register_operand" "d") + (atomic_hiqi_op:SI (match_dup 0) + (match_operand:SI 4 "register_operand" "dJ"))] + UNSPEC_SYNC_NEW_OP_12)) + (set (match_dup 1) + (unspec_volatile:SI + [(match_dup 1) + (match_dup 2) + (match_dup 3) + (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] + "GENERATE_LL_SC" +{ + return MIPS_SYNC_NEW_OP_12 ("", MIPS_SYNC_NEW_OP_12_NOT_NOP); +} + [(set_attr "length" "40")]) + +(define_expand "sync_nand" + [(set (match_operand:SHORT 0 "memory_operand") + (unspec_volatile:SHORT + [(match_dup 0) + (match_operand:SHORT 1 "general_operand")] + UNSPEC_SYNC_OLD_OP))] + "GENERATE_LL_SC" +{ + union mips_gen_fn_ptrs generator; + generator.fn_4 = gen_sync_nand_12; + mips_expand_atomic_qihi (generator, + NULL, operands[0], operands[1], NULL); + DONE; +}) + +;; Helper insn for sync_nand +(define_insn "sync_nand_12" + [(set (match_operand:SI 0 "memory_operand" "+R") + (unspec_volatile:SI + [(match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d") + (match_dup 0) + (match_operand:SI 3 "register_operand" "dJ")] + UNSPEC_SYNC_OLD_OP_12)) + (clobber (match_scratch:SI 4 "=&d"))] + "GENERATE_LL_SC" +{ + return MIPS_SYNC_OP_12 ("and", MIPS_SYNC_OP_12_NOT_NOT); +} + [(set_attr "length" "44")]) + +(define_expand "sync_old_nand" + [(parallel [ + (set (match_operand:SHORT 0 "register_operand") + (match_operand:SHORT 1 "memory_operand")) + (set (match_dup 1) + (unspec_volatile:SHORT [(match_dup 1) + (match_operand:SHORT 2 "general_operand")] + UNSPEC_SYNC_OLD_OP))])] + "GENERATE_LL_SC" +{ + union mips_gen_fn_ptrs generator; + generator.fn_5 = gen_sync_old_nand_12; + mips_expand_atomic_qihi (generator, + operands[0], operands[1], operands[2], NULL); + DONE; +}) + +;; Helper insn for sync_old_nand +(define_insn "sync_old_nand_12" + [(set (match_operand:SI 0 "register_operand" "=&d") + (match_operand:SI 1 "memory_operand" "+R")) + (set (match_dup 1) + (unspec_volatile:SI + [(match_operand:SI 2 "register_operand" "d") + (match_operand:SI 3 "register_operand" "d") + (match_operand:SI 4 "register_operand" "dJ")] + UNSPEC_SYNC_OLD_OP_12)) + (clobber (match_scratch:SI 5 "=&d"))] + "GENERATE_LL_SC" +{ + return MIPS_SYNC_OLD_OP_12 ("and", MIPS_SYNC_OLD_OP_12_NOT_NOT, + MIPS_SYNC_OLD_OP_12_NOT_NOT_REG); +} + [(set_attr "length" "44")]) + +(define_expand "sync_new_nand" + [(parallel [ + (set (match_operand:SHORT 0 "register_operand") + (unspec_volatile:SHORT [(match_operand:SHORT 1 "memory_operand") + (match_operand:SHORT 2 "general_operand")] + UNSPEC_SYNC_NEW_OP)) + (set (match_dup 1) + (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)] + UNSPEC_SYNC_NEW_OP))])] + "GENERATE_LL_SC" +{ + union mips_gen_fn_ptrs generator; + generator.fn_5 = gen_sync_new_nand_12; + mips_expand_atomic_qihi (generator, + operands[0], operands[1], operands[2], NULL); + DONE; +}) + +;; Helper insn for sync_new_nand +(define_insn "sync_new_nand_12" + [(set (match_operand:SI 0 "register_operand" "=&d") + (unspec_volatile:SI + [(match_operand:SI 1 "memory_operand" "+R") + (match_operand:SI 2 "register_operand" "d") + (match_operand:SI 3 "register_operand" "d") + (match_operand:SI 4 "register_operand" "dJ")] + UNSPEC_SYNC_NEW_OP_12)) + (set (match_dup 1) + (unspec_volatile:SI + [(match_dup 1) + (match_dup 2) + (match_dup 3) + (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] + "GENERATE_LL_SC" +{ + return MIPS_SYNC_NEW_OP_12 ("and", MIPS_SYNC_NEW_OP_12_NOT_NOT); +} + [(set_attr "length" "40")]) + (define_insn "sync_sub" [(set (match_operand:GPR 0 "memory_operand" "+R") (unspec_volatile:GPR @@ -4507,7 +4732,7 @@ [(set_attr "length" "28")]) (define_insn "sync_old_add" - [(set (match_operand:GPR 0 "register_operand" "=d,&d") + [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR @@ -4538,7 +4763,7 @@ [(set_attr "length" "28")]) (define_insn "sync_new_add" - [(set (match_operand:GPR 0 "register_operand" "=d,&d") + [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R") (match_operand:GPR 2 "arith_operand" "I,d"))) (set (match_dup 1) @@ -4584,7 +4809,7 @@ [(set_attr "length" "28")]) (define_insn "sync_old_" - [(set (match_operand:GPR 0 "register_operand" "=d,&d") + [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR @@ -4601,7 +4826,7 @@ [(set_attr "length" "28")]) (define_insn "sync_new_" - [(set (match_operand:GPR 0 "register_operand" "=d,&d") + [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR @@ -4631,7 +4856,7 @@ [(set_attr "length" "32")]) (define_insn "sync_old_nand" - [(set (match_operand:GPR 0 "register_operand" "=d,&d") + [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] @@ -4646,7 +4871,7 @@ [(set_attr "length" "32")]) (define_insn "sync_new_nand" - [(set (match_operand:GPR 0 "register_operand" "=d,&d") + [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] @@ -4661,7 +4886,7 @@ [(set_attr "length" "32")]) (define_insn "sync_lock_test_and_set" - [(set (match_operand:GPR 0 "register_operand" "=d,&d") + [(set (match_operand:GPR 0 "register_operand" "=&d,&d") (match_operand:GPR 1 "memory_operand" "+R,R")) (set (match_dup 1) (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")] @@ -4674,6 +4899,36 @@ return MIPS_SYNC_EXCHANGE ("", "move"); } [(set_attr "length" "24")]) + +(define_expand "sync_lock_test_and_set" + [(match_operand:SHORT 0 "register_operand") + (match_operand:SHORT 1 "memory_operand") + (match_operand:SHORT 2 "general_operand")] + "GENERATE_LL_SC" +{ + union mips_gen_fn_ptrs generator; + generator.fn_5 = gen_test_and_set_12; + mips_expand_atomic_qihi (generator, + operands[0], operands[1], operands[2], NULL); + DONE; +}) + +(define_insn "test_and_set_12" + [(set (match_operand:SI 0 "register_operand" "=&d,&d") + (match_operand:SI 1 "memory_operand" "+R,R")) + (set (match_dup 1) + (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d") + (match_operand:SI 3 "register_operand" "d,d") + (match_operand:SI 4 "arith_operand" "d,J")] + UNSPEC_SYNC_EXCHANGE_12))] + "GENERATE_LL_SC" +{ + if (which_alternative == 0) + return MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_NONZERO_OP); + else + return MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_ZERO_OP); +} + [(set_attr "length" "28,24")]) ;; Block moves, see mips.c for more details. ;; Argument 0 is the destination