Adapt other atomic operations to ARMv8-M Baseline
authorThomas Preud'homme <thomas.preudhomme@arm.com>
Thu, 27 Oct 2016 10:19:13 +0000 (10:19 +0000)
committerThomas Preud'homme <thopre01@gcc.gnu.org>
Thu, 27 Oct 2016 10:19:13 +0000 (10:19 +0000)
2016-10-27  Thomas Preud'homme  <thomas.preudhomme@arm.com>

    gcc/
    * config/arm/arm.c (arm_split_atomic_op): Add function comment.  Add
    logic to to decide whether to copy over old value to register for new
    value.
    * config/arm/sync.md: Add comments explaning why mode and code
    attribute are not defined in iterators.md
    (thumb1_atomic_op_str): New code attribute.
    (thumb1_atomic_newop_str): Likewise.
    (thumb1_atomic_fetch_op_str): Likewise.
    (thumb1_atomic_fetch_newop_str): Likewise.
    (thumb1_atomic_fetch_oldop_str): Likewise.
    (atomic_exchange<mode>): Add new ARMv8-M Baseline only alternatives to
    mirror the more restrictive constraints of the Thumb-1 insns after
    split compared to Thumb-2 counterpart insns.
    (atomic_<sync_optab><mode>): Likewise.  Add comment to keep constraints
    in sync with non atomic version.
    (atomic_nand<mode>): Likewise.
    (atomic_fetch_<sync_optab><mode>): Likewise.
    (atomic_fetch_nand<mode>): Likewise.
    (atomic_<sync_optab>_fetch<mode>): Likewise.
    (atomic_nand_fetch<mode>): Likewise.
    * config/arm/thumb1.md (thumb1_addsi3): Add comment to keep contraint
    in sync with atomic version.
    (thumb1_subsi3_insn): Likewise.
    (thumb1_andsi3_insn): Likewise.
    (thumb1_iorsi3_insn): Likewise.
    (thumb1_xorsi3_insn): Likewise.

From-SVN: r241614

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/sync.md
gcc/config/arm/thumb1.md

index ca1502a..d1d53de 100644 (file)
@@ -1,3 +1,32 @@
+2016-10-27  Thomas Preud'homme  <thomas.preudhomme@arm.com>
+
+       * config/arm/arm.c (arm_split_atomic_op): Add function comment.  Add
+       logic to to decide whether to copy over old value to register for new
+       value.
+       * config/arm/sync.md: Add comments explaning why mode and code
+       attribute are not defined in iterators.md
+       (thumb1_atomic_op_str): New code attribute.
+       (thumb1_atomic_newop_str): Likewise.
+       (thumb1_atomic_fetch_op_str): Likewise.
+       (thumb1_atomic_fetch_newop_str): Likewise.
+       (thumb1_atomic_fetch_oldop_str): Likewise.
+       (atomic_exchange<mode>): Add new ARMv8-M Baseline only alternatives to
+       mirror the more restrictive constraints of the Thumb-1 insns after
+       split compared to Thumb-2 counterpart insns.
+       (atomic_<sync_optab><mode>): Likewise.  Add comment to keep constraints
+       in sync with non atomic version.
+       (atomic_nand<mode>): Likewise.
+       (atomic_fetch_<sync_optab><mode>): Likewise.
+       (atomic_fetch_nand<mode>): Likewise.
+       (atomic_<sync_optab>_fetch<mode>): Likewise.
+       (atomic_nand_fetch<mode>): Likewise.
+       * config/arm/thumb1.md (thumb1_addsi3): Add comment to keep contraint
+       in sync with atomic version.
+       (thumb1_subsi3_insn): Likewise.
+       (thumb1_andsi3_insn): Likewise.
+       (thumb1_iorsi3_insn): Likewise.
+       (thumb1_xorsi3_insn): Likewise.
+
 2016-10-27  Nick Clifton  <nickc@redhat.com>
 
        * plugin.c (register_plugin_info): Produce an error message if the
