]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
s390.c (s390_expand_mask_and_shift, [...]): New.
authorAdrian Straetling <straetling@de.ibm.com>
Wed, 7 Dec 2005 19:56:32 +0000 (19:56 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Wed, 7 Dec 2005 19:56:32 +0000 (19:56 +0000)
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

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.md
gcc/testsuite/ChangeLog
gcc/testsuite/lib/target-supports.exp

index f6f3e08f5b6885bf7fc6c4d83e92c0a5f27d8dac..b7b8ff80509d024c0252b558abf66d0a8c9a0ae3 100644 (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
index 42eecdbfcf64fcc89911fcd7b1f12ea53a556032..bb1516a88e52d5161aacfdd246c2950a6076a021 100644 (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);
index d9dc288e062a5b530345df4ac24e1e41f0ad17e7..880ebdd108317b4b5de02a53e5e7f2ffd464effc 100644 (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.  */
 
index 4bf6d8a8854393a55c1b7fae92263850ea30cf2f..d75015d5688a15cdd3e803fe091ea79fc48bd883 100644 (file)
          (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" "")
index 45d0af7a9ac675fa05e7e584aa5bde2444bc2abe..ec769baab19a7db3bb36abc86b833c648f7bd3a1 100644 (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.
index d2400956accf5ae53e1ea086e483f4c436d9cd6f..edafc749b52264bfca3c4183872ad42b87bc9fad 100644 (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
         }