s390.c (s390_expand_atomic): New function.
authorAdrian Straetling <straetling@de.ibm.com>
Wed, 7 Dec 2005 20:01:30 +0000 (20:01 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Wed, 7 Dec 2005 20:01:30 +0000 (20:01 +0000)
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

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.md

index b7b8ff80509d024c0252b558abf66d0a8c9a0ae3..37f83ad477395732feeaea638961a185c4a91b81 100644 (file)
@@ -1,3 +1,13 @@
+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.
+
 2005-12-07  Adrian Straetling  <straetling@de.ibm.com>
 
        * config/s390/s390.c (s390_expand_mask_and_shift, 
index bb1516a88e52d5161aacfdd246c2950a6076a021..e62493d1bb0dc25b17f1ce4c8c0f2e629a56b943 100644 (file)
@@ -76,6 +76,8 @@ 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 void s390_expand_atomic (enum machine_mode, enum rtx_code, 
+                               rtx, rtx, rtx, bool);
 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 880ebdd108317b4b5de02a53e5e7f2ffd464effc..901b9b5f8607715532c310132c8638596bfb0de5 100644 (file)
@@ -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.  */
 
index d75015d5688a15cdd3e803fe091ea79fc48bd883..cf484c3bc202d07292dc428cce564175532238ad 100644 (file)
 ;; the same template.
 (define_code_macro SHIFT [ashift lshiftrt])
 
+;; These macros allow to combine most atomic operations.
+(define_code_macro ATOMIC [and ior xor plus minus mult])
+(define_code_attr atomic [(and "and") (ior "ior") (xor "xor") 
+                         (plus "add") (minus "sub") (mult "nand")])
+
 
 ;; In FPR templates, a string like "lt<de>br" will expand to "ltdbr" in DFmode
 ;; and "ltebr" in SFmode.
    (set_attr "type"   "sem")])
 
 
+;
+; Other atomic instruction patterns.
+;
+
+(define_expand "sync_lock_test_and_set<mode>"
+  [(match_operand:HQI 0 "register_operand")
+   (match_operand:HQI 1 "memory_operand")
+   (match_operand:HQI 2 "general_operand")]
+  ""
+  "s390_expand_atomic (<MODE>mode, SET, operands[0], operands[1], 
+                      operands[2], false); DONE;")
+
+(define_expand "sync_<atomic><mode>"
+  [(set (match_operand:HQI 0 "memory_operand")
+       (ATOMIC:HQI (match_dup 0)
+                   (match_operand:HQI 1 "general_operand")))]
+  ""
+  "s390_expand_atomic (<MODE>mode, <CODE>, NULL_RTX, operands[0], 
+                      operands[1], false); DONE;")
+
+(define_expand "sync_old_<atomic><mode>"
+  [(set (match_operand:HQI 0 "register_operand")
+       (match_operand:HQI 1 "memory_operand"))
+   (set (match_dup 1)
+       (ATOMIC:HQI (match_dup 1)
+                   (match_operand:HQI 2 "general_operand")))]
+  ""
+  "s390_expand_atomic (<MODE>mode, <CODE>, operands[0], operands[1], 
+                      operands[2], false); DONE;")
+
+(define_expand "sync_new_<atomic><mode>"
+  [(set (match_operand:HQI 0 "register_operand")
+       (ATOMIC:HQI (match_operand:HQI 1 "memory_operand")
+                   (match_operand:HQI 2 "general_operand"))) 
+   (set (match_dup 1) (ATOMIC:HQI (match_dup 1) (match_dup 2)))]
+  ""
+  "s390_expand_atomic (<MODE>mode, <CODE>, operands[0], operands[1], 
+                      operands[2], true); DONE;")
+
 ;;
 ;;- Miscellaneous instructions.
 ;;