index 781353e..3c4c704 100644 (file)
@@ -28342,6 +28342,15 @@ arm_split_compare_and_swap (rtx operands[])
     emit_label (label2);
 }
 
+/* Split an atomic operation pattern.  Operation is given by CODE and is one
+   of PLUS, MINUS, IOR, XOR, SET (for an exchange operation) or NOT (for a nand
+   operation).  Operation is performed on the content at MEM and on VALUE
+   following the memory model MODEL_RTX.  The content at MEM before and after
+   the operation is returned in OLD_OUT and NEW_OUT respectively while the
+   success of the operation is returned in COND.  Using a scratch register or
+   an operand register for these determines what result is returned for that
+   pattern.  */
+
 void
 arm_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
                     rtx value, rtx model_rtx, rtx cond)
@@ -28350,6 +28359,7 @@ arm_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
   machine_mode mode = GET_MODE (mem);
   machine_mode wmode = (mode == DImode ? DImode : SImode);
   rtx_code_label *label;
+  bool all_low_regs, bind_old_new;
   rtx x;
 
   bool is_armv8_sync = arm_arch8 && is_mm_sync (model);
@@ -28384,6 +28394,28 @@ arm_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
 
   arm_emit_load_exclusive (mode, old_out, mem, use_acquire);
 
+  /* Does the operation require destination and first operand to use the same
+     register?  This is decided by register constraints of relevant insn
+     patterns in thumb1.md.  */
+  gcc_assert (!new_out || REG_P (new_out));
+  all_low_regs = REG_P (value) && REGNO_REG_CLASS (REGNO (value)) == LO_REGS
+                && new_out && REGNO_REG_CLASS (REGNO (new_out)) == LO_REGS
+                && REGNO_REG_CLASS (REGNO (old_out)) == LO_REGS;
+  bind_old_new =
+    (TARGET_THUMB1
+     && code != SET
+     && code != MINUS
+     && (code != PLUS || (!all_low_regs && !satisfies_constraint_L (value))));
+
+  /* We want to return the old value while putting the result of the operation
+     in the same register as the old value so copy the old value over to the
+     destination register and use that register for the operation.  */
+  if (old_out && bind_old_new)
+    {
+      emit_move_insn (new_out, old_out);
+      old_out = new_out;
+    }
+
   switch (code)
     {
     case SET:
index 583b0af..e7be492 100644 (file)
   [(set_attr "arch" "32,v8mb,v8mb,v8mb")])
 
 (define_insn_and_split "atomic_exchange<mode>"
-  [(set (match_operand:QHSD 0 "s_register_operand" "=&r")      ;; output
-       (match_operand:QHSD 1 "mem_noofs_operand" "+Ua"))       ;; memory
+  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,&r")   ;; output
+       (match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua"))    ;; memory
    (set (match_dup 1)
        (unspec_volatile:QHSD
-         [(match_operand:QHSD 2 "s_register_operand" "r")      ;; input
+         [(match_operand:QHSD 2 "s_register_operand" "r,r")    ;; input
           (match_operand:SI 3 "const_int_operand" "")]         ;; model
          VUNSPEC_ATOMIC_XCHG))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:SI 4 "=&r"))]
+   (clobber (match_scratch:SI 4 "=&r,&l"))]
   "<sync_predtab>"
   "#"
   "&& reload_completed"
     arm_split_atomic_op (SET, operands[0], NULL, operands[1],
                         operands[2], operands[3], operands[4]);
     DONE;
