From: Richard Sandiford Date: Sat, 26 Apr 2008 07:40:04 +0000 (+0000) Subject: mips.md (UNSPEC_COMPARE_AND_SWAP_12): New unspec_volitile. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=49bce30a21d7cec8632fba32fd83abe7db1acad5;p=gcc.git mips.md (UNSPEC_COMPARE_AND_SWAP_12): New unspec_volitile. gcc/ 2008-04-23 David Daney * config/mips/mips.md (UNSPEC_COMPARE_AND_SWAP_12): New unspec_volitile. (UNSPEC_SYNC_OLD_OP, UNSPEC_SYNC_NEW_OP, UNSPEC_SYNC_EXCHANGE, UNSPEC_MEMORY_BARRIER, UNSPEC_SET_GOT_VERSION, UNSPEC_UPDATE_GOT_VERSION): Renumber. (sync_compare_and_swap): New expand for QI and HI modes. (compare_and_swap_12): New insn. * config/mips/mips-protos.h (mips_expand_compare_and_swap_12): Declare. * config/mips/mips.c (mips_force_binary): New function. (mips_emit_int_order_test, mips_expand_synci_loop): Use it. (mips_expand_compare_and_swap_12): New function. * config/mips/mips.h (MIPS_COMPARE_AND_SWAP_12): New macro. gcc/testsuite/ * gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: Expect __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 and __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 to be defined. * gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Likewise. From-SVN: r134695 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 374615b4546..2435b898a3d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2008-04-26 David Daney + + * config/mips/mips.md (UNSPEC_COMPARE_AND_SWAP_12): New + unspec_volitile. + (UNSPEC_SYNC_OLD_OP, UNSPEC_SYNC_NEW_OP, UNSPEC_SYNC_EXCHANGE, + UNSPEC_MEMORY_BARRIER, UNSPEC_SET_GOT_VERSION, + UNSPEC_UPDATE_GOT_VERSION): Renumber. + (sync_compare_and_swap): New expand for QI and HI modes. + (compare_and_swap_12): New insn. + * config/mips/mips-protos.h (mips_expand_compare_and_swap_12): Declare. + * config/mips/mips.c (mips_force_binary): New function. + (mips_emit_int_order_test, mips_expand_synci_loop): Use it. + (mips_expand_compare_and_swap_12): New function. + * config/mips/mips.h (MIPS_COMPARE_AND_SWAP_12): New macro. + 2008-04-25 Jan Hubicka PR testsuite/35843 diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index deb99a08867..fbac8fcfd07 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -292,5 +292,6 @@ 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); #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 94a14274533..86072acf4ab 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -1,6 +1,6 @@ /* Subroutines used for MIPS code generation. Copyright (C) 1989, 1990, 1991, 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. @@ -2121,6 +2121,19 @@ mips_emit_binary (enum rtx_code code, rtx target, rtx op0, rtx op1) gen_rtx_fmt_ee (code, GET_MODE (target), op0, op1))); } +/* Compute (CODE OP0 OP1) and store the result in a new register + of mode MODE. Return that new register. */ + +static rtx +mips_force_binary (enum machine_mode mode, enum rtx_code code, rtx op0, rtx op1) +{ + rtx reg; + + reg = gen_reg_rtx (mode); + mips_emit_binary (code, reg, op0, op1); + return reg; +} + /* Copy VALUE to a register and return that register. If new pseudos are allowed, copy it into a new register, otherwise use DEST. */ @@ -3741,8 +3754,10 @@ mips_emit_int_order_test (enum rtx_code code, bool *invert_ptr, } else if (invert_ptr == 0) { - rtx inv_target = gen_reg_rtx (GET_MODE (target)); - mips_emit_binary (inv_code, inv_target, cmp0, cmp1); + rtx inv_target; + + inv_target = mips_force_binary (GET_MODE (target), + inv_code, cmp0, cmp1); mips_emit_binary (XOR, target, inv_target, const1_rtx); } else @@ -5850,8 +5865,7 @@ mips_expand_synci_loop (rtx begin, rtx end) emit_insn (gen_synci (begin)); - cmp = gen_reg_rtx (Pmode); - mips_emit_binary (GTU, cmp, begin, end); + cmp = mips_force_binary (Pmode, GTU, begin, end); mips_emit_binary (PLUS, begin, begin, inc); @@ -5859,6 +5873,68 @@ 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. */ + +void +mips_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval) +{ + rtx orig_addr, memsi_addr, memsi, shift, shiftsi, unshifted_mask; + rtx mask, inverted_mask, oldvalsi, old_shifted, newvalsi, new_shifted, res; + + /* Compute the address of the containing SImode value. */ + orig_addr = force_reg (Pmode, XEXP (mem, 0)); + memsi_addr = mips_force_binary (Pmode, AND, orig_addr, + force_reg (Pmode, GEN_INT (-4))); + + /* Create a memory reference for it. */ + memsi = gen_rtx_MEM (SImode, memsi_addr); + set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER); + MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem); + + /* Work out the byte offset of the QImode or HImode value, + counting from the least significant byte. */ + shift = mips_force_binary (Pmode, AND, orig_addr, GEN_INT (3)); + if (TARGET_BIG_ENDIAN) + mips_emit_binary (XOR, shift, shift, + GEN_INT (GET_MODE (mem) == QImode ? 3 : 2)); + + /* Multiply by eight to convert the shift value from bytes to bits. */ + mips_emit_binary (ASHIFT, shift, shift, GEN_INT (3)); + + /* Make the final shift an SImode value, so that it can be used in + SImode operations. */ + shiftsi = force_reg (SImode, gen_lowpart (SImode, shift)); + + /* Set MASK to an inclusive mask of the QImode or HImode value. */ + unshifted_mask = GEN_INT (GET_MODE_MASK (GET_MODE (mem))); + unshifted_mask = force_reg (SImode, unshifted_mask); + mask = mips_force_binary (SImode, ASHIFT, unshifted_mask, shiftsi); + + /* Compute the equivalent exclusive mask. */ + inverted_mask = gen_reg_rtx (SImode); + emit_insn (gen_rtx_SET (VOIDmode, inverted_mask, + gen_rtx_NOT (SImode, mask))); + + /* Shift the old value into place. */ + oldvalsi = force_reg (SImode, gen_lowpart (SImode, oldval)); + old_shifted = mips_force_binary (SImode, ASHIFT, oldvalsi, shiftsi); + + /* Do the same for the new value. */ + newvalsi = force_reg (SImode, gen_lowpart (SImode, newval)); + new_shifted = mips_force_binary (SImode, ASHIFT, newvalsi, shiftsi); + + /* Do the SImode atomic access. */ + res = gen_reg_rtx (SImode); + emit_insn (gen_compare_and_swap_12 (res, memsi, mask, inverted_mask, + old_shifted, new_shifted)); + + /* 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 bitfield of WIDTH bits starting BITPOS bits into *OP. When returning true, update *OP, *LEFT and *RIGHT as follows: diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 3a0e58c96e6..cda433aa4f0 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -2904,6 +2904,30 @@ while (0) "\tnop\n" \ "2:\tsync%-%]%>%)" +/* 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. + + - 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%@,%4,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" + /* Return an asm string that atomically: - Sets memory reference %0 to %0 INSN %1. diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index cbdcdc6ed13..05adf2226d4 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -54,12 +54,13 @@ (UNSPEC_SYNCI 35) (UNSPEC_SYNC 36) (UNSPEC_COMPARE_AND_SWAP 37) - (UNSPEC_SYNC_OLD_OP 38) - (UNSPEC_SYNC_NEW_OP 39) - (UNSPEC_SYNC_EXCHANGE 40) - (UNSPEC_MEMORY_BARRIER 41) - (UNSPEC_SET_GOT_VERSION 42) - (UNSPEC_UPDATE_GOT_VERSION 43) + (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_ADDRESS_FIRST 100) @@ -4447,6 +4448,34 @@ } [(set_attr "length" "32")]) +(define_expand "sync_compare_and_swap" + [(match_operand:SHORT 0 "register_operand") + (match_operand:SHORT 1 "memory_operand") + (match_operand:SHORT 2 "general_operand") + (match_operand:SHORT 3 "general_operand")] + "GENERATE_LL_SC" +{ + mips_expand_compare_and_swap_12 (operands[0], operands[1], + operands[2], operands[3]); + DONE; +}) + +;; Helper insn for mips_expand_compare_and_swap_12. +(define_insn "compare_and_swap_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" "d") + (match_operand:SI 5 "register_operand" "d")] + UNSPEC_COMPARE_AND_SWAP_12))] + "GENERATE_LL_SC" +{ + return MIPS_COMPARE_AND_SWAP_12; +} + [(set_attr "length" "40")]) + (define_insn "sync_add" [(set (match_operand:GPR 0 "memory_operand" "+R,R") (unspec_volatile:GPR diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bbb71b265ed..8f91bfd5752 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2008-04-26 Richard Sandiford + + * gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: Expect + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 and + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 to be defined. + * gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Likewise. + 2008-04-25 Tobias Burnus * gfortran/array_constructor_23.f: Change REAL(10) into kind > 8. diff --git a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c index 72eff4da37c..4c642258f7b 100644 --- a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c +++ b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c @@ -1,11 +1,11 @@ /* { dg-do preprocess } */ /* { dg-mips-options "-mips2" } */ -#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 +#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) == defined (__mips16) #error nonono #endif -#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 +#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) == defined (__mips16) #error nonono #endif diff --git a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c index fed2b38a57f..4265e4167ba 100644 --- a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c +++ b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c @@ -1,11 +1,11 @@ /* { dg-do preprocess } */ /* { dg-mips-options "-mgp64" } */ -#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 +#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) == defined (__mips16) #error nonono #endif -#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 +#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) == defined (__mips16) #error nonono #endif