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]

patch: [FRV] membar optimization


While looking at uncontributed patches we have, I noticed we had a
much better __builtin_{read,write}* implementation that removes redundant
membar instructions.

This pass was written by Richard Sandiford, but was never contributed.

I've made some minor cosmetic changes, added documentation, and adapted
the code base to changes in edge iterators.

Richard S, could you take a peek at this, to make sure I didn't miss
anything?

This patch has been tested on ppc64-linux x frv-elf.

I'm committing to mainline.

	* 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.

Index: config/frv/frv.opt
===================================================================
RCS file: /cvs/uberbaum/gcc/config/frv/frv.opt,v
retrieving revision 1.2
diff -c -p -r1.2 frv.opt
*** config/frv/frv.opt	25 Jun 2005 01:21:05 -0000	1.2
--- config/frv/frv.opt	28 Jul 2005 01:50:10 -0000
*************** mno-eflags
*** 157,162 ****
--- 157,166 ----
  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: config/frv/frv.h
===================================================================
RCS file: /cvs/uberbaum/gcc/config/frv/frv.h,v
retrieving revision 1.68
diff -c -p -r1.68 frv.h
*** config/frv/frv.h	26 Jul 2005 15:41:49 -0000	1.68
--- config/frv/frv.h	28 Jul 2005 01:50:13 -0000
*************** typedef struct frv_stack {
*** 1492,1504 ****
     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
--- 1492,1497 ----
Index: config/frv/frv.c
===================================================================
RCS file: /cvs/uberbaum/gcc/config/frv/frv.c,v
retrieving revision 1.95
diff -c -p -r1.95 frv.c
*** config/frv/frv.c	26 Jul 2005 15:41:47 -0000	1.95
--- config/frv/frv.c	28 Jul 2005 01:50:17 -0000
*************** static GTY(()) rtx frv_nops[NUM_NOP_PATT
*** 109,114 ****
--- 109,129 ----
  /* 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)
*************** static unsigned int frv_num_nops;
*** 123,128 ****
--- 138,153 ----
         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
    {
*************** frv_override_options (void)
*** 756,761 ****
--- 781,789 ----
    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]);
  
*************** frv_ifcvt_modify_tests (ce_if_block_t *c
*** 5291,5297 ****
  
    if (join_bb)
      {
!       int regno;
  
        /* Remove anything live at the beginning of the join block from being
           available for allocation.  */
--- 5319,5325 ----
  
    if (join_bb)
      {
!       unsigned int regno;
  
        /* Remove anything live at the beginning of the join block from being
           available for allocation.  */
*************** frv_ifcvt_modify_tests (ce_if_block_t *c
*** 5328,5334 ****
      {
        rtx last_insn = BB_END (bb[j]);
        rtx insn = BB_HEAD (bb[j]);
!       int regno;
  
        if (dump_file)
  	fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n",
--- 5356,5362 ----
      {
        rtx last_insn = BB_END (bb[j]);
        rtx insn = BB_HEAD (bb[j]);
!       unsigned int regno;
  
        if (dump_file)
  	fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n",
*************** frv_fill_unused_units (enum frv_insn_gro
*** 7661,7666 ****
--- 7689,8022 ----
      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);
+ }
+ 
  /* Used by frv_reorg to keep track of the current packet's address.  */
  static unsigned int frv_packet_address;
  
*************** frv_register_nop (rtx nop)
*** 7773,7778 ****
--- 8129,8137 ----
  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)
*************** static struct builtin_description bdesc_
*** 7953,7985 ****
    { 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.  */
  
  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 }
  };
  
  /* 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 }
  };
  
  /* Initialize media builtins.  */
--- 8312,8344 ----
    { CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 }
  };
  
! /* 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_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_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.  */
*************** frv_matching_accg_mode (enum machine_mod
*** 8305,8310 ****
--- 8664,8681 ----
      }
  }
  
+ /* 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.  */
*************** frv_expand_voidaccop_builtin (enum insn_
*** 8670,8705 ****
    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".  */
  
  static rtx
! frv_expand_load_builtin (enum insn_code icode, enum insn_code membar_icode,
! 			 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)));
    return target;
  }
  
! /* Likewise __builtin_write* functions, with ICODE being the instruction
!    code of the store.  */
  
  static rtx
! frv_expand_store_builtin (enum insn_code icode, enum insn_code membar_icode,
! 			  tree arglist)
  {
!   rtx op0 = frv_read_argument (& arglist);
!   rtx op1 = frv_read_argument (& arglist);
  
!   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)));
    return NULL_RTX;
  }
  
--- 9041,9078 ----
    return NULL_RTX;
  }
  
! /* 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 machine_mode target_mode,
!                          tree arglist, rtx target)
  {
!   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.  */
  
  static rtx
! frv_expand_store_builtin (enum insn_code icode, tree 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[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;
  }
  
*************** frv_expand_builtin (tree exp,
*** 9049,9059 ****
  
    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);
  
    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 0;
  }
--- 9422,9433 ----
  
    for (i = 0, d = bdesc_loads; i < ARRAY_SIZE (bdesc_loads); i++, d++)
      if (d->code == fcode)
!       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, arglist);
  
    return 0;
  }