-  })
+  }
+  [(set_attr "arch" "32,v8mb")])
+
+;; The following mode and code attribute are defined here because they are
+;; specific to atomics and are not needed anywhere else.
 
 (define_mode_attr atomic_op_operand
   [(QI "reg_or_int_operand")
 (define_mode_attr atomic_op_str
   [(QI "rn") (HI "rn") (SI "rn") (DI "r")])
 
+(define_code_attr thumb1_atomic_op_str
+  [(ior "l,l") (xor "l,l") (and "l,l") (plus "lIJL,r") (minus "lPd,lPd")])
+
+(define_code_attr thumb1_atomic_newop_str
+  [(ior "&l,&l") (xor "&l,&l") (and "&l,&l") (plus "&l,&r") (minus "&l,&l")])
+
+;; Constraints of this pattern must be at least as strict as those of the non
+;; atomic operations in thumb1.md and aim to be as permissive.
 (define_insn_and_split "atomic_<sync_optab><mode>"
-  [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua")
+  [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua,Ua,Ua")
        (unspec_volatile:QHSD
          [(syncop:QHSD (match_dup 0)
-            (match_operand:QHSD 1 "<atomic_op_operand>" "<atomic_op_str>"))
+            (match_operand:QHSD 1 "<atomic_op_operand>" "<atomic_op_str>,<thumb1_atomic_op_str>"))
           (match_operand:SI 2 "const_int_operand")]            ;; model
          VUNSPEC_ATOMIC_OP))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:QHSD 3 "=&r"))
-   (clobber (match_scratch:SI 4 "=&r"))]
+   (clobber (match_scratch:QHSD 3 "=&r,<thumb1_atomic_newop_str>"))
+   (clobber (match_scratch:SI 4 "=&r,&l,&l"))]
   "<sync_predtab>"
   "#"
   "&& reload_completed"
     arm_split_atomic_op (<CODE>, NULL, operands[3], operands[0],
                         operands[1], operands[2], operands[4]);
     DONE;
-  })
+  }
+  [(set_attr "arch" "32,v8mb,v8mb")])
 
+;; Constraints of this pattern must be at least as strict as those of the non
+;; atomic NANDs in thumb1.md and aim to be as permissive.
 (define_insn_and_split "atomic_nand<mode>"
-  [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua")
+  [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua,Ua")
        (unspec_volatile:QHSD
          [(not:QHSD
             (and:QHSD (match_dup 0)
-              (match_operand:QHSD 1 "<atomic_op_operand>" "<atomic_op_str>")))
+              (match_operand:QHSD 1 "<atomic_op_operand>" "<atomic_op_str>,l")))
           (match_operand:SI 2 "const_int_operand")]            ;; model
          VUNSPEC_ATOMIC_OP))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:QHSD 3 "=&r"))
-   (clobber (match_scratch:SI 4 "=&r"))]
+   (clobber (match_scratch:QHSD 3 "=&r,&l"))
+   (clobber (match_scratch:SI 4 "=&r,&l"))]
   "<sync_predtab>"
   "#"
   "&& reload_completed"
     arm_split_atomic_op (NOT, NULL, operands[3], operands[0],
                         operands[1], operands[2], operands[4]);
     DONE;
-  })
+  }
+  [(set_attr "arch" "32,v8mb")])
+
+;; 3 alternatives are needed to represent constraints after split from
+;; thumb1_addsi3: (i) case where operand1 and destination can be in different
+;; registers, (ii) case where they are in the same low register and (iii) case
+;; when they are in the same register without restriction on the register.  We
+;; disparage slightly alternatives that require copying the old value into the
+;; register for the new value (see bind_old_new in arm_split_atomic_op).
+(define_code_attr thumb1_atomic_fetch_op_str
+  [(ior "l,l,l") (xor "l,l,l") (and "l,l,l") (plus "lL,?IJ,?r") (minus "lPd,lPd,lPd")])
 
