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:
parent
634010f7c8
commit
3093f076e1
6 changed files with 182 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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" "")
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue