s390.c (s390_expand_mask_and_shift, [...]): New.

2005-12-07  Adrian Straetling  <straetling@de.ibm.com>

	* config/s390/s390.c (s390_expand_mask_and_shift, 
	struct alignment_context, init_alignment_context, 
	s390_expand_cs_hqi): New.
	* config/s390/s390-protos.h (s390_expand_cs_hqi): Declare.
	* config/s390/s390.md ("sync_compare_and_swaphi",
	"sync_compare_and_swapqi"): New pattern.

	* lib/target-supports.exp (check_effective_target_sync_char_short):
	Add s390*.

From-SVN: r108178
This commit is contained in:
Adrian Straetling 2005-12-07 19:56:32 +00:00 committed by Ulrich Weigand
parent 634010f7c8
commit 3093f076e1
6 changed files with 182 additions and 0 deletions

View file

@ -1,3 +1,12 @@
2005-12-07 Adrian Straetling <straetling@de.ibm.com>
* config/s390/s390.c (s390_expand_mask_and_shift,
struct alignment_context, init_alignment_context,
s390_expand_cs_hqi): New.
* config/s390/s390-protos.h (s390_expand_cs_hqi): Declare.
* config/s390/s390.md ("sync_compare_and_swaphi",
"sync_compare_and_swapqi"): New pattern.
2005-12-07 Daniel Berlin <dberlin@dberlin.org>
Fix PR tree-optimization/25291

View file

@ -75,6 +75,7 @@ extern void s390_expand_setmem (rtx, rtx, rtx);
extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx);
extern bool s390_expand_addcc (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
extern bool s390_expand_insv (rtx, rtx, rtx, rtx);
extern void s390_expand_cs_hqi (enum machine_mode, rtx, rtx, rtx, rtx);
extern rtx s390_return_addr_rtx (int, rtx);
extern rtx s390_back_chain_rtx (void);
extern rtx s390_emit_call (rtx, rtx, rtx, rtx);

View file

@ -3972,6 +3972,156 @@ s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
return false;
}
/* A subroutine of s390_expand_cs_hqi which returns a register which holds VAL
of mode MODE shifted by COUNT bits. */
static inline rtx
s390_expand_mask_and_shift (rtx val, enum machine_mode mode, rtx count)
{
val = expand_simple_binop (SImode, AND, val, GEN_INT (GET_MODE_MASK (mode)),
NULL_RTX, 1, OPTAB_DIRECT);
return expand_simple_binop (SImode, ASHIFT, val, count,
NULL_RTX, 1, OPTAB_DIRECT);
}
/* Structure to hold the initial parameters for a compare_and_swap operation
in HImode and QImode. */
struct alignment_context
{
rtx memsi; /* SI aligned memory location. */
rtx shift; /* Bit offset with regard to lsb. */
rtx modemask; /* Mask of the HQImode shifted by SHIFT bits. */
rtx modemaski; /* ~modemask */
bool aligned; /* True if memory is aliged, false else. */
};
/* A subroutine of s390_expand_cs_hqi to initialize the structure AC for
transparent simplifying, if the memory alignment is known to be at least
32bit. MEM is the memory location for the actual operation and MODE its
mode. */
static void
init_alignment_context (struct alignment_context *ac, rtx mem,
enum machine_mode mode)
{
ac->shift = GEN_INT (GET_MODE_SIZE (SImode) - GET_MODE_SIZE (mode));
ac->aligned = (MEM_ALIGN (mem) >= GET_MODE_BITSIZE (SImode));
if (ac->aligned)
ac->memsi = adjust_address (mem, SImode, 0); /* Memory is aligned. */
else
{
/* Alignment is unknown. */
rtx byteoffset, addr, align;
/* Force the address into a register. */
addr = force_reg (Pmode, XEXP (mem, 0));
/* Align it to SImode. */
align = expand_simple_binop (Pmode, AND, addr,
GEN_INT (-GET_MODE_SIZE (SImode)),
NULL_RTX, 1, OPTAB_DIRECT);
/* Generate MEM. */
ac->memsi = gen_rtx_MEM (SImode, align);
MEM_VOLATILE_P (ac->memsi) = MEM_VOLATILE_P (mem);
set_mem_align (ac->memsi, GET_MODE_BITSIZE (SImode));
/* Calculate shiftcount. */
byteoffset = expand_simple_binop (Pmode, AND, addr,
GEN_INT (GET_MODE_SIZE (SImode) - 1),
NULL_RTX, 1, OPTAB_DIRECT);
/* As we already have some offset, evaluate the remaining distance. */
ac->shift = expand_simple_binop (SImode, MINUS, ac->shift, byteoffset,
NULL_RTX, 1, OPTAB_DIRECT);
}
/* Shift is the byte count, but we need the bitcount. */
ac->shift = expand_simple_binop (SImode, MULT, ac->shift, GEN_INT (BITS_PER_UNIT),
NULL_RTX, 1, OPTAB_DIRECT);
/* Calculate masks. */
ac->modemask = expand_simple_binop (SImode, ASHIFT,
GEN_INT (GET_MODE_MASK (mode)), ac->shift,
NULL_RTX, 1, OPTAB_DIRECT);
ac->modemaski = expand_simple_unop (SImode, NOT, ac->modemask, NULL_RTX, 1);
}
/* Expand an atomic compare and swap operation for HImode and QImode. MEM is
the memory location, CMP the old value to compare MEM with and NEW the value
to set if CMP == MEM.
CMP is never in memory for compare_and_swap_cc because
expand_bool_compare_and_swap puts it into a register for later compare. */
void
s390_expand_cs_hqi (enum machine_mode mode, rtx target, rtx mem, rtx cmp, rtx new)
{
struct alignment_context ac;
rtx cmpv, newv, val, resv, cc;
rtx res = gen_reg_rtx (SImode);
rtx csloop = gen_label_rtx ();
rtx csend = gen_label_rtx ();
gcc_assert (register_operand (target, VOIDmode));
gcc_assert (MEM_P (mem));
init_alignment_context (&ac, mem, mode);
/* Shift the values to the correct bit positions. */
if (!(ac.aligned && MEM_P (cmp)))
cmp = s390_expand_mask_and_shift (cmp, mode, ac.shift);
if (!(ac.aligned && MEM_P (new)))
new = s390_expand_mask_and_shift (new, mode, ac.shift);
/* Load full word. Subsequent loads are performed by CS. */
val = expand_simple_binop (SImode, AND, ac.memsi, ac.modemaski,
NULL_RTX, 1, OPTAB_DIRECT);
/* Start CS loop. */
emit_label (csloop);
/* val = "<mem>00..0<mem>"
* cmp = "00..0<cmp>00..0"
* new = "00..0<new>00..0"
*/
/* Patch cmp and new with val at correct position. */
if (ac.aligned && MEM_P (cmp))
{
cmpv = force_reg (SImode, val);
store_bit_field (cmpv, GET_MODE_BITSIZE (mode), 0, SImode, cmp);
}
else
cmpv = force_reg (SImode, expand_simple_binop (SImode, IOR, cmp, val,
NULL_RTX, 1, OPTAB_DIRECT));
if (ac.aligned && MEM_P (new))
{
newv = force_reg (SImode, val);
store_bit_field (newv, GET_MODE_BITSIZE (mode), 0, SImode, new);
}
else
newv = force_reg (SImode, expand_simple_binop (SImode, IOR, new, val,
NULL_RTX, 1, OPTAB_DIRECT));
/* Emit compare_and_swap pattern. */
emit_insn (gen_sync_compare_and_swap_ccsi (res, ac.memsi, cmpv, newv));
/* Jump to end if we're done (likely?). */
s390_emit_jump (csend, s390_emit_compare (EQ, cmpv, ac.memsi));
/* Check for changes outside mode. */
resv = expand_simple_binop (SImode, AND, res, ac.modemaski,
NULL_RTX, 1, OPTAB_DIRECT);
cc = s390_emit_compare (NE, resv, val);
emit_move_insn (val, resv);
/* Loop internal if so. */
s390_emit_jump (csloop, cc);
emit_label (csend);
/* Return the correct part of the bitfield. */
convert_move (target, expand_simple_binop (SImode, LSHIFTRT, res, ac.shift,
NULL_RTX, 1, OPTAB_DIRECT), 1);
}
/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
We need to emit DTP-relative relocations. */

