aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/s390/s390.c
diff options
context:
space:
mode:
authorAdrian Straetling <straetling@de.ibm.com>2005-12-07 20:01:30 +0000
committerUlrich Weigand <uweigand@gcc.gnu.org>2005-12-07 20:01:30 +0000
commit45d18331f6fef4363e14fd19871ef765d1203472 (patch)
tree37f5267f112834ab802c16d730d210dd4de74128 /gcc/config/s390/s390.c
parent3093f076e124d0d02ef4460e7c47289fdd567c31 (diff)
downloadgcc-45d18331f6fef4363e14fd19871ef765d1203472.zip
gcc-45d18331f6fef4363e14fd19871ef765d1203472.tar.gz
gcc-45d18331f6fef4363e14fd19871ef765d1203472.tar.bz2
s390.c (s390_expand_atomic): New function.
2005-12-07 Adrian Straetling <straetling@de.ibm.com> * config/s390/s390.c (s390_expand_atomic): New function. Adjust comment of helper functions. * config/s390/s390-protos.h (s390_expand_atomic): Declare. * config/s390/s390.md ("ATOMIC"): New code macro. ("atomic"): Corresponding new code attribute. ("sync_lock_test_and_set[hq]i", "sync_{new_,old_,}{and,ior,xor,add,sub,nand}[hq]i"): New pattern. From-SVN: r108180
Diffstat (limited to 'gcc/config/s390/s390.c')
-rw-r--r--gcc/config/s390/s390.c103
1 files changed, 97 insertions, 6 deletions
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 880ebdd..901b9b5 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -3972,8 +3972,8 @@ 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. */
+/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic which returns a
+ register that 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)
@@ -3996,10 +3996,10 @@ struct alignment_context
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. */
+/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic to initialize
+ 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,
@@ -4122,6 +4122,97 @@ s390_expand_cs_hqi (enum machine_mode mode, rtx target, rtx mem, rtx cmp, rtx ne
NULL_RTX, 1, OPTAB_DIRECT), 1);
}
+/* Expand an atomic operation CODE of mode MODE. MEM is the memory location
+ and VAL the value to play with. If AFTER is true then store the the value
+ MEM holds after the operation, if AFTER is false then store the value MEM
+ holds before the operation. If TARGET is zero then discard that value, else
+ store it to TARGET. */
+
+void
+s390_expand_atomic (enum machine_mode mode, enum rtx_code code,
+ rtx target, rtx mem, rtx val, bool after)
+{
+ struct alignment_context ac;
+ rtx cmp;
+ rtx new = gen_reg_rtx (SImode);
+ rtx orig = gen_reg_rtx (SImode);
+ rtx csloop = gen_label_rtx ();
+
+ gcc_assert (!target || register_operand (target, VOIDmode));
+ gcc_assert (MEM_P (mem));
+
+ init_alignment_context (&ac, mem, mode);
+
+ /* Shift val to the correct bit positions.
+ Preserve "icm", but prevent "ex icm". */
+ if (!(ac.aligned && code == SET && MEM_P (val)))
+ val = s390_expand_mask_and_shift (val, mode, ac.shift);
+
+ /* Further preparation insns. */
+ if (code == PLUS || code == MINUS)
+ emit_move_insn (orig, val);
+ else if (code == MULT || code == AND) /* val = "11..1<val>11..1" */
+ val = expand_simple_binop (SImode, XOR, val, ac.modemaski,
+ NULL_RTX, 1, OPTAB_DIRECT);
+
+ /* Load full word. Subsequent loads are performed by CS. */
+ cmp = force_reg (SImode, ac.memsi);
+
+ /* Start CS loop. */
+ emit_label (csloop);
+ emit_move_insn (new, cmp);
+
+ /* Patch new with val at correct position. */
+ switch (code)
+ {
+ case PLUS:
+ case MINUS:
+ val = expand_simple_binop (SImode, code, new, orig,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ val = expand_simple_binop (SImode, AND, val, ac.modemask,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ /* FALLTHRU */
+ case SET:
+ if (ac.aligned && MEM_P (val))
+ store_bit_field (new, GET_MODE_BITSIZE (mode), 0, SImode, val);
+ else
+ {
+ new = expand_simple_binop (SImode, AND, new, ac.modemaski,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ new = expand_simple_binop (SImode, IOR, new, val,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ }
+ break;
+ case AND:
+ case IOR:
+ case XOR:
+ new = expand_simple_binop (SImode, code, new, val,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ break;
+ case MULT: /* NAND */
+ new = expand_simple_binop (SImode, XOR, new, ac.modemask,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ new = expand_simple_binop (SImode, AND, new, val,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ /* Emit compare_and_swap pattern. */
+ emit_insn (gen_sync_compare_and_swap_ccsi (cmp, ac.memsi, cmp, new));
+
+ /* Loop until swapped (unlikely?). */
+ s390_emit_jump (csloop, gen_rtx_fmt_ee (NE, CCZ1mode,
+ gen_rtx_REG (CCZ1mode, CC_REGNUM),
+ const0_rtx));
+
+ /* Return the correct part of the bitfield. */
+ if (target)
+ convert_move (target, expand_simple_binop (SImode, LSHIFTRT,
+ after ? new : cmp, 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. */