This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: Implement more MIPS QI andHI atomic memory operations.


This is a prototype of a patch I am considering that implements
optimized versions of all atomic memory primitives for QI and HI modes
on MIPS.

This version only adds sync_lock_test_and_set{QI,HI}, if the approach is
deemed acceptable I would add sync_{old,new}_{add,sub,ior,and,xor,nand}
for the final patch.

I have made the expand function that fixes up the address and generates
masks more general so that it takes a pointer to a generator function
that generates the SI mode underlying atomic primitive.  Then in the .md
file the define_expand passes a pointer to the required generator
function when calling the expander.

Q1: Is is ok to pass a union of function pointers to the expander?

Q2:  Should all the atomic insns be put in a seperate sync.md as they
are for several other targets (sparc, i386...)?

Q3: What is the namespace of the unspec_volatile numbers?  Or: when and
why do I have to define new numbers?

Q4: Is there a better way to accomplish this?

2008-05-09  David Daney  <ddaney@avtrex.com>

    * config/mips/mips.md (sync_compare_and_swap<mode>): Call
    mips_expand_atomic_qihi instead of
    mips_expand_compare_and_swap_12.
    (sync_lock_test_and_set<mode>): New define_expand.
    (test_and_set_12): New insn.
    * config/mips/mips-protos.h (mips_gen_fn_6, mips_gen_fn_5,
    mips_gen_fn_4): New typedefs.
    (mips_expand_compare_and_swap_12): Remove declaration.
    (mips_expand_atomic_qihi): Declare function.
    * config/mips/mips.c (mips_expand_compare_and_swap_12): Rename to...
    (mips_expand_atomic_qihi): ... this.  Use new generator function
    parameter.
    * config/mips/mips.h (MIPS_SYNC_EXCHANGE_12): New macro.
    (MIPS_SYNC_EXCHANGE_12_0): Same.

Index: config/mips/mips.md
===================================================================
--- config/mips/mips.md	(revision 135124)
+++ config/mips/mips.md	(working copy)
@@ -4455,8 +4455,10 @@ (define_expand "sync_compare_and_swap<mo
    (match_operand:SHORT 3 "general_operand")]
   "GENERATE_LL_SC"
 {
-  mips_expand_compare_and_swap_12 (operands[0], operands[1],
-				   operands[2], operands[3]);
+  union mips_gen_fn_ptrs generator;
+  generator.fn_6 = gen_compare_and_swap_12;
+  mips_expand_atomic_qihi (generator, true,
+			   operands[0], operands[1], operands[2], operands[3]);
   DONE;
 })
 
@@ -4674,6 +4676,35 @@ (define_insn "sync_lock_test_and_set<mod
     return MIPS_SYNC_EXCHANGE ("<d>", "move");
 }
   [(set_attr "length" "24")])
+
+(define_expand "sync_lock_test_and_set<mode>"
+  [(match_operand:SHORT 0 "register_operand")
+   (match_operand:SHORT 1 "memory_operand")
+   (match_operand:SHORT 2 "general_operand")]
+  "GENERATE_LL_SC"
+{
+  union mips_gen_fn_ptrs generator;
+  generator.fn_4 = gen_test_and_set_12;
+  mips_expand_atomic_qihi (generator, false,
+			   operands[0], operands[1], operands[2], NULL);
+  DONE;
+})
+
+(define_insn "test_and_set_12"
+  [(set (match_operand:SI 0 "register_operand" "=d,&d")
+	(match_operand:SI 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
+			     (match_operand:SI 3 "arith_operand" "d,J")]
+	 UNSPEC_SYNC_EXCHANGE))]
+  "GENERATE_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_EXCHANGE_12;
+  else
+    return MIPS_SYNC_EXCHANGE_12_0;
+}
+  [(set_attr "length" "28,24")])
 
 ;; Block moves, see mips.c for more details.
 ;; Argument 0 is the destination
Index: config/mips/mips-protos.h
===================================================================
--- config/mips/mips-protos.h	(revision 135124)
+++ config/mips/mips-protos.h	(working copy)
@@ -292,6 +292,17 @@ extern bool mips_use_ins_ext_p (rtx, HOS
 extern const char *mips16e_output_save_restore (rtx, HOST_WIDE_INT);
 extern bool mips16e_save_restore_pattern_p (rtx, HOST_WIDE_INT,
 					    struct mips16e_save_restore_info *);
-extern void mips_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx);
+typedef rtx (*mips_gen_fn_6) (rtx, rtx, rtx, rtx, rtx, rtx);
+typedef rtx (*mips_gen_fn_5) (rtx, rtx, rtx, rtx, rtx);
+typedef rtx (*mips_gen_fn_4) (rtx, rtx, rtx, rtx);
+union mips_gen_fn_ptrs
+{
+  mips_gen_fn_6 fn_6;
+  mips_gen_fn_5 fn_5;
+  mips_gen_fn_4 fn_4;
+};
+
+extern void mips_expand_atomic_qihi (union mips_gen_fn_ptrs, bool,
+				     rtx, rtx, rtx, rtx);
 
 #endif /* ! GCC_MIPS_PROTOS_H */
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 135124)
+++ config/mips/mips.c	(working copy)
@@ -5873,14 +5873,30 @@ mips_expand_synci_loop (rtx begin, rtx e
   emit_jump_insn (gen_condjump (cmp_result, label));
 }
 