View file

@ -7270,6 +7270,22 @@
(compare:CCZ1 (match_dup 1) (match_dup 2)))])]
"")
(define_expand "sync_compare_and_swap<mode>"
[(parallel
[(set (match_operand:HQI 0 "register_operand" "")
(match_operand:HQI 1 "memory_operand" ""))
(set (match_dup 1)
(unspec_volatile:HQI
[(match_dup 1)
(match_operand:HQI 2 "general_operand" "")
(match_operand:HQI 3 "general_operand" "")]
UNSPECV_CAS))
(set (reg:CCZ1 CC_REGNUM)
(compare:CCZ1 (match_dup 1) (match_dup 2)))])]
""
"s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1],
operands[2], operands[3]); DONE;")
(define_expand "sync_compare_and_swap_cc<mode>"
[(parallel
[(set (match_operand:TDSI 0 "register_operand" "")

View file

@ -1,3 +1,8 @@
2005-12-07 Adrian Straetling <straetling@de.ibm.com>
* lib/target-supports.exp (check_effective_target_sync_char_short):
Add s390*.
2005-12-06 Janis Johnson <janis187@us.ibm.com>
* lib/gcc-dg.exp (cleanup-dump): Remove options from test name.

View file

@ -1380,6 +1380,7 @@ proc check_effective_target_sync_char_short { } {
|| [istarget i?86-*-*]
|| [istarget x86_64-*-*]
|| [istarget alpha*-*-*]
|| [istarget s390*-*-*]
|| [istarget powerpc*-*-*] } {
set et_sync_char_short_saved 1
}