+(define_code_attr thumb1_atomic_fetch_newop_str
+  [(ior "&l,&l,&l") (xor "&l,&l,&l") (and "&l,&l,&l") (plus "&l,&l,&r") (minus "&l,&l,&l")])
+
+(define_code_attr thumb1_atomic_fetch_oldop_str
+  [(ior "&r,&r,&r") (xor "&r,&r,&r") (and "&r,&r,&r") (plus "&l,&r,&r") (minus "&l,&l,&l")])
+
+;; Constraints of this pattern must be at least as strict as those of the non
+;; atomic operations in thumb1.md and aim to be as permissive.
 (define_insn_and_split "atomic_fetch_<sync_optab><mode>"
-  [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
-       (match_operand:QHSD 1 "mem_noofs_operand" "+Ua"))
+  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,<thumb1_atomic_fetch_oldop_str>")
+       (match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua,Ua,Ua"))
    (set (match_dup 1)
        (unspec_volatile:QHSD
          [(syncop:QHSD (match_dup 1)
-            (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>"))
+            (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,<thumb1_atomic_fetch_op_str>"))
           (match_operand:SI 3 "const_int_operand")]            ;; model
          VUNSPEC_ATOMIC_OP))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:QHSD 4 "=&r"))
-   (clobber (match_scratch:SI 5 "=&r"))]
+   (clobber (match_scratch:QHSD 4 "=&r,<thumb1_atomic_fetch_newop_str>"))
+   (clobber (match_scratch:SI 5 "=&r,&l,&l,&l"))]
   "<sync_predtab>"
   "#"
   "&& reload_completed"
     arm_split_atomic_op (<CODE>, operands[0], operands[4], operands[1],
                         operands[2], operands[3], operands[5]);
     DONE;
-  })
+  }
+  [(set_attr "arch" "32,v8mb,v8mb,v8mb")])
 
+;; Constraints of this pattern must be at least as strict as those of the non
+;; atomic NANDs in thumb1.md and aim to be as permissive.
 (define_insn_and_split "atomic_fetch_nand<mode>"
-  [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
-       (match_operand:QHSD 1 "mem_noofs_operand" "+Ua"))
+  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,&r")
+       (match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua"))
    (set (match_dup 1)
        (unspec_volatile:QHSD
          [(not:QHSD
             (and:QHSD (match_dup 1)
-              (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>")))
+              (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,l")))
           (match_operand:SI 3 "const_int_operand")]            ;; model
          VUNSPEC_ATOMIC_OP))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:QHSD 4 "=&r"))
-   (clobber (match_scratch:SI 5 "=&r"))]
+   (clobber (match_scratch:QHSD 4 "=&r,&l"))
+   (clobber (match_scratch:SI 5 "=&r,&l"))]
   "<sync_predtab>"
   "#"
   "&& reload_completed"
     arm_split_atomic_op (NOT, operands[0], operands[4], operands[1],
                         operands[2], operands[3], operands[5]);
     DONE;
-  })
+  }
+  [(set_attr "arch" "32,v8mb")])
 
+;; Constraints of this pattern must be at least as strict as those of the non
+;; atomic operations in thumb1.md and aim to be as permissive.
 (define_insn_and_split "atomic_<sync_optab>_fetch<mode>"
-  [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
+  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,<thumb1_atomic_newop_str>")
        (syncop:QHSD
-         (match_operand:QHSD 1 "mem_noofs_operand" "+Ua")
-         (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>")))
+         (match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua,Ua")
+         (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,<thumb1_atomic_op_str>")))
    (set (match_dup 1)
        (unspec_volatile:QHSD
          [(match_dup 1) (match_dup 2)
           (match_operand:SI 3 "const_int_operand")]            ;; model
          VUNSPEC_ATOMIC_OP))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:SI 4 "=&r"))]
+   (clobber (match_scratch:SI 4 "=&r,&l,&l"))]
   "<sync_predtab>"
   "#"
   "&& reload_completed"
     arm_split_atomic_op (<CODE>, NULL, operands[0], operands[1],
                         operands[2], operands[3], operands[4]);
     DONE;
-  })
+  }
+  [(set_attr "arch" "32,v8mb,v8mb")])
 
