OSDN Git Service

* config/frv/frv.opt (moptimize-membar): New.
authoraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 28 Jul 2005 02:03:45 +0000 (02:03 +0000)
committeraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 28 Jul 2005 02:03:45 +0000 (02:03 +0000)
* doc/invoke.texi: Document -moptimize-membar and its inverse.

* config/frv/frv.h: Remove machine_function definition.

        * config/frv/frv.c (struct frv_io): New.
        (struct machine_function): Moved from frv.h.  Add has_membar_p.
        (frv_same_doubleword_p, frv_io_fixed_order_p, frv_io_union)
        (frv_extract_membar, frv_io_check_address, frv_io_handle_set)
        (frv_io_handle_use_1, frv_io_handle_use, frv_optimize_membar_local)
        (frv_optimize_membar_global, frv_optimize_membar): New functions.
        (frv_reorg): Call frv_optimize_membar when appropriate.
        (bdesc_loads, bdesc_stores): Use the membar code as the icode field.
        (frv_expand_builtin): Adjust calls accordingly.
        (frv_io_address_cookie): New function.
        (frv_expand_load_builtin, frv_expand_store_builtin): Emit a normal
        load or store rather than a special insn.  Add ccnstant address and
        io-type operands to the membar.
(frv_ifcvt_modify_tests): Unsign regno.
(frv_ifcvt_modify_tests): Same.

* config/frv/frv.md: Remove UNSPEC_BUILTIN_{LOAD,STORE}.  Change
UNSPEC_OPTIONAL_MEMBAR constant.
(builtin_read_<mode>): Delete.
(builtin_write_<mode>): Delete.
("optional_membar_<mode>"): Add operand.

* testsuite/gcc.target/frv/all-builtin-read8.c: Delete.
* testsuite/gcc.target/frv/all-builtin-read16.c: Delete.
* testsuite/gcc.target/frv/all-builtin-read32.c: Delete.
* testsuite/gcc.target/frv/all-builtin-read64.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write8.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write16.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write32.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write64.c: Delete.
* testsuite/gcc.target/frv/all-read-write-1.c: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@102455 138bc75d-0d04-0410-961f-82ee72b054a4

15 files changed:
gcc/ChangeLog
gcc/config/frv/frv.c
gcc/config/frv/frv.h
gcc/config/frv/frv.md
gcc/config/frv/frv.opt
gcc/doc/invoke.texi
gcc/testsuite/gcc.target/frv/all-builtin-read16.c [deleted file]
gcc/testsuite/gcc.target/frv/all-builtin-read32.c [deleted file]
gcc/testsuite/gcc.target/frv/all-builtin-read64.c [deleted file]
gcc/testsuite/gcc.target/frv/all-builtin-read8.c [deleted file]
gcc/testsuite/gcc.target/frv/all-builtin-write16.c [deleted file]
gcc/testsuite/gcc.target/frv/all-builtin-write32.c [deleted file]
gcc/testsuite/gcc.target/frv/all-builtin-write64.c [deleted file]
gcc/testsuite/gcc.target/frv/all-builtin-write8.c [deleted file]
gcc/testsuite/gcc.target/frv/all-read-write-1.c [new file with mode: 0644]

index 6b273f2..299d206 100644 (file)
@@ -1,3 +1,43 @@
+2005-07-27  Aldy Hernandez  <aldyh@redhat.com>
+
+       * config/frv/frv.opt (moptimize-membar): New.
+
+       * doc/invoke.texi: Document -moptimize-membar and its inverse.
+
+       * config/frv/frv.h: Remove machine_function definition.
+
+        * config/frv/frv.c (struct frv_io): New.
+        (struct machine_function): Moved from frv.h.  Add has_membar_p.
+        (frv_same_doubleword_p, frv_io_fixed_order_p, frv_io_union)
+        (frv_extract_membar, frv_io_check_address, frv_io_handle_set)
+        (frv_io_handle_use_1, frv_io_handle_use, frv_optimize_membar_local)
+        (frv_optimize_membar_global, frv_optimize_membar): New functions.
+        (frv_reorg): Call frv_optimize_membar when appropriate.
+        (bdesc_loads, bdesc_stores): Use the membar code as the icode field.
+        (frv_expand_builtin): Adjust calls accordingly.
+        (frv_io_address_cookie): New function.
+        (frv_expand_load_builtin, frv_expand_store_builtin): Emit a normal
+        load or store rather than a special insn.  Add ccnstant address and
+        io-type operands to the membar.
+       (frv_ifcvt_modify_tests): Unsign regno.
+       (frv_ifcvt_modify_tests): Same.
+
+       * config/frv/frv.md: Remove UNSPEC_BUILTIN_{LOAD,STORE}.  Change
+       UNSPEC_OPTIONAL_MEMBAR constant.
+       (builtin_read_<mode>): Delete.
+       (builtin_write_<mode>): Delete.
+       ("optional_membar_<mode>"): Add operand.
+
+       * testsuite/gcc.target/frv/all-builtin-read8.c: Delete.
+       * testsuite/gcc.target/frv/all-builtin-read16.c: Delete.
+       * testsuite/gcc.target/frv/all-builtin-read32.c: Delete.
+       * testsuite/gcc.target/frv/all-builtin-read64.c: Delete.
+       * testsuite/gcc.target/frv/all-builtin-write8.c: Delete.
+       * testsuite/gcc.target/frv/all-builtin-write16.c: Delete.
+       * testsuite/gcc.target/frv/all-builtin-write32.c: Delete.
+       * testsuite/gcc.target/frv/all-builtin-write64.c: Delete.
+       * testsuite/gcc.target/frv/all-read-write-1.c: New.
+
 2005-07-28  Kaz Kojima  <kkojima@gcc.gnu.org>
 
        * df.c (df_uses_record): Handle SCRATCH.
