diff gcc/config/mips/sync.md @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/config/mips/sync.md	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/config/mips/sync.md	Fri Oct 27 22:46:09 2017 +0900
@@ -1,7 +1,6 @@
 ;;  Machine Description for MIPS based processor synchronization
 ;;  instructions.
-;;  Copyright (C) 2007, 2008, 2009, 2010
-;;  Free Software Foundation, Inc.
+;;  Copyright (C) 2007-2017 Free Software Foundation, Inc.
 
 ;; This file is part of GCC.
 
@@ -29,6 +28,9 @@
   UNSPEC_SYNC_EXCHANGE
   UNSPEC_SYNC_EXCHANGE_12
   UNSPEC_MEMORY_BARRIER
+  UNSPEC_ATOMIC_COMPARE_AND_SWAP
+  UNSPEC_ATOMIC_EXCHANGE
+  UNSPEC_ATOMIC_FETCH_OP
 ])
 
 ;; Atomic fetch bitwise operations.
@@ -54,9 +56,10 @@
   "GENERATE_SYNC"
   { return mips_output_sync (); })
 
+;; Can be removed in favor of atomic_compare_and_swap below.
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
@@ -86,7 +89,7 @@
 ;; Helper insn for mips_expand_atomic_qihi.
 (define_insn "compare_and_swap_12"
   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-	(match_operand:SI 1 "memory_operand" "+R,R"))
+	(match_operand:SI 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
 			     (match_operand:SI 3 "register_operand" "d,d")
@@ -103,7 +106,7 @@
    (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZC,ZC")
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 0)
 		     (match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -131,12 +134,12 @@
 
 ;; Helper insn for sync_<optab><mode>
 (define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZC")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
-			      (match_operand:SI 3 "register_operand" "dJ"))]
+			      (match_operand:SI 3 "reg_or_0_operand" "dJ"))]
 	  UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 4 "=&d"))]
   "GENERATE_LL_SC"
@@ -171,13 +174,13 @@
 ;; Helper insn for sync_old_<optab><mode>
 (define_insn "sync_old_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZC"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
-			      (match_operand:SI 4 "register_operand" "dJ"))]
+			      (match_operand:SI 4 "reg_or_0_operand" "dJ"))]
 	  UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 5 "=&d"))]
   "GENERATE_LL_SC"
@@ -214,11 +217,11 @@
 (define_insn "sync_new_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZC")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
-			      (match_operand:SI 4 "register_operand" "dJ"))]
+			      (match_operand:SI 4 "reg_or_0_operand" "dJ"))]
 	  UNSPEC_SYNC_NEW_OP_12))
    (set (match_dup 1)
 	(unspec_volatile:SI
@@ -254,12 +257,12 @@
 
 ;; Helper insn for sync_nand<mode>
 (define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZC")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_dup 0)
-	   (match_operand:SI 3 "register_operand" "dJ")]
+	   (match_operand:SI 3 "reg_or_0_operand" "dJ")]
 	  UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 4 "=&d"))]
   "GENERATE_LL_SC"
@@ -293,12 +296,12 @@
 ;; Helper insn for sync_old_nand<mode>
 (define_insn "sync_old_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZC"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
-	   (match_operand:SI 4 "register_operand" "dJ")]
+	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
 	  UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 5 "=&d"))]
   "GENERATE_LL_SC"
@@ -334,10 +337,10 @@
 (define_insn "sync_new_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZC")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
-	   (match_operand:SI 4 "register_operand" "dJ")]
+	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
 	  UNSPEC_SYNC_NEW_OP_12))
    (set (match_dup 1)
 	(unspec_volatile:SI
@@ -357,7 +360,7 @@
    (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZC")
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
 		      (match_operand:GPR 1 "register_operand" "d"))]
@@ -368,9 +371,10 @@
    (set_attr "sync_mem" "0")
    (set_attr "sync_insn1_op2" "1")])
 