Index: config/frv/frv.md
===================================================================
RCS file: /cvs/uberbaum/gcc/config/frv/frv.md,v
retrieving revision 1.38
diff -c -p -r1.38 frv.md
*** config/frv/frv.md	26 Jul 2005 15:41:49 -0000	1.38
--- config/frv/frv.md	28 Jul 2005 01:50:20 -0000
***************
*** 41,49 ****
     (UNSPEC_EH_RETURN_EPILOGUE	6)
     (UNSPEC_GOT			7)
     (UNSPEC_LDD			8)
!    (UNSPEC_BUILTIN_LOAD		9)
!    (UNSPEC_BUILTIN_STORE	10)
!    (UNSPEC_OPTIONAL_MEMBAR	11)
  
     (UNSPEC_GETTLSOFF			200)
     (UNSPEC_TLS_LOAD_GOTTLSOFF12		201)
--- 41,47 ----
     (UNSPEC_EH_RETURN_EPILOGUE	6)
     (UNSPEC_GOT			7)
     (UNSPEC_LDD			8)
!    (UNSPEC_OPTIONAL_MEMBAR	9)
  
     (UNSPEC_GETTLSOFF			200)
     (UNSPEC_TLS_LOAD_GOTTLSOFF12		201)
***************
*** 2168,2208 ****
      FAIL;
  }")
  
- ;; 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")])
  
  (define_insn "optional_membar_<mode>"
    [(set (match_operand:IMODE 0 "memory_operand" "=m")
! 	(unspec:IMODE [(const_int 0)] UNSPEC_OPTIONAL_MEMBAR))]
    ""
    "membar"
    [(set_attr "length" "4")])
--- 2166,2182 ----
      FAIL;
  }")
  
  
+ ;; 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 [(match_operand 1 "const_int_operand" "")
! 		       (match_operand 2 "const_int_operand" "")]
! 		      UNSPEC_OPTIONAL_MEMBAR))]
    ""
    "membar"
    [(set_attr "length" "4")])
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/uberbaum/gcc/doc/invoke.texi,v
retrieving revision 1.640
diff -c -p -r1.640 invoke.texi
*** doc/invoke.texi	28 Jun 2005 02:20:29 -0000	1.640
--- doc/invoke.texi	28 Jul 2005 01:50:29 -0000
*************** Objective-C and Objective-C++ Dialects}.
*** 478,483 ****
--- 478,484 ----
  -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
*************** Disable nested conditional execution opt
*** 8464,8469 ****
--- 8465,8482 ----
  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
  
Index: testsuite/gcc.target/frv/all-builtin-read8.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-read8.c
diff -N testsuite/gcc.target/frv/all-builtin-read8.c
*** testsuite/gcc.target/frv/all-builtin-read8.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,11 ****
- /* { dg-do compile } */
- 
- unsigned char z;
- 
- void foo (void *x)
- {
-   z = __builtin_read8 (x);
- }
- 
- /* { dg-final { scan-assembler "ldub" } } */
- /* { dg-final { scan-assembler "membar" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-builtin-read16.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-read16.c
diff -N testsuite/gcc.target/frv/all-builtin-read16.c
*** testsuite/gcc.target/frv/all-builtin-read16.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,11 ****
- /* { dg-do compile } */
- 
- unsigned short z;
- 
- void foo (void *x)
- {
-   z = __builtin_read16 (x);
- }
- 
- /* { dg-final { scan-assembler "lduh" } } */
- /* { dg-final { scan-assembler "membar" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-builtin-read32.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-read32.c
diff -N testsuite/gcc.target/frv/all-builtin-read32.c
*** testsuite/gcc.target/frv/all-builtin-read32.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,12 ****
- /* { 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" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-builtin-read64.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-read64.c
diff -N testsuite/gcc.target/frv/all-builtin-read64.c
*** testsuite/gcc.target/frv/all-builtin-read64.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,11 ****
- /* { 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" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-builtin-write8.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-write8.c
diff -N testsuite/gcc.target/frv/all-builtin-write8.c
*** testsuite/gcc.target/frv/all-builtin-write8.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,12 ****
- /* { 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" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-builtin-write16.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-write16.c
diff -N testsuite/gcc.target/frv/all-builtin-write16.c
*** testsuite/gcc.target/frv/all-builtin-write16.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,12 ****
- /* { 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" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-builtin-write32.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-write32.c
diff -N testsuite/gcc.target/frv/all-builtin-write32.c
*** testsuite/gcc.target/frv/all-builtin-write32.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,12 ****
- /* { 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" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-builtin-write64.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-builtin-write64.c
diff -N testsuite/gcc.target/frv/all-builtin-write64.c
*** testsuite/gcc.target/frv/all-builtin-write64.c	26 Jul 2005 15:41:47 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,12 ****
- /* { 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" } } */
--- 0 ----
Index: testsuite/gcc.target/frv/all-read-write-1.c
===================================================================
RCS file: testsuite/gcc.target/frv/all-read-write-1.c
diff -N testsuite/gcc.target/frv/all-read-write-1.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.target/frv/all-read-write-1.c	28 Jul 2005 01:50:29 -0000
***************
*** 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);
+ }


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