-/* Expand a QI or HI mode compare_and_swap.  The operands are the same
-   as for the generator function.  */
+/* Expand a QI or HI mode atomic memory operation.
+
+   GENERATOR contains a pointer to the gen_* function that generates
+   the SI mode underlying atomic operation using masks that we
+   calculate.
+
+   NEED_MASK indicates that the GENERATOR needs the inclusive mask as
+   its third argument.
+
+   RESULT is the return register for the operation.
+
+   MEM is the location of the atomic access.
+
+   OLDVAL is the first operand for the operation.
+
+   NEWVAL is the optional second operand for the operation.  Its value
+   is NULL if unused.  */
 
 void
-mips_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+mips_expand_atomic_qihi (union mips_gen_fn_ptrs generator, bool need_mask,
+                         rtx result, rtx mem, rtx oldval, rtx newval)
 {
   rtx orig_addr, memsi_addr, memsi, shift, shiftsi, unshifted_mask;
-  rtx unshifted_mask_reg, mask, inverted_mask, res;
+  rtx unshifted_mask_reg, mask, inverted_mask, res, si_op;
   enum machine_mode mode;
 
   mode = GET_MODE (mem);
@@ -5927,7 +5943,7 @@ mips_expand_compare_and_swap_12 (rtx res
     }
 
   /* Do the same for the new value.  */
-  if (newval != const0_rtx)
+  if (newval && newval != const0_rtx)
     {
       newval = convert_modes (SImode, mode, newval, true);
       newval = force_reg (SImode, newval);
@@ -5936,8 +5952,13 @@ mips_expand_compare_and_swap_12 (rtx res
 
   /* Do the SImode atomic access.  */
   res = gen_reg_rtx (SImode);
-  emit_insn (gen_compare_and_swap_12 (res, memsi, mask, inverted_mask,
-				      oldval, newval));
+  if (newval)
+    si_op = generator.fn_6 (res, memsi, mask, inverted_mask, oldval, newval);
+  else if (need_mask)
+    si_op = generator.fn_5 (res, memsi, mask, inverted_mask, oldval);
+  else
+    si_op = generator.fn_4 (res, memsi, inverted_mask, oldval);
+  emit_insn (si_op);
 
   /* Shift and convert the result.  */
   mips_emit_binary (AND, res, res, mask);
Index: config/mips/mips.h
===================================================================
--- config/mips/mips.h	(revision 135124)
+++ config/mips/mips.h	(working copy)
@@ -3065,6 +3065,37 @@ while (0)
   "\tnop\n"					\
   "\tsync%-%]%>%)"
 
+/* Return an asm string that atomically:
+
+     - Given that %2 contains an exclusive mask and %3 has already
+       been ANDed with the inclusive mask.
+
+     - Sets bits selected by the inclusive mask of memory reference %1
+       to %3.
+
+     - Sets register %0 to the old value of memory reference %1.
+  */
+#define MIPS_SYNC_EXCHANGE_12			\
+  "%(%<%[%|\n"					\
+  "1:\tll\t%0,%1\n"				\
+  "\tand\t%@,%0,%2\n"				\
+  "\tor\t%@,%@,%3\n"				\
+  "\tsc\t%@,%1\n"				\
+  "\tbeq\t%@,%.,1b\n"				\
+  "\tnop\n"					\
+  "\tsync%-%]%>%)"
+
+/* Like MIPS_SYNC_EXCHANGE_12, except %3 is a constant zero, so the OR
+   can be omitted.  */
+#define MIPS_SYNC_EXCHANGE_12_0			\
+  "%(%<%[%|\n"					\
+  "1:\tll\t%0,%1\n"				\
+  "\tand\t%@,%0,%2\n"				\
+  "\tsc\t%@,%1\n"				\
+  "\tbeq\t%@,%.,1b\n"				\
+  "\tnop\n"					\
+  "\tsync%-%]%>%)"
+
 #ifndef USED_FOR_TARGET
 extern const enum reg_class mips_regno_to_class[];
 extern bool mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]