index 756ae63..9213f9b 100644 (file)
@@ -109,6 +109,21 @@ static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS];
 /* The number of nop instructions in frv_nops[].  */
 static unsigned int frv_num_nops;
 
+/* Information about one __builtin_read or __builtin_write access, or
+   the combination of several such accesses.  The most general value
+   is all-zeros (an unknown access to an unknown address).  */
+struct frv_io {
+  /* The type of access.  FRV_IO_UNKNOWN means the access can be either
+     a read or a write.  */
+  enum { FRV_IO_UNKNOWN, FRV_IO_READ, FRV_IO_WRITE } type;
+
+  /* The constant address being accessed, or zero if not known.  */
+  HOST_WIDE_INT const_address;
+
+  /* The run-time address, as used in operand 0 of the membar pattern.  */
+  rtx var_address;
+};
+
 /* Return true if instruction INSN should be packed with the following
    instruction.  */
 #define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode)
@@ -123,6 +138,16 @@ static unsigned int frv_num_nops;
        REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X));   \
        REG++)
 
+/* This structure contains machine specific function data.  */
+struct machine_function GTY(())
+{
+  /* True if we have created an rtx that relies on the stack frame.  */
+  int frame_needed;
+
+  /* True if this function contains at least one __builtin_{read,write}*.  */
+  bool has_membar_p;
+};
+
 /* Temporary register allocation support structure.  */
 typedef struct frv_tmp_reg_struct
   {
@@ -756,6 +781,9 @@ frv_override_options (void)
   if ((target_flags_explicit & MASK_LINKED_FP) == 0)
     target_flags |= MASK_LINKED_FP;
 
+  if ((target_flags_explicit & MASK_OPTIMIZE_MEMBAR) == 0)
+    target_flags |= MASK_OPTIMIZE_MEMBAR;
+
   for (i = 0; i < ARRAY_SIZE (frv_unit_names); i++)
     frv_unit_codes[i] = get_cpu_unit_code (frv_unit_names[i]);
 
@@ -5291,7 +5319,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
 
   if (join_bb)
     {
-      int regno;
+      unsigned int regno;
 
       /* Remove anything live at the beginning of the join block from being
          available for allocation.  */
@@ -5328,7 +5356,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
     {
       rtx last_insn = BB_END (bb[j]);
       rtx insn = BB_HEAD (bb[j]);
-      int regno;
+      unsigned int regno;
 
       if (dump_file)
        fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n",
@@ -7661,6 +7689,334 @@ frv_fill_unused_units (enum frv_insn_group group)
     frv_insert_nop_in_packet (packet_group->nop);
 }
 
+/* Return true if accesses IO1 and IO2 refer to the same doubleword.  */
+
+static bool
+frv_same_doubleword_p (const struct frv_io *io1, const struct frv_io *io2)
+{
+  if (io1->const_address != 0 && io2->const_address != 0)
+    return io1->const_address == io2->const_address;
+
+  if (io1->var_address != 0 && io2->var_address != 0)
+    return rtx_equal_p (io1->var_address, io2->var_address);
+
+  return false;
+}
+
+/* Return true if operations IO1 and IO2 are guaranteed to complete
+   in order.  */
+
+static bool
+frv_io_fixed_order_p (const struct frv_io *io1, const struct frv_io *io2)
+{
+  /* The order of writes is always preserved.  */
+  if (io1->type == FRV_IO_WRITE && io2->type == FRV_IO_WRITE)
+    return true;
+
+  /* The order of reads isn't preserved.  */
+  if (io1->type != FRV_IO_WRITE && io2->type != FRV_IO_WRITE)
+    return false;
+
+  /* One operation is a write and the other is (or could be) a read.
+     The order is only guaranteed if the accesses are to the same
+     doubleword.  */
+  return frv_same_doubleword_p (io1, io2);
+}
+
+/* Generalize I/O operation X so that it covers both X and Y. */
+
+static void
+frv_io_union (struct frv_io *x, const struct frv_io *y)
+{
+  if (x->type != y->type)
+    x->type = FRV_IO_UNKNOWN;
+  if (!frv_same_doubleword_p (x, y))
+    {
+      x->const_address = 0;
+      x->var_address = 0;
+    }
+}
+
+/* Fill IO with information about the load or store associated with
+   membar instruction INSN.  */
+
+static void
+frv_extract_membar (struct frv_io *io, rtx insn)
+{
+  extract_insn (insn);
+  io->type = INTVAL (recog_data.operand[2]);
+  io->const_address = INTVAL (recog_data.operand[1]);
+  io->var_address = XEXP (recog_data.operand[0], 0);
+}
+
+/* A note_stores callback for which DATA points to an rtx.  Nullify *DATA
+   if X is a register and *DATA depends on X.  */
+
+static void
+frv_io_check_address (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  rtx *other = data;
+
+  if (REG_P (x) && *other != 0 && reg_overlap_mentioned_p (x, *other))
+    *other = 0;
+}
+
+/* A note_stores callback for which DATA points to a HARD_REG_SET.
+   Remove every modified register from the set.  */
+
+static void
+frv_io_handle_set (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  HARD_REG_SET *set = data;
+  unsigned int regno;
+
+  if (REG_P (x))
+    FOR_EACH_REGNO (regno, x)
+      CLEAR_HARD_REG_BIT (*set, regno);
+}
+
+/* A for_each_rtx callback for which DATA points to a HARD_REG_SET.
+   Add every register in *X to the set.  */
+
+static int
+frv_io_handle_use_1 (rtx *x, void *data)
+{
+  HARD_REG_SET *set = data;
+  unsigned int regno;
+
+  if (REG_P (*x))
+    FOR_EACH_REGNO (regno, *x)
+      SET_HARD_REG_BIT (*set, regno);
+
+  return 0;
+}
+
+/* A note_stores callback that applies frv_io_handle_use_1 to an
+   entire rhs value.  */
+
+static void
+frv_io_handle_use (rtx *x, void *data)
+{
+  for_each_rtx (x, frv_io_handle_use_1, data);
+}
+
+/* Go through block BB looking for membars to remove.  There are two
+   cases where intra-block analysis is enough:
+
+   - a membar is redundant if it occurs between two consecutive I/O
+   operations and if those operations are guaranteed to complete
+   in order.
+
+   - a membar for a __builtin_read is redundant if the result is
+   used before the next I/O operation is issued.
+
+   If the last membar in the block could not be removed, and there
+   are guaranteed to be no I/O operations between that membar and
+   the end of the block, store the membar in *LAST_MEMBAR, otherwise
+   store null.
+
+   Describe the block's first I/O operation in *NEXT_IO.  Describe
+   an unknown operation if the block doesn't do any I/O.  */
+
+static void
+frv_optimize_membar_local (basic_block bb, struct frv_io *next_io,
+                          rtx *last_membar)
+{
+  HARD_REG_SET used_regs;
+  rtx next_membar, set, insn;
+  bool next_is_end_p;
+
+  /* NEXT_IO is the next I/O operation to be performed after the current
+     instruction.  It starts off as being an unknown operation.  */
+  memset (next_io, 0, sizeof (*next_io));
+
+  /* NEXT_IS_END_P is true if NEXT_IO describes the end of the block.  */
+  next_is_end_p = true;
+
+  /* If the current instruction is a __builtin_read or __builtin_write,
+     NEXT_MEMBAR is the membar instruction associated with it.  NEXT_MEMBAR
+     is null if the membar has already been deleted.
+
+     Note that the initialization here should only be needed to
+     supress warnings.  */
+  next_membar = 0;
+
+  /* USED_REGS is the set of registers that are used before the
+     next I/O instruction.  */
+  CLEAR_HARD_REG_SET (used_regs);
+
+  for (insn = BB_END (bb); insn != BB_HEAD (bb); insn = PREV_INSN (insn))
+    if (GET_CODE (insn) == CALL_INSN)
+      {
+       /* We can't predict what a call will do to volatile memory.  */
+       memset (next_io, 0, sizeof (struct frv_io));
+       next_is_end_p = false;
+       CLEAR_HARD_REG_SET (used_regs);
+      }
+    else if (INSN_P (insn))
+      switch (recog_memoized (insn))
+       {
+       case CODE_FOR_optional_membar_qi:
+       case CODE_FOR_optional_membar_hi:
+       case CODE_FOR_optional_membar_si:
+       case CODE_FOR_optional_membar_di:
+         next_membar = insn;
+         if (next_is_end_p)
+           {
+             /* Local information isn't enough to decide whether this
+                membar is needed.  Stash it away for later.  */
+             *last_membar = insn;
+             frv_extract_membar (next_io, insn);
+             next_is_end_p = false;
+           }
+         else
+           {
+             /* Check whether the I/O operation before INSN could be
+                reordered with one described by NEXT_IO.  If it can't,
+                INSN will not be needed.  */
+             struct frv_io prev_io;
+
+             frv_extract_membar (&prev_io, insn);
+             if (frv_io_fixed_order_p (&prev_io, next_io))
+               {
+                 if (dump_file)
+                   fprintf (dump_file,
+                            ";; [Local] Removing membar %d since order"
+                            " of accesses is guaranteed\n",
+                            INSN_UID (next_membar));
+
+                 insn = NEXT_INSN (insn);
+                 delete_insn (next_membar);
+                 next_membar = 0;
+               }
+             *next_io = prev_io;
+           }
+         break;
+
+       default:
+         /* Invalidate NEXT_IO's address if it depends on something that
+            is clobbered by INSN.  */
+         if (next_io->var_address)
+           note_stores (PATTERN (insn), frv_io_check_address,
+                        &next_io->var_address);
+
+         /* If the next membar is associated with a __builtin_read,
+            see if INSN reads from that address.  If it does, and if
+            the destination register is used before the next I/O access,
+            there is no need for the membar.  */
+         set = PATTERN (insn);
+         if (next_io->type == FRV_IO_READ
+             && next_io->var_address != 0
+             && next_membar != 0
+             && GET_CODE (set) == SET
+             && GET_CODE (SET_DEST (set)) == REG
+             && TEST_HARD_REG_BIT (used_regs, REGNO (SET_DEST (set))))
+           {
+             rtx src;
+
+             src = SET_SRC (set);
+             if (GET_CODE (src) == ZERO_EXTEND)
+               src = XEXP (src, 0);
+
+             if (GET_CODE (src) == MEM
+                 && rtx_equal_p (XEXP (src, 0), next_io->var_address))
+               {
+                 if (dump_file)
+                   fprintf (dump_file,
+                            ";; [Local] Removing membar %d since the target"
+                            " of %d is used before the I/O operation\n",
+                            INSN_UID (next_membar), INSN_UID (insn));
+
+                 if (next_membar == *last_membar)
+                   *last_membar = 0;
+
+                 delete_insn (next_membar);
+                 next_membar = 0;
+               }
+           }
+
+         /* If INSN has volatile references, forget about any registers
+            that are used after it.  Otherwise forget about uses that
+            are (or might be) defined by INSN.  */
+         if (volatile_refs_p (PATTERN (insn)))
+           CLEAR_HARD_REG_SET (used_regs);
+         else
+           note_stores (PATTERN (insn), frv_io_handle_set, &used_regs);
+
+         note_uses (&PATTERN (insn), frv_io_handle_use, &used_regs);
+         break;
+       }
+}
+
+/* See if MEMBAR, the last membar instruction in BB, can be removed.
+   FIRST_IO[X] describes the first operation performed by basic block X.  */
+
+static void
+frv_optimize_membar_global (basic_block bb, struct frv_io *first_io,
+                           rtx membar)
+{
+  struct frv_io this_io, next_io;
+  edge succ;
+  edge_iterator ei;
+
+  /* We need to keep the membar if there is an edge to the exit block.  */
+  FOR_EACH_EDGE (succ, ei, bb->succs)
+  /* for (succ = bb->succ; succ != 0; succ = succ->succ_next) */
+    if (succ->dest == EXIT_BLOCK_PTR)
+      return;
+
+  /* Work out the union of all successor blocks.  */
+  ei = ei_start (bb->succs);
+  ei_cond (ei, &succ);
+  /* next_io = first_io[bb->succ->dest->index]; */
+  next_io = first_io[succ->dest->index];
+  ei = ei_start (bb->succs);
+  if (ei_cond (ei, &succ))
+    {
+      for (ei_next (&ei); ei_cond (ei, &succ); ei_next (&ei))
+       /*for (succ = bb->succ->succ_next; succ != 0; succ = succ->succ_next)*/
+       frv_io_union (&next_io, &first_io[succ->dest->index]);
+    }
+  else
+    gcc_unreachable ();
+
+  frv_extract_membar (&this_io, membar);
+  if (frv_io_fixed_order_p (&this_io, &next_io))
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                ";; [Global] Removing membar %d since order of accesses"
+                " is guaranteed\n", INSN_UID (membar));
+
+      delete_insn (membar);
+    }
+}
+
+/* Remove redundant membars from the current function.  */
+
+static void
+frv_optimize_membar (void)
+{
+  basic_block bb;
+  struct frv_io *first_io;
+  rtx *last_membar;
+
+  compute_bb_for_insn ();
+  first_io = xcalloc (last_basic_block, sizeof (struct frv_io));
+  last_membar = xcalloc (last_basic_block, sizeof (rtx));
+
+  FOR_EACH_BB (bb)
+    frv_optimize_membar_local (bb, &first_io[bb->index],
+                              &last_membar[bb->index]);
+
+  FOR_EACH_BB (bb)
+    if (last_membar[bb->index] != 0)
+      frv_optimize_membar_global (bb, first_io, last_membar[bb->index]);
+
+  free (first_io);
+  free (last_membar);
+}
+\f
 /* Used by frv_reorg to keep track of the current packet's address.  */
 static unsigned int frv_packet_address;
 