+;; Constraints of this pattern must be at least as strict as those of the non
+;; atomic NANDs in thumb1.md and aim to be as permissive.
 (define_insn_and_split "atomic_nand_fetch<mode>"
-  [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
+  [(set (match_operand:QHSD 0 "s_register_operand" "=&r,&l")
        (not:QHSD
          (and:QHSD
-           (match_operand:QHSD 1 "mem_noofs_operand" "+Ua")
-           (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>"))))
+           (match_operand:QHSD 1 "mem_noofs_operand" "+Ua,Ua")
+           (match_operand:QHSD 2 "<atomic_op_operand>" "<atomic_op_str>,l"))))
    (set (match_dup 1)
        (unspec_volatile:QHSD
          [(match_dup 1) (match_dup 2)
           (match_operand:SI 3 "const_int_operand")]            ;; model
          VUNSPEC_ATOMIC_OP))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:SI 4 "=&r"))]
+   (clobber (match_scratch:SI 4 "=&r,&l"))]
   "<sync_predtab>"
   "#"
   "&& reload_completed"
     arm_split_atomic_op (NOT, NULL, operands[0], operands[1],
                         operands[2], operands[3], operands[4]);
     DONE;
-  })
+  }
+  [(set_attr "arch" "32,v8mb")])
 
 (define_insn "arm_load_exclusive<mode>"
   [(set (match_operand:SI 0 "s_register_operand" "=r,r")
index 67f2878..5f0dffb 100644 (file)
    (set_attr "type" "multiple")]
 )
 
+;; Changes to the constraints of this pattern must be propagated to those of
+;; atomic additions in sync.md and to the logic for bind_old_new in
+;; arm_split_atomic_op in arm.c.  These must be at least as strict as the
+;; constraints here and aim to be as permissive.
 (define_insn_and_split "*thumb1_addsi3"
   [(set (match_operand:SI          0 "register_operand" "=l,l,l,*rk,*hk,l,k,l,l,l")
        (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,k,k,0,l,k")
    (set_attr "type" "multiple")]
 )
 
+;; Changes to the constraints of this pattern must be propagated to those of
+;; atomic subtractions in sync.md and to the logic for bind_old_new in
+;; arm_split_atomic_op in arm.c.  These must be at least as strict as the
+;; constraints here and aim to be as permissive.
 (define_insn "thumb1_subsi3_insn"
   [(set (match_operand:SI           0 "register_operand" "=l")
        (minus:SI (match_operand:SI 1 "register_operand" "l")
    (set_attr "type" "muls")]
 )
 
+;; Changes to the constraints of this pattern must be propagated to those of
+;; atomic bitwise ANDs and NANDs in sync.md and to the logic for bind_old_new
+;; in arm_split_atomic_op in arm.c.  These must be at least as strict as the
+;; constraints here and aim to be as permissive.
 (define_insn "*thumb1_andsi3_insn"
   [(set (match_operand:SI         0 "register_operand" "=l")
        (and:SI (match_operand:SI 1 "register_operand" "%0")
    (set_attr "type" "logics_reg")]
 )
 
+;; Changes to the constraints of this pattern must be propagated to those of
+;; atomic inclusive ORs in sync.md and to the logic for bind_old_new in
+;; arm_split_atomic_op in arm.c.  These must be at least as strict as the
+;; constraints here and aim to be as permissive.
 (define_insn "*thumb1_iorsi3_insn"
   [(set (match_operand:SI         0 "register_operand" "=l")
        (ior:SI (match_operand:SI 1 "register_operand" "%0")
    (set_attr "conds" "set")
    (set_attr "type" "logics_reg")])
 
+;; Changes to the constraints of this pattern must be propagated to those of
+;; atomic exclusive ORs in sync.md and to the logic for bind_old_new in
+;; arm_split_atomic_op in arm.c.  These must be at least as strict as the
+;; constraints here and aim to be as permissive.
 (define_insn "*thumb1_xorsi3_insn"
   [(set (match_operand:SI         0 "register_operand" "=l")
        (xor:SI (match_operand:SI 1 "register_operand" "%0")