+;; Can be removed in favor of atomic_fetch_add below.
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 1)
@@ -385,7 +389,7 @@
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-	(match_operand:GPR 1 "memory_operand" "+R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 1)
@@ -400,7 +404,7 @@
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZC,ZC")
 		  (match_operand:GPR 2 "arith_operand" "I,d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -416,7 +420,7 @@
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZC")
 		   (match_operand:GPR 2 "register_operand" "d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -431,7 +435,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZC,ZC")
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
@@ -444,7 +448,7 @@
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -459,7 +463,7 @@
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -474,7 +478,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZC,ZC")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
@@ -486,7 +490,7 @@
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
@@ -500,7 +504,7 @@
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
@@ -515,13 +519,13 @@
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
   "GENERATE_LL_SC"
   { return mips_output_sync_loop (insn, operands); }
-  [(set_attr "sync_release_barrier" "no")
+  [(set_attr "sync_memmodel" "11")
    (set_attr "sync_insn1" "li,move")
    (set_attr "sync_oldval" "0")
    (set_attr "sync_mem" "1")
@@ -542,15 +546,15 @@
 
 (define_insn "test_and_set_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZC"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
 			     (match_operand:SI 3 "register_operand" "d")
-			     (match_operand:SI 4 "arith_operand" "dJ")]
+			     (match_operand:SI 4 "reg_or_0_operand" "dJ")]
 	  UNSPEC_SYNC_EXCHANGE_12))]
   "GENERATE_LL_SC"
   { return mips_output_sync_loop (insn, operands); }
-  [(set_attr "sync_release_barrier" "no")
+  [(set_attr "sync_memmodel" "11")
    (set_attr "sync_oldval" "0")
    (set_attr "sync_mem" "1")
    ;; Unused, but needed to give the number of operands expected by
@@ -558,3 +562,155 @@
    (set_attr "sync_inclusive_mask" "2")
    (set_attr "sync_exclusive_mask" "3")
    (set_attr "sync_insn1_op2" "4")])