@@ -7773,6 +8129,9 @@ frv_register_nop (rtx nop)
 static void
 frv_reorg (void)
 {
+  if (optimize > 0 && TARGET_OPTIMIZE_MEMBAR && cfun->machine->has_membar_p)
+    frv_optimize_membar ();
+
   frv_num_nops = 0;
   frv_register_nop (gen_nop ());
   if (TARGET_MEDIA)
@@ -7953,33 +8312,33 @@ static struct builtin_description bdesc_voidacc[] =
   { CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 }
 };
 
-/* Intrinsics that load a value and then issue a MEMBAR.
-   The FLAGS field is the icode for the membar.  */
+/* Intrinsics that load a value and then issue a MEMBAR.  The load is
+   a normal move and the ICODE is for the membar.  */
 
 static struct builtin_description bdesc_loads[] =
 {
-  { CODE_FOR_builtin_read_qi, "__builtin_read8", FRV_BUILTIN_READ8, 0,
-    CODE_FOR_optional_membar_qi },
-  { CODE_FOR_builtin_read_hi, "__builtin_read16", FRV_BUILTIN_READ16, 0,
-    CODE_FOR_optional_membar_hi },
-  { CODE_FOR_builtin_read_si, "__builtin_read32", FRV_BUILTIN_READ32, 0,
-    CODE_FOR_optional_membar_si },
-  { CODE_FOR_builtin_read_di, "__builtin_read64", FRV_BUILTIN_READ64, 0,
-    CODE_FOR_optional_membar_di }
+  { CODE_FOR_optional_membar_qi, "__builtin_read8",
+    FRV_BUILTIN_READ8, 0, 0 },
+  { CODE_FOR_optional_membar_hi, "__builtin_read16",
+    FRV_BUILTIN_READ16, 0, 0 },
+  { CODE_FOR_optional_membar_si, "__builtin_read32",
+    FRV_BUILTIN_READ32, 0, 0 },
+  { CODE_FOR_optional_membar_di, "__builtin_read64",
+    FRV_BUILTIN_READ64, 0, 0 }
 };
 
 /* Likewise stores.  */
 
 static struct builtin_description bdesc_stores[] =
 {
-  { CODE_FOR_builtin_write_qi, "__builtin_write8", FRV_BUILTIN_WRITE8, 0,
-    CODE_FOR_optional_membar_qi },
-  { CODE_FOR_builtin_write_hi, "__builtin_write16", FRV_BUILTIN_WRITE16, 0,
-    CODE_FOR_optional_membar_hi },
-  { CODE_FOR_builtin_write_si, "__builtin_write32", FRV_BUILTIN_WRITE32, 0,
-    CODE_FOR_optional_membar_si },
-  { CODE_FOR_builtin_write64, "__builtin_write64", FRV_BUILTIN_WRITE64, 0,
-    CODE_FOR_optional_membar_di }
+  { CODE_FOR_optional_membar_qi, "__builtin_write8",
+    FRV_BUILTIN_WRITE8, 0, 0 },
+  { CODE_FOR_optional_membar_hi, "__builtin_write16",
+    FRV_BUILTIN_WRITE16, 0, 0 },
+  { CODE_FOR_optional_membar_si, "__builtin_write32",
+    FRV_BUILTIN_WRITE32, 0, 0 },
+  { CODE_FOR_optional_membar_di, "__builtin_write64",
+    FRV_BUILTIN_WRITE64, 0, 0 },
 };
 
 /* Initialize media builtins.  */
