mips.md (UNSPEC_COMPARE_AND_SWAP_12): New unspec_volitile.

gcc/
2008-04-23  David Daney  <ddaney@avtrex.com>

	* 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<mode>): 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
This commit is contained in:
Richard Sandiford 2008-04-26 07:40:04 +00:00
parent a93a597ae7
commit 49bce30a21
8 changed files with 167 additions and 15 deletions

View File

@ -1,3 +1,18 @@
2008-04-26 David Daney <ddaney@avtrex.com>
* 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<mode>): 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 <jh@suse.cz>
PR testsuite/35843

View File

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

View File

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

View File

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

View File

@ -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<mode>"
[(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<mode>"
[(set (match_operand:GPR 0 "memory_operand" "+R,R")
(unspec_volatile:GPR

View File

@ -1,3 +1,10 @@
2008-04-26 Richard Sandiford <rsandifo@nildram.co.uk>
* 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 <burnus@net-b.de>
* gfortran/array_constructor_23.f: Change REAL(10) into kind > 8.

View File

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

View File

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