rs6000.c (rs6000_expand_compare_and_swapqhi): New.
* config/rs6000/rs6000.c (rs6000_expand_compare_and_swapqhi): New. (rs6000_split_compare_and_swapqhi): New. * config/rs6000/sync.md (sync_compare_and_swap{hi,qi}): New. (sync_compare_and_swapqhi_internal): New. * config/rs6000/rs6000-protos.h: Declare. From-SVN: r109226
This commit is contained in:
parent
f1d592bed3
commit
9fc75b97f9
4 changed files with 147 additions and 1 deletions
|
@ -1,4 +1,12 @@
|
||||||
2005-12-31 Andrew Pinski <pinskia@ohysics.uc.edu>
|
2006-01-01 David Edelsohn <edelsohn@gnu.org>
|
||||||
|
|
||||||
|
* config/rs6000/rs6000.c (rs6000_expand_compare_and_swapqhi): New.
|
||||||
|
(rs6000_split_compare_and_swapqhi): New.
|
||||||
|
* config/rs6000/sync.md (sync_compare_and_swap{hi,qi}): New.
|
||||||
|
(sync_compare_and_swapqhi_internal): New.
|
||||||
|
* config/rs6000/rs6000-protos.h: Declare.
|
||||||
|
|
||||||
|
2005-12-31 Andrew Pinski <pinskia@physics.uc.edu>
|
||||||
|
|
||||||
PR tree-opt/25612
|
PR tree-opt/25612
|
||||||
* tree-ssa-pre.c (compute_avail): Treat the static chain decl as a
|
* tree-ssa-pre.c (compute_avail): Treat the static chain decl as a
|
||||||
|
|
|
@ -86,6 +86,8 @@ extern void rs6000_emit_sync (enum rtx_code, enum machine_mode,
|
||||||
rtx, rtx, rtx, rtx, bool);
|
rtx, rtx, rtx, rtx, bool);
|
||||||
extern void rs6000_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
|
extern void rs6000_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
|
||||||
extern void rs6000_split_compare_and_swap (rtx, rtx, rtx, rtx, rtx);
|
extern void rs6000_split_compare_and_swap (rtx, rtx, rtx, rtx, rtx);
|
||||||
|
extern void rs6000_expand_compare_and_swapqhi (rtx, rtx, rtx, rtx);
|
||||||
|
extern void rs6000_split_compare_and_swapqhi (rtx, rtx, rtx, rtx, rtx, rtx);
|
||||||
extern void rs6000_split_lock_test_and_set (rtx, rtx, rtx, rtx);
|
extern void rs6000_split_lock_test_and_set (rtx, rtx, rtx, rtx);
|
||||||
extern void rs6000_emit_swdivsf (rtx, rtx, rtx);
|
extern void rs6000_emit_swdivsf (rtx, rtx, rtx);
|
||||||
extern void rs6000_emit_swdivdf (rtx, rtx, rtx);
|
extern void rs6000_emit_swdivdf (rtx, rtx, rtx);
|
||||||
|
|
|
@ -12275,6 +12275,96 @@ rs6000_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
|
||||||
emit_insn (gen_isync ());
|
emit_insn (gen_isync ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval)
|
||||||
|
{
|
||||||
|
enum machine_mode mode = GET_MODE (mem);
|
||||||
|
rtx addrSI, align, wdst, shift, mask;
|
||||||
|
HOST_WIDE_INT shift_mask = mode == QImode ? 0x18 : 0x10;
|
||||||
|
HOST_WIDE_INT imask = GET_MODE_MASK (mode);
|
||||||
|
|
||||||
|
/* Shift amount for subword relative to aligned word. */
|
||||||
|
addrSI = force_reg (SImode, gen_lowpart_common (SImode, XEXP (mem, 0)));
|
||||||
|
shift = gen_reg_rtx (SImode);
|
||||||
|
emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
|
||||||
|
GEN_INT (shift_mask)));
|
||||||
|
emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
|
||||||
|
|
||||||
|
/* Shift and mask old value into position within word. */
|
||||||
|
oldval = convert_modes (SImode, mode, oldval, 1);
|
||||||
|
oldval = expand_binop (SImode, and_optab,
|
||||||
|
oldval, GEN_INT (imask), NULL_RTX,
|
||||||
|
1, OPTAB_LIB_WIDEN);
|
||||||
|
emit_insn (gen_ashlsi3 (oldval, oldval, shift));
|
||||||
|
|
||||||
|
/* Shift and mask new value into position within word. */
|
||||||
|
newval = convert_modes (SImode, mode, newval, 1);
|
||||||
|
newval = expand_binop (SImode, and_optab,
|
||||||
|
newval, GEN_INT (imask), NULL_RTX,
|
||||||
|
1, OPTAB_LIB_WIDEN);
|
||||||
|
emit_insn (gen_ashlsi3 (newval, newval, shift));
|
||||||
|
|
||||||
|
/* Mask for insertion. */
|
||||||
|
mask = gen_reg_rtx (SImode);
|
||||||
|
emit_move_insn (mask, GEN_INT (imask));
|
||||||
|
emit_insn (gen_ashlsi3 (mask, mask, shift));
|
||||||
|
|
||||||
|
/* Address of aligned word containing subword. */
|
||||||
|
align = expand_binop (Pmode, and_optab, XEXP (mem, 0), GEN_INT (-4),
|
||||||
|
NULL_RTX, 1, OPTAB_LIB_WIDEN);
|
||||||
|
mem = change_address (mem, SImode, align);
|
||||||
|
set_mem_align (mem, 32);
|
||||||
|
MEM_VOLATILE_P (mem) = 1;
|
||||||
|
|
||||||
|
wdst = gen_reg_rtx (SImode);
|
||||||
|
emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask,
|
||||||
|
oldval, newval, mem));
|
||||||
|
|
||||||
|
emit_move_insn (dst, gen_lowpart (mode, wdst));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rs6000_split_compare_and_swapqhi (rtx dest, rtx mask,
|
||||||
|
rtx oldval, rtx newval, rtx mem,
|
||||||
|
rtx scratch)
|
||||||
|
{
|
||||||
|
rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
|
||||||
|
|
||||||
|
emit_insn (gen_memory_barrier ());
|
||||||
|
label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
|
||||||
|
label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
|
||||||
|
emit_label (XEXP (label1, 0));
|
||||||
|
|
||||||
|
emit_load_locked (SImode, scratch, mem);
|
||||||
|
|
||||||
|
/* Mask subword within loaded value for comparison with oldval.
|
||||||
|
Use UNSPEC_AND to avoid clobber.*/
|
||||||
|
emit_insn (gen_rtx_SET (SImode, dest,
|
||||||
|
gen_rtx_UNSPEC (SImode,
|
||||||
|
gen_rtvec (2, scratch, mask),
|
||||||
|
UNSPEC_AND)));
|
||||||
|
|
||||||
|
x = gen_rtx_COMPARE (CCmode, dest, oldval);
|
||||||
|
emit_insn (gen_rtx_SET (VOIDmode, cond, x));
|
||||||
|
|
||||||
|
x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
|
||||||
|
emit_unlikely_jump (x, label2);
|
||||||
|
|
||||||
|
/* Clear subword within loaded value for insertion of new value. */
|
||||||
|
emit_insn (gen_rtx_SET (SImode, scratch,
|
||||||
|
gen_rtx_AND (SImode,
|
||||||
|
gen_rtx_NOT (SImode, mask), scratch)));
|
||||||
|
emit_insn (gen_iorsi3 (scratch, scratch, newval));
|
||||||
|
emit_store_conditional (SImode, cond, mem, scratch);
|
||||||
|
|
||||||
|
x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
|
||||||
|
emit_unlikely_jump (x, label1);
|
||||||
|
|
||||||
|
emit_insn (gen_isync ());
|
||||||
|
emit_label (XEXP (label2, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Emit instructions to move SRC to DST. Called by splitters for
|
/* Emit instructions to move SRC to DST. Called by splitters for
|
||||||
multi-register moves. It will emit at most one instruction for
|
multi-register moves. It will emit at most one instruction for
|
||||||
each register that is accessed; that is, it won't emit li/lis pairs
|
each register that is accessed; that is, it won't emit li/lis pairs
|
||||||
|
|
|
@ -86,6 +86,52 @@
|
||||||
DONE;
|
DONE;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
(define_expand "sync_compare_and_swaphi"
|
||||||
|
[(match_operand:HI 0 "gpc_reg_operand" "")
|
||||||
|
(match_operand:HI 1 "memory_operand" "")
|
||||||
|
(match_operand:HI 2 "gpc_reg_operand" "")
|
||||||
|
(match_operand:HI 3 "gpc_reg_operand" "")]
|
||||||
|
"TARGET_POWERPC"
|
||||||
|
{
|
||||||
|
rs6000_expand_compare_and_swapqhi (operands[0], operands[1],
|
||||||
|
operands[2], operands[3]);
|
||||||
|
DONE;
|
||||||
|
})
|
||||||
|
|
||||||
|
(define_expand "sync_compare_and_swapqi"
|
||||||
|
[(match_operand:QI 0 "gpc_reg_operand" "")
|
||||||
|
(match_operand:QI 1 "memory_operand" "")
|
||||||
|
(match_operand:QI 2 "gpc_reg_operand" "")
|
||||||
|
(match_operand:QI 3 "gpc_reg_operand" "")]
|
||||||
|
"TARGET_POWERPC"
|
||||||
|
{
|
||||||
|
rs6000_expand_compare_and_swapqhi (operands[0], operands[1],
|
||||||
|
operands[2], operands[3]);
|
||||||
|
DONE;
|
||||||
|
})
|
||||||
|
|
||||||
|
(define_insn_and_split "sync_compare_and_swapqhi_internal"
|
||||||
|
[(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
|
||||||
|
(match_operand:SI 4 "memory_operand" "+Z"))
|
||||||
|
(set (match_dup 4)
|
||||||
|
(unspec:SI
|
||||||
|
[(match_operand:SI 1 "gpc_reg_operand" "r")
|
||||||
|
(match_operand:SI 2 "gpc_reg_operand" "r")
|
||||||
|
(match_operand:SI 3 "gpc_reg_operand" "r")]
|
||||||
|
UNSPEC_CMPXCHG))
|
||||||
|
(clobber (match_scratch:SI 5 "=&r"))
|
||||||
|
(clobber (match_scratch:CC 6 "=&x"))]
|
||||||
|
"TARGET_POWERPC"
|
||||||
|
"#"
|
||||||
|
"&& reload_completed"
|
||||||
|
[(const_int 0)]
|
||||||
|
{
|
||||||
|
rs6000_split_compare_and_swapqhi (operands[0], operands[1],
|
||||||
|
operands[2], operands[3], operands[4],
|
||||||
|
operands[5]);
|
||||||
|
DONE;
|
||||||
|
})
|
||||||
|
|
||||||
(define_insn_and_split "sync_lock_test_and_set<mode>"
|
(define_insn_and_split "sync_lock_test_and_set<mode>"
|
||||||
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
|
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
|
||||||
(match_operand:GPR 1 "memory_operand" "+Z"))
|
(match_operand:GPR 1 "memory_operand" "+Z"))
|
||||||
|
|
Loading…
Add table
Reference in a new issue