+
+(define_insn "atomic_compare_and_swap<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
+	;; Logically this unspec is an "eq" operator, but we need to obscure
+	;; reads and writes from/to memory with an unspec to prevent
+	;; optimizations on shared memory locations.  Otherwise, comparison in
+	;; { mem = 2; if (atomic_cmp_swap(mem,...) == 2) ...; }
+	;; would be optimized away.  In addition to that we need to use
+	;; unspec_volatile, not just plain unspec -- for the sake of other
+	;; threads -- to make sure we don't remove the entirety of the pattern
+	;; just because current thread doesn't observe any effect from it.
+	;; TODO: the obscuring unspec can be relaxed for permissive memory
+	;; models.
+	;; Same applies to other atomic_* patterns.
+	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZC,ZC")
+			      (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
+	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
+   (set (match_operand:GPR 1 "register_operand" "=&d,&d")
+	(unspec_volatile:GPR [(match_dup 2)]
+	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
+   (set (match_dup 2)
+	(unspec_volatile:GPR [(match_dup 2)
+			      (match_dup 3)
+			      (match_operand:GPR 4 "arith_operand" "I,d")]
+	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
+   (unspec_volatile:GPR [(match_operand:SI 5 "const_int_operand")
+			 (match_operand:SI 6 "const_int_operand")
+			 (match_operand:SI 7 "const_int_operand")]
+    UNSPEC_ATOMIC_COMPARE_AND_SWAP)]
+  "GENERATE_LL_SC"
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "li,move")
+   (set_attr "sync_oldval" "1")
+   (set_attr "sync_cmp" "0")
+   (set_attr "sync_mem" "2")
+   (set_attr "sync_required_oldval" "3")
+   (set_attr "sync_insn1_op2" "4")
+   (set_attr "sync_memmodel" "6")])
+
+(define_expand "atomic_exchange<mode>"
+  [(match_operand:GPR 0 "register_operand")
+   (match_operand:GPR 1 "memory_operand")
+   (match_operand:GPR 2 "arith_operand")
+   (match_operand:SI 3 "const_int_operand")]
+  "GENERATE_LL_SC || ISA_HAS_SWAP"
+{
+  if (ISA_HAS_SWAP)
+    {
+      if (!mem_noofs_operand (operands[1], <MODE>mode))
+        {
+	  rtx addr;
+
+	  addr = force_reg (Pmode, XEXP (operands[1], 0));
+	  operands[1] = replace_equiv_address (operands[1], addr);
+	}
+      operands[2] = force_reg (<MODE>mode, operands[2]);
+      emit_insn (gen_atomic_exchange<mode>_swap (operands[0], operands[1],
+						 operands[2]));
+    }
+  else
+    emit_insn (gen_atomic_exchange<mode>_llsc (operands[0], operands[1],
+					       operands[2], operands[3]));
+  DONE;
+})
+
+(define_insn "atomic_exchange<mode>_llsc"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZC,ZC")]
+	 UNSPEC_ATOMIC_EXCHANGE))
+   (set (match_dup 1)
+	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
+	 UNSPEC_ATOMIC_EXCHANGE))
+   (unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")]
+    UNSPEC_ATOMIC_EXCHANGE)]
+  "GENERATE_LL_SC && !ISA_HAS_SWAP"
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "li,move")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")
+   (set_attr "sync_memmodel" "3")])
+
+;; XLP issues implicit sync for SWAP/LDADD, so no need for an explicit one.
+(define_insn "atomic_exchange<mode>_swap"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+	(unspec_volatile:GPR [(match_operand:GPR 1 "mem_noofs_operand" "+ZR")]
+	 UNSPEC_ATOMIC_EXCHANGE))
+   (set (match_dup 1)
+	(unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "0")]
+	 UNSPEC_ATOMIC_EXCHANGE))]
+  "ISA_HAS_SWAP"
+  "swap<size>\t%0,%b1"
+  [(set_attr "type" "atomic")])
+
+(define_expand "atomic_fetch_add<mode>"
+  [(match_operand:GPR 0 "register_operand")
+   (match_operand:GPR 1 "memory_operand")
+   (match_operand:GPR 2 "arith_operand")
+   (match_operand:SI 3 "const_int_operand")]
+  "GENERATE_LL_SC || ISA_HAS_LDADD"
+{
+  if (ISA_HAS_LDADD)
+    {
+      if (!mem_noofs_operand (operands[1], <MODE>mode))
+        {
+	  rtx addr;
+
+	  addr = force_reg (Pmode, XEXP (operands[1], 0));
+	  operands[1] = replace_equiv_address (operands[1], addr);
+	}
+      operands[2] = force_reg (<MODE>mode, operands[2]);
+      emit_insn (gen_atomic_fetch_add<mode>_ldadd (operands[0], operands[1],
+						   operands[2]));
+    }
+  else
+    emit_insn (gen_atomic_fetch_add<mode>_llsc (operands[0], operands[1],
+						operands[2], operands[3]));
+  DONE;
+})
+
+(define_insn "atomic_fetch_add<mode>_llsc"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZC,ZC")]
+	 UNSPEC_ATOMIC_FETCH_OP))
+   (set (match_dup 1)
+	(unspec_volatile:GPR
+	 [(plus:GPR (match_dup 1)
+		    (match_operand:GPR 2 "arith_operand" "I,d"))]
+	 UNSPEC_ATOMIC_FETCH_OP))
+   (unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")]
+    UNSPEC_ATOMIC_FETCH_OP)]
+  "GENERATE_LL_SC && !ISA_HAS_LDADD"
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "addiu,addu")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")
+   (set_attr "sync_memmodel" "3")])
+
+;; XLP issues implicit sync for SWAP/LDADD, so no need for an explicit one.
+(define_insn "atomic_fetch_add<mode>_ldadd"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+	(unspec_volatile:GPR [(match_operand:GPR 1 "mem_noofs_operand" "+ZR")]
+	 UNSPEC_ATOMIC_FETCH_OP))
+   (set (match_dup 1)
+	(unspec_volatile:GPR
+	 [(plus:GPR (match_dup 1)
+		    (match_operand:GPR 2 "register_operand" "0"))]
+	 UNSPEC_ATOMIC_FETCH_OP))]
+  "ISA_HAS_LDADD"
+  "ldadd<size>\t%0,%b1"
+  [(set_attr "type" "atomic")])