@@ -8305,6 +8664,18 @@ frv_matching_accg_mode (enum machine_mode mode)
     }
 }
 
+/* Given that a __builtin_read or __builtin_write function is accessing
+   address ADDRESS, return the value that should be used as operand 1
+   of the membar.  */
+
+static rtx
+frv_io_address_cookie (rtx address)
+{
+  return (GET_CODE (address) == CONST_INT
+         ? GEN_INT (INTVAL (address) / 8 * 8)
+         : const0_rtx);
+}
+
 /* Return the accumulator guard that should be paired with accumulator
    register ACC.  The mode of the returned register is in the same
    class as ACC, but is four times smaller.  */
@@ -8670,36 +9041,38 @@ frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist)
   return NULL_RTX;
 }
 
-/* Expand a __builtin_read* function.  ICODE is the instruction code for
-   the load and MEMBAR_ICODE is the instruction code of the "membar".  */
+/* Expand a __builtin_read* function.  ICODE is the instruction code for the
+   membar and TARGET_MODE is the mode that the loaded value should have.  */
 
 static rtx
-frv_expand_load_builtin (enum insn_code icode, enum insn_code membar_icode,
-                        tree arglist, rtx target)
+frv_expand_load_builtin (enum insn_code icode, enum machine_mode target_mode,
+                         tree arglist, rtx target)
 {
-  rtx op0 = frv_read_argument (& arglist);
-
-  target = frv_legitimize_target (icode, target);
-  op0 = frv_volatile_memref (insn_data[membar_icode].operand[0].mode, op0);
-  emit_insn (GEN_FCN (icode) (target, op0));
-  emit_insn (GEN_FCN (membar_icode) (copy_rtx (op0)));
+  rtx op0 = frv_read_argument (&arglist);
+  rtx cookie = frv_io_address_cookie (op0);
+
+  if (target == 0 || !REG_P (target))
+    target = gen_reg_rtx (target_mode);
+  op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
+  convert_move (target, op0, 1);
+  emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_READ)));
+  cfun->machine->has_membar_p = 1;
   return target;
 }
 
-/* Likewise __builtin_write* functions, with ICODE being the instruction
-   code of the store.  */
+/* Likewise __builtin_write* functions.  */
 
 static rtx
-frv_expand_store_builtin (enum insn_code icode, enum insn_code membar_icode,
-                         tree arglist)
+frv_expand_store_builtin (enum insn_code icode, tree arglist)
 {
-  rtx op0 = frv_read_argument (& arglist);
-  rtx op1 = frv_read_argument (& arglist);
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+  rtx cookie = frv_io_address_cookie (op0);
 
-  op0 = frv_volatile_memref (insn_data[membar_icode].operand[0].mode, op0);
-  op1 = frv_legitimize_argument (icode, 1, op1);
-  emit_insn (GEN_FCN (icode) (op0, op1));
-  emit_insn (GEN_FCN (membar_icode) (copy_rtx (op0)));
+  op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
+  convert_move (op0, force_reg (insn_data[icode].operand[0].mode, op1), 1);
+  emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_WRITE)));
+  cfun->machine->has_membar_p = 1;
   return NULL_RTX;
 }
 
@@ -9049,11 +9422,12 @@ frv_expand_builtin (tree exp,
 
   for (i = 0, d = bdesc_loads; i < ARRAY_SIZE (bdesc_loads); i++, d++)
     if (d->code == fcode)
-      return frv_expand_load_builtin (d->icode, d->flag, arglist, target);
+      return frv_expand_load_builtin (d->icode, TYPE_MODE (TREE_TYPE (exp)),
+                                     arglist, target);
 
   for (i = 0, d = bdesc_stores; i < ARRAY_SIZE (bdesc_stores); i++, d++)
     if (d->code == fcode)
-      return frv_expand_store_builtin (d->icode, d->flag, arglist);
+      return frv_expand_store_builtin (d->icode, arglist);
 
   return 0;
 }
index 41c11c4..73ecb2a 100644 (file)
@@ -1492,13 +1492,6 @@ typedef struct frv_stack {
    address of other frames.  */
 #define RETURN_ADDR_RTX(COUNT, FRAMEADDR) frv_return_addr_rtx (COUNT, FRAMEADDR)
 
-/* This function contains machine specific function data.  */
-struct machine_function GTY(())
-{
-  /* True if we have created an rtx that relies on the stack frame.  */
-  int frame_needed;
-};
-
 #define RETURN_POINTER_REGNUM LR_REGNO
 
 /* A C expression whose value is RTL representing the location of the incoming
index 5b744bb..d0f3592 100644 (file)
@@ -41,9 +41,7 @@
    (UNSPEC_EH_RETURN_EPILOGUE  6)
    (UNSPEC_GOT                 7)
    (UNSPEC_LDD                 8)
-   (UNSPEC_BUILTIN_LOAD                9)
-   (UNSPEC_BUILTIN_STORE       10)
-   (UNSPEC_OPTIONAL_MEMBAR     11)
+   (UNSPEC_OPTIONAL_MEMBAR     9)
 
    (UNSPEC_GETTLSOFF                   200)
    (UNSPEC_TLS_LOAD_GOTTLSOFF12                201)
     FAIL;
 }")
 \f
-;; The load part of a __builtin_read* function.
-;; Use UNSPECs to distinguish these patterns from normal moves.
-(define_insn "builtin_read_<mode>"
-  [(set (match_operand:SI 0 "register_operand" "=d")
-       (zero_extend:SI (unspec:IMODE
-                        [(match_operand:IMODE 1 "memory_operand" "m")]
-                        UNSPEC_BUILTIN_LOAD)))]
-  ""
-  "ld<BREADsuffix>%I1%U1 %M1,%0"
-  [(set_attr "length" "4")
-   (set_attr "type" "gload")])
-
-;; The store part of a __builtin_write* function.
-(define_insn "builtin_write_<mode>"
-  [(set (match_operand:IMODE 0 "memory_operand" "=m")
-       (unspec:IMODE [(match_operand:IMODE 1 "reg_or_0_operand" "dO")]
-                     UNSPEC_BUILTIN_STORE))]
-  ""
-  "st<IMODEsuffix>%I0%U0 %z1, %M0"
-  [(set_attr "length" "4")
-   (set_attr "type" "gstore")])
-
-;; This one has a different predicate for operand 1.
-(define_insn "builtin_write64"
-  [(set (match_operand:DI 0 "memory_operand" "=m")
-       (unspec:DI [(match_operand:DI 1 "register_operand" "d")]
-                  UNSPEC_BUILTIN_STORE))]
-  ""
-  "std%I0%U0 %z1, %M0"
-  [(set_attr "length" "4")
-   (set_attr "type" "gstore")])
 
+;; The "membar" part of a __builtin_read* or __builtin_write* function.
+;; Operand 0 is a volatile reference to the memory that the function reads
+;; or writes.  Operand 1 is the address being accessed, or zero if the
+;; address isn't a known constant.  Operand 2 describes the __builtin
+;; function (either FRV_IO_READ or FRV_IO_WRITE).
 (define_insn "optional_membar_<mode>"
   [(set (match_operand:IMODE 0 "memory_operand" "=m")
-       (unspec:IMODE [(const_int 0)] UNSPEC_OPTIONAL_MEMBAR))]
+       (unspec:IMODE [(match_operand 1 "const_int_operand" "")
+                      (match_operand 2 "const_int_operand" "")]
+                     UNSPEC_OPTIONAL_MEMBAR))]
   ""
   "membar"
   [(set_attr "length" "4")])
index 46d2381..7416dfa 100644 (file)
@@ -157,6 +157,10 @@ mno-eflags
 Target RejectNegative
 Do not mark ABI switches in e_flags
 
+moptimize-membar
+Target Report Mask(OPTIMIZE_MEMBAR)
+Remove redundant membars
+
 mpack
 Target Report Mask(PACK)
 Pack VLIW instructions
index f245055..d24e75b 100644 (file)
@@ -482,6 +482,7 @@ Objective-C and Objective-C++ Dialects}.
 -mlinked-fp  -mlong-calls  -malign-labels @gol
 -mlibrary-pic  -macc-4  -macc-8 @gol
 -mpack  -mno-pack  -mno-eflags  -mcond-move  -mno-cond-move @gol
+-moptimize-membar -mno-optimize-membar @gol
 -mscc  -mno-scc  -mcond-exec  -mno-cond-exec @gol
 -mvliw-branch  -mno-vliw-branch @gol
 -mmulti-cond-exec  -mno-multi-cond-exec  -mnested-cond-exec @gol
@@ -8526,6 +8527,18 @@ Disable nested conditional execution optimizations.
 This switch is mainly for debugging the compiler and will likely be removed
 in a future version.
 
+@item -moptimize-membar
+@opindex moptimize-membar
+
+This switch removes redundant @code{membar} instructions from the
+compiler generated code.  It is enabled by default.
+
+@item -mno-optimize-membar
+@opindex mno-optimize-membar
+
+This switch disables the automatic removal of redundant @code{membar}
+instructions from the generated code.
+
 @item -mtomcat-stats
 @opindex mtomcat-stats
 
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-read16.c b/gcc/testsuite/gcc.target/frv/all-builtin-read16.c
deleted file mode 100644 (file)
index 362cc84..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* { dg-do compile } */
-
-unsigned short z;
-
-void foo (void *x)
-{
-  z = __builtin_read16 (x);
-}
-
-/* { dg-final { scan-assembler "lduh" } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-read32.c b/gcc/testsuite/gcc.target/frv/all-builtin-read32.c
deleted file mode 100644 (file)
index 7e988a4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O" } */
-
-unsigned long z;
-
-void foo (void *x)
-{
-  z = __builtin_read32 (x);
-}
-
-/* { dg-final { scan-assembler "ld " } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-read64.c b/gcc/testsuite/gcc.target/frv/all-builtin-read64.c
deleted file mode 100644 (file)
index 1d5b656..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* { dg-do compile } */
-
-unsigned long long z;
-
-void foo (void *x)
-{
-  z = __builtin_read64 (x);
-}
-
-/* { dg-final { scan-assembler "ldd" } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-read8.c b/gcc/testsuite/gcc.target/frv/all-builtin-read8.c
deleted file mode 100644 (file)
index b53fb61..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* { dg-do compile } */
-
-unsigned char z;
-
-void foo (void *x)
-{
-  z = __builtin_read8 (x);
-}
-
-/* { dg-final { scan-assembler "ldub" } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-write16.c b/gcc/testsuite/gcc.target/frv/all-builtin-write16.c
deleted file mode 100644 (file)
index f9f1cb5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do compile } */
-
-unsigned short *addr;
-unsigned short datum;
-
-void foo ()
-{
-  __builtin_write16 (addr, datum);
-}
-
-/* { dg-final { scan-assembler "sth" } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-write32.c b/gcc/testsuite/gcc.target/frv/all-builtin-write32.c
deleted file mode 100644 (file)
index b977153..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do compile } */
-
-unsigned long *addr;
-unsigned long datum;
-
-void foo ()
-{
-  __builtin_write32 (addr, datum);
-}
-
-/* { dg-final { scan-assembler "st " } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-write64.c b/gcc/testsuite/gcc.target/frv/all-builtin-write64.c
deleted file mode 100644 (file)
index eac50a2..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do compile } */
-
-unsigned long long *addr;
-unsigned long long datum;
-
-void foo ()
-{
-  __builtin_write64 (addr, datum);
-}
-
-/* { dg-final { scan-assembler "std " } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-builtin-write8.c b/gcc/testsuite/gcc.target/frv/all-builtin-write8.c
deleted file mode 100644 (file)
index 56e4f3e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do compile } */
-
-unsigned char *addr;
-unsigned char datum;
-
-void foo ()
-{
-  __builtin_write8 (addr, datum);
-}
-
-/* { dg-final { scan-assembler "stb" } } */
-/* { dg-final { scan-assembler "membar" } } */
diff --git a/gcc/testsuite/gcc.target/frv/all-read-write-1.c b/gcc/testsuite/gcc.target/frv/all-read-write-1.c
new file mode 100644 (file)
index 0000000..8496a58
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+extern void abort (void);
+extern void exit (int);
+
+volatile unsigned long long x[2];
+
+int main ()
+{
+  volatile char *addr = (volatile char *) &x[0];
+
+  x[0] = ~0ULL;
+  x[1] = ~0ULL;
+  __builtin_write64 (addr, 0x1122334455667788ULL);
+  __builtin_write32 (addr + 8, 0x12345678);
+  __builtin_write16 (addr + 12, 0xaabb);
+  __builtin_write8 (addr + 14, 0xcc);
+
+  if (x[0] != 0x1122334455667788ULL
+      || x[1] != 0x12345678aabbccffULL
+      || __builtin_read8 (addr) != 0x11
+      || __builtin_read16 (addr + 2) != 0x3344
+      || __builtin_read32 (addr + 4) != 0x55667788
+      || __builtin_read64 (addr + 8) != 0x12345678aabbccffULL)
+    abort ();
+
+  __builtin_write64 (addr, 0);
+  __builtin_write32 (addr + 8, 0);
+  __builtin_write16 (addr + 12, 0);
+  __builtin_write8 (addr + 14, 0);
+  if (x[0] != 0 || x[1] != 0xff)
+    abort ();
+
+  exit (0);
+}