[patch] TARGET_MEM_REF (resent 2)

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Mon Apr 4 20:25:00 GMT 2005


Hello,

this version of the patch reflects the Steven's comments.  Bootstrapped
& regtested on i686.

Zdenek

	* tree-ssa-address.c: New file.
	* Makefile.in (tree-ssa-address.o): Add.
	* expr.c (expand_expr_real_1): Do not handle REF_ORIGINAL on
	INDIRECT_REFs.  Handle TARGET_MEM_REFs.
	* gimplify.c (gimplify_addr_expr): Handle TARGET_MEM_REFs.
	* tree-dfa.c (create_tmr_ann): New function.
	* tree-eh.c (tree_could_trap_p): Handle TARGET_MEM_REFs.
	* tree-flow-inline.h (tmr_ann, get_tmr_ann): New functions.
	* tree-flow.h (enum tree_ann_type): Add TMR_ANN.
	(struct tmr_ann_d, tmr_ann_t): New.
	(union tree_ann_d): Add tmr.
	(tmr_ann, get_tmr_ann, create_tmr_ann): Declare.
	(struct mem_address): New.
	(create_mem_ref, addr_for_mem_ref, get_address_description,
	maybe_fold_tmr):  Declare.
	* tree-mudflap.c (mf_xform_derefs_1): Handle TARGET_MEM_REFs.
	* tree-pretty-print.c (dump_generic_node): Ditto.
	* tree-ssa-loop-im.c (for_each_index): Ditto.
	* tree-ssa-loop-ivopts.c (may_be_unaligned_p,
	find_interesting_uses_address): Ditto.
	(rewrite_address_base): Removed.
	(get_ref_tag, copy_ref_info): New functions.
	(rewrite_use_address): Produce TARGET_MEM_REFs.
	* tree-ssa-operands.c (get_tmr_operands): New function.
	(get_expr_operands): Handle TARGET_MEM_REFs.
	* tree.c (copy_node_stat): Copy annotations for TARGET_MEM_REFs.
	(build): Handle 5 arguments.
	(build5_stat): New function.
	* tree.def (TARGET_MEM_DEF): New.
	* tree.h (REF_ORIGINAL): Removed.
	(TMR_SYMBOL, TMR_BASE, TMR_INDEX, TMR_STEP, TMR_OFFSET, build5): New
	macros.
	(build5_stat, tree_mem_ref_addr, copy_mem_ref_info): Declare.
	* tree-ssa-ccp.c (fold_stmt_r): Call maybe_fold_tmr.
	* doc/c-tree.texi: Document TARGET_MEM_REF.
	* doc/tree-ssa.texi: Add TARGET_MEM_REF to gimple grammar.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1461
diff -c -3 -p -r1.1461 Makefile.in
*** Makefile.in	31 Mar 2005 16:38:25 -0000	1.1461
--- Makefile.in	4 Apr 2005 11:37:36 -0000
*************** OBJS-common = \
*** 922,928 ****
   tree-chrec.o tree-scalar-evolution.o tree-data-ref.o			   \
   tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o  \
   gimplify.o tree-pretty-print.o tree-into-ssa.o          \
!  tree-outof-ssa.o tree-ssa-ccp.o tree-vn.o             \
   tree-ssa-dce.o  tree-ssa-copy.o tree-nrv.o tree-ssa-copyrename.o  \
   tree-ssa-pre.o tree-ssa-live.o tree-ssa-operands.o tree-ssa-alias.o       \
   tree-ssa-phiopt.o tree-ssa-forwprop.o tree-nested.o tree-ssa-dse.o	   \
--- 922,928 ----
   tree-chrec.o tree-scalar-evolution.o tree-data-ref.o			   \
   tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o  \
   gimplify.o tree-pretty-print.o tree-into-ssa.o          \
!  tree-outof-ssa.o tree-ssa-ccp.o tree-vn.o tree-ssa-address.o             \
   tree-ssa-dce.o  tree-ssa-copy.o tree-nrv.o tree-ssa-copyrename.o  \
   tree-ssa-pre.o tree-ssa-live.o tree-ssa-operands.o tree-ssa-alias.o       \
   tree-ssa-phiopt.o tree-ssa-forwprop.o tree-nested.o tree-ssa-dse.o	   \
*************** tree-ssa-loop.o : tree-ssa-loop.c $(TREE
*** 1726,1731 ****
--- 1726,1736 ----
     $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) \
     output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
     tree-pass.h $(FLAGS_H) tree-inline.h $(SCEV_H)
+ tree-ssa-address.o : tree-ssa-address.c $(TREE_FLOW_H) $(CONFIG_H) \
+    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) \
+    output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
+    tree-pass.h $(FLAGS_H) tree-inline.h $(RECOG_H) insn-config.h $(EXPR_H) \
+    gt-tree-ssa-address.h $(GGC_H)
  tree-ssa-loop-unswitch.o : tree-ssa-loop-unswitch.c $(TREE_FLOW_H) $(CONFIG_H) \
     $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) domwalk.h $(PARAMS_H)\
     output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
*************** GTFILES = $(srcdir)/input.h $(srcdir)/co
*** 2456,2462 ****
    $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \
    $(srcdir)/tree-mudflap.c $(srcdir)/tree-flow.h \
    $(srcdir)/c-objc-common.c $(srcdir)/c-common.c $(srcdir)/c-parser.c \
!   $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c \
    $(srcdir)/tree-phinodes.c $(srcdir)/tree-cfg.c \
    $(srcdir)/tree-dfa.c $(srcdir)/tree-ssa-propagate.c \
    $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \
--- 2461,2467 ----
    $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \
    $(srcdir)/tree-mudflap.c $(srcdir)/tree-flow.h \
    $(srcdir)/c-objc-common.c $(srcdir)/c-common.c $(srcdir)/c-parser.c \
!   $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c $(srcdir)/tree-ssa-address.c \
    $(srcdir)/tree-phinodes.c $(srcdir)/tree-cfg.c \
    $(srcdir)/tree-dfa.c $(srcdir)/tree-ssa-propagate.c \
    $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \
*************** gt-dwarf2out.h gt-reg-stack.h gt-dwarf2a
*** 2480,2486 ****
  gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parser.h \
  gt-c-pragma.h gtype-c.h gt-cfglayout.h \
  gt-tree-mudflap.h gt-tree-complex.h \
! gt-tree-eh.h \
  gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \
  gt-tree-phinodes.h gt-tree-cfg.h gt-tree-nested.h \
  gt-tree-ssa-operands.h gt-tree-ssa-propagate.h \
--- 2485,2491 ----
  gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parser.h \
  gt-c-pragma.h gtype-c.h gt-cfglayout.h \
  gt-tree-mudflap.h gt-tree-complex.h \
! gt-tree-eh.h gt-tree-ssa-address.h \
  gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \
  gt-tree-phinodes.h gt-tree-cfg.h gt-tree-nested.h \
  gt-tree-ssa-operands.h gt-tree-ssa-propagate.h \
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.783
diff -c -3 -p -r1.783 expr.c
*** expr.c	30 Mar 2005 21:34:23 -0000	1.783
--- expr.c	4 Apr 2005 11:37:37 -0000
*************** expand_expr_real_1 (tree exp, rtx target
*** 6822,6828 ****
      case INDIRECT_REF:
        {
  	tree exp1 = TREE_OPERAND (exp, 0);
- 	tree orig;
  
  	if (modifier != EXPAND_WRITE)
  	  {
--- 6822,6827 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 6845,6854 ****
  
  	temp = gen_rtx_MEM (mode, op0);
  
! 	orig = REF_ORIGINAL (exp);
! 	if (!orig)
! 	  orig = exp;
! 	set_mem_attributes (temp, orig, 0);
  
  	/* Resolve the misalignment now, so that we don't have to remember
  	   to resolve it later.  Of course, this only works for reads.  */
--- 6844,6850 ----
  
  	temp = gen_rtx_MEM (mode, op0);
  
! 	set_mem_attributes (temp, exp, 0);
  
  	/* Resolve the misalignment now, so that we don't have to remember
  	   to resolve it later.  Of course, this only works for reads.  */
*************** expand_expr_real_1 (tree exp, rtx target
*** 6880,6885 ****
--- 6876,6893 ----
  	return temp;
        }
  
+     case TARGET_MEM_REF:
+       {
+ 	struct mem_address addr;
+ 
+ 	get_address_description (exp, &addr);
+ 	op0 = addr_for_mem_ref (&addr, true);
+ 	op0 = memory_address (mode, op0);
+ 	temp = gen_rtx_MEM (mode, op0);
+ 	set_mem_attributes (temp, tmr_ann (exp)->original, 0);
+       }
+       return temp;
+ 
      case ARRAY_REF:
  
        {
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.122
diff -c -3 -p -r2.122 gimplify.c
*** gimplify.c	1 Apr 2005 03:42:41 -0000	2.122
--- gimplify.c	4 Apr 2005 11:37:37 -0000
*************** gimplify_addr_expr (tree *expr_p, tree *
*** 3270,3275 ****
--- 3270,3280 ----
        ret = GS_OK;
        break;
  
+     case TARGET_MEM_REF:
+       *expr_p = tree_mem_ref_addr (TREE_TYPE (expr), op0);
+       ret = GS_OK;
+       break;
+ 
      default:
        /* We use fb_either here because the C frontend sometimes takes
  	 the address of a call that returns a struct; see
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dfa.c,v
retrieving revision 2.50
diff -c -3 -p -r2.50 tree-dfa.c
*** tree-dfa.c	13 Mar 2005 00:45:49 -0000	2.50
--- tree-dfa.c	4 Apr 2005 11:37:37 -0000
*************** create_stmt_ann (tree t)
*** 446,451 ****
--- 446,470 ----
    return ann;
  }
  
+ /* Create a new annotation for a TARGET_MEM_REF node T.  */
+ 
+ tmr_ann_t
+ create_tmr_ann (tree t)
+ {
+   tmr_ann_t ann;
+ 
+   gcc_assert (TREE_CODE (t) == TARGET_MEM_REF);
+   gcc_assert (!t->common.ann || t->common.ann->common.type == TMR_ANN);
+ 
+   ann = ggc_alloc (sizeof (*ann));
+   memset ((void *) ann, 0, sizeof (*ann));
+ 
+   ann->common.type = TMR_ANN;
+ 
+   t->common.ann = (tree_ann_t) ann;
+ 
+   return ann;
+ }
  
  /* Create a new annotation for a tree T.  */
  
Index: tree-eh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-eh.c,v
retrieving revision 2.28
diff -c -3 -p -r2.28 tree-eh.c
*** tree-eh.c	1 Apr 2005 03:42:44 -0000	2.28
--- tree-eh.c	4 Apr 2005 11:37:37 -0000
*************** tree_could_trap_p (tree expr)
*** 1739,1744 ****
--- 1739,1751 ----
   restart:
    switch (code)
      {
+     case TARGET_MEM_REF:
+       /* For TARGET_MEM_REFs use the information based on the original
+ 	 reference.  */
+       expr = tmr_ann (expr)->original;
+       code = TREE_CODE (expr);
+       goto restart;
+ 
      case COMPONENT_REF:
      case REALPART_EXPR:
      case IMAGPART_EXPR:
Index: tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow-inline.h,v
retrieving revision 2.34
diff -c -3 -p -r2.34 tree-flow-inline.h
*** tree-flow-inline.h	21 Mar 2005 19:26:58 -0000	2.34
--- tree-flow-inline.h	4 Apr 2005 11:37:37 -0000
*************** get_stmt_ann (tree stmt)
*** 67,72 ****
--- 67,92 ----
  }
  
  
+ /* Return the annotation for T, which must be a TARGET_MEM_REF
+    node.  Return NULL if the statement annotation doesn't exist.  */
+ static inline tmr_ann_t
+ tmr_ann (tree t)
+ {
+ #ifdef ENABLE_CHECKING
+   gcc_assert (TREE_CODE (t) == TARGET_MEM_REF);
+ #endif
+   return (tmr_ann_t) t->common.ann;
+ }
+ 
+ /* Return the annotation for T, which must be a TARGET_MEM_REF
+    node.  Create the annotation if it doesn't exist.  */
+ static inline tmr_ann_t
+ get_tmr_ann (tree t)
+ {
+   tmr_ann_t ann = tmr_ann (t);
+   return ann ? ann : create_tmr_ann (t);
+ }
+ 
  /* Return the annotation type for annotation ANN.  */
  static inline enum tree_ann_type
  ann_type (tree_ann_t ann)
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 2.88
diff -c -3 -p -r2.88 tree-flow.h
*** tree-flow.h	29 Mar 2005 11:45:49 -0000	2.88
--- tree-flow.h	4 Apr 2005 11:37:37 -0000
*************** struct ptr_info_def GTY(())
*** 83,89 ****
  /*---------------------------------------------------------------------------
  		   Tree annotations stored in tree_common.ann
  ---------------------------------------------------------------------------*/
! enum tree_ann_type { TREE_ANN_COMMON, VAR_ANN, STMT_ANN };
  
  struct tree_ann_common_d GTY(())
  {
--- 83,89 ----
  /*---------------------------------------------------------------------------
  		   Tree annotations stored in tree_common.ann
  ---------------------------------------------------------------------------*/
! enum tree_ann_type { TREE_ANN_COMMON, VAR_ANN, STMT_ANN, TMR_ANN };
  
  struct tree_ann_common_d GTY(())
  {
*************** struct stmt_ann_d GTY(())
*** 317,327 ****
--- 317,342 ----
    void * GTY ((skip (""))) histograms;
  };
  
+ /* Annotation for TARGET_MEM_REFs.  */
+ 
+ struct tmr_ann_d GTY(())
+ {
+   struct tree_ann_common_d common;
+ 
+   /* Name tag, type tag, or base object, whichever is applicable
+      for the reference from that the TARGET_MEM_REF was created.  */
+   tree tag;
+ 
+   /* Original memory reference corresponding to the TARGET_MEM_REF.  */
+   tree original;
+ };
+ 
  union tree_ann_d GTY((desc ("ann_type ((tree_ann_t)&%h)")))
  {
    struct tree_ann_common_d GTY((tag ("TREE_ANN_COMMON"))) common;
    struct var_ann_d GTY((tag ("VAR_ANN"))) decl;
    struct stmt_ann_d GTY((tag ("STMT_ANN"))) stmt;
+   struct tmr_ann_d GTY((tag ("TMR_ANN"))) tmr;
  };
  
  extern GTY(()) VEC(tree) *modified_noreturn_calls;
*************** extern GTY(()) VEC(tree) *modified_noret
*** 329,334 ****
--- 344,350 ----
  typedef union tree_ann_d *tree_ann_t;
  typedef struct var_ann_d *var_ann_t;
  typedef struct stmt_ann_d *stmt_ann_t;
+ typedef struct tmr_ann_d *tmr_ann_t;
  
  static inline tree_ann_t tree_ann (tree);
  static inline tree_ann_t get_tree_ann (tree);
*************** static inline var_ann_t var_ann (tree);
*** 336,341 ****
--- 352,359 ----
  static inline var_ann_t get_var_ann (tree);
  static inline stmt_ann_t stmt_ann (tree);
  static inline stmt_ann_t get_stmt_ann (tree);
+ static inline tmr_ann_t tmr_ann (tree);
+ static inline tmr_ann_t get_tmr_ann (tree);
  static inline enum tree_ann_type ann_type (tree_ann_t);
  static inline basic_block bb_for_stmt (tree);
  extern void set_bb_for_stmt (tree, basic_block);
*************** extern void dump_generic_bb (FILE *, bas
*** 545,550 ****
--- 563,569 ----
  /* In tree-dfa.c  */
  extern var_ann_t create_var_ann (tree);
  extern stmt_ann_t create_stmt_ann (tree);
+ extern tmr_ann_t create_tmr_ann (tree);
  extern tree_ann_t create_tree_ann (tree);
  extern void reserve_phi_args_for_new_edge (basic_block);
  extern tree create_phi_node (tree, basic_block);
*************** extern bool expr_invariant_in_loop_p (st
*** 785,790 ****
--- 804,823 ----
  
  tree force_gimple_operand (tree, tree *, bool, tree);
  
+ /* In tree-ssa-address.c  */
+ 
+ /* Description of a memory address.  */
+ 
+ struct mem_address
+ {
+   tree symbol, base, index, step, offset;
+ };
+ 
+ tree create_mem_ref (block_stmt_iterator *, tree, tree);
+ rtx addr_for_mem_ref (struct mem_address *, bool);
+ void get_address_description (tree, struct mem_address *);
+ tree maybe_fold_tmr (tree);
+ 
  #include "tree-flow-inline.h"
  
  #endif /* _TREE_FLOW_H  */
Index: tree-mudflap.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-mudflap.c,v
retrieving revision 2.36
diff -c -3 -p -r2.36 tree-mudflap.c
*** tree-mudflap.c	11 Mar 2005 09:05:08 -0000	2.36
--- tree-mudflap.c	4 Apr 2005 11:37:37 -0000
*************** mf_xform_derefs_1 (block_stmt_iterator *
*** 853,858 ****
--- 853,866 ----
                             integer_one_node));
        break;
  
+     case TARGET_MEM_REF:
+       addr = tree_mem_ref_addr (ptr_type_node, t);
+       base = addr;
+       limit = fold (build2 (MINUS_EXPR, ptr_type_node,
+ 			    fold (build2 (PLUS_EXPR, ptr_type_node, base, size)),
+ 			    build_int_cst_type (ptr_type_node, 1)));
+       break;
+ 
      case ARRAY_RANGE_REF:
        warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
        return;
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.53
diff -c -3 -p -r2.53 tree-pretty-print.c
*** tree-pretty-print.c	30 Mar 2005 21:34:28 -0000	2.53
--- tree-pretty-print.c	4 Apr 2005 11:37:37 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 441,446 ****
--- 441,504 ----
        pp_string (buffer, "::");
        break;
  
+     case TARGET_MEM_REF:
+       {
+ 	const char *sep = "";
+ 	tree tmp;
+ 
+ 	pp_string (buffer, "MEM[");
+ 
+ 	tmp = TMR_SYMBOL (node);
+ 	if (tmp)
+ 	  {
+ 	    pp_string (buffer, sep);
+ 	    sep = ", ";
+ 	    pp_string (buffer, "symbol: ");
+ 	    dump_generic_node (buffer, tmp, spc, flags, false);
+ 	  }
+ 	tmp = TMR_BASE (node);
+ 	if (tmp)
+ 	  {
+ 	    pp_string (buffer, sep);
+ 	    sep = ", ";
+ 	    pp_string (buffer, "base: ");
+ 	    dump_generic_node (buffer, tmp, spc, flags, false);
+ 	  }
+ 	tmp = TMR_INDEX (node);
+ 	if (tmp)
+ 	  {
+ 	    pp_string (buffer, sep);
+ 	    sep = ", ";
+ 	    pp_string (buffer, "index: ");
+ 	    dump_generic_node (buffer, tmp, spc, flags, false);
+ 	  }
+ 	tmp = TMR_STEP (node);
+ 	if (tmp)
+ 	  {
+ 	    pp_string (buffer, sep);
+ 	    sep = ", ";
+ 	    pp_string (buffer, "step: ");
+ 	    dump_generic_node (buffer, tmp, spc, flags, false);
+ 	  }
+ 	tmp = TMR_OFFSET (node);
+ 	if (tmp)
+ 	  {
+ 	    pp_string (buffer, sep);
+ 	    sep = ", ";
+ 	    pp_string (buffer, "offset: ");
+ 	    dump_generic_node (buffer, tmp, spc, flags, false);
+ 	  }
+ 	pp_string (buffer, "]");
+ 	if (flags & TDF_DETAILS)
+ 	  {
+ 	    pp_string (buffer, "{");
+ 	    dump_generic_node (buffer, tmr_ann (node)->original, spc, flags,
+ 			       false);
+ 	    pp_string (buffer, "}");
+ 	  }
+       }
+       break;
+ 
      case ARRAY_TYPE:
        {
  	tree tmp;
Index: tree-ssa-address.c
===================================================================
RCS file: tree-ssa-address.c
diff -N tree-ssa-address.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- tree-ssa-address.c	4 Apr 2005 11:37:37 -0000
***************
*** 0 ****
--- 1,937 ----
+ /* Memory address lowering and addressing mode selection.
+    Copyright (C) 2004 Free Software Foundation, Inc.
+    
+ This file is part of GCC.
+    
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+    
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+    
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.  */
+ 
+ /* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
+    that directly map to addressing modes of the target.  */
+ 
+ #include "config.h"
+ #include "system.h"
+ #include "coretypes.h"
+ #include "tm.h"
+ #include "tree.h"
+ #include "rtl.h"
+ #include "tm_p.h"
+ #include "hard-reg-set.h"
+ #include "basic-block.h"
+ #include "output.h"
+ #include "diagnostic.h"
+ #include "tree-flow.h"
+ #include "tree-dump.h"
+ #include "tree-pass.h"
+ #include "timevar.h"
+ #include "flags.h"
+ #include "tree-inline.h"
+ #include "insn-config.h"
+ #include "recog.h"
+ #include "expr.h"
+ #include "ggc.h"
+ 
+ /* A "template" for memory address, used to determine whether the address is
+    valid for mode.  */
+ 
+ struct mem_addr_template GTY (())
+ {
+   rtx ref;			/* The template.  */
+   rtx * GTY ((skip)) step_p;	/* The point in template where the step should be
+ 				   filled in.  */
+   rtx * GTY ((skip)) off_p;	/* The point in template where the offset should
+ 				   be filled in.  */
+ };
+ 
+ /* The templates.  Each of the five bits of the index corresponds to one
+    component of TARGET_MEM_REF being present, see TEMPL_IDX.  */
+ 
+ static GTY (()) struct mem_addr_template templates[32];
+ 
+ #define TEMPL_IDX(SYMBOL, BASE, INDEX, STEP, OFFSET) \
+   (((SYMBOL != 0) << 4) \
+    | ((BASE != 0) << 3) \
+    | ((INDEX != 0) << 2) \
+    | ((STEP != 0) << 1) \
+    | (OFFSET != 0))
+ 
+ /* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR.  If
+    some statements are produced, emits them before BSI.  */
+ 
+ static tree
+ force_gimple_operand_bsi (block_stmt_iterator *bsi, tree expr,
+ 			  bool simple_p, tree var)
+ {
+   tree stmts;
+ 
+   expr = force_gimple_operand (unshare_expr (expr), &stmts, simple_p, var);
+   if (stmts)
+     bsi_insert_before (bsi, stmts, BSI_SAME_STMT);
+ 
+   return expr;
+ }
+ 
+ /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
+    STEP and OFFSET to *ADDR.  Stores pointers to where step is placed to
+    *STEP_P and offset to *OFFSET_P.  */
+ 
+ static void
+ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset,
+ 	      rtx *addr, rtx **step_p, rtx **offset_p)
+ {
+   rtx act_elem;
+ 
+   *addr = NULL_RTX;
+   if (step_p)
+     *step_p = NULL;
+   if (offset_p)
+     *offset_p = NULL;
+ 
+   if (index)
+     {
+       act_elem = index;
+       if (step)
+ 	{
+ 	  act_elem = gen_rtx_fmt_ee (MULT, Pmode, act_elem, step);
+ 
+ 	  if (step_p)
+ 	    *step_p = &XEXP (act_elem, 1);
+ 	}
+ 
+       *addr = act_elem;
+     }
+ 
+   if (base)
+     {
+       if (*addr)
+ 	*addr = gen_rtx_fmt_ee (PLUS, Pmode, *addr, base);
+       else
+ 	*addr = base;
+     }
+ 
+   if (symbol)
+     {
+       act_elem = symbol;
+       if (offset)
+ 	{
+ 	  act_elem = gen_rtx_fmt_e (CONST, Pmode,
+ 				    gen_rtx_fmt_ee (PLUS, Pmode,
+ 						    act_elem, offset));
+ 	  if (offset_p)
+ 	    *offset_p = &XEXP (XEXP (act_elem, 0), 1);
+ 	}
+ 
+       if (*addr)
+ 	*addr = gen_rtx_fmt_ee (PLUS, Pmode, *addr, act_elem);
+       else
+ 	*addr = act_elem;
+     }
+   else if (offset)
+     {
+       if (*addr)
+ 	{
+ 	  *addr = gen_rtx_fmt_ee (PLUS, Pmode, *addr, offset);
+ 	  if (offset_p)
+ 	    *offset_p = &XEXP (*addr, 1);
+ 	}
+       else
+ 	{
+ 	  *addr = offset;
+ 	  if (offset_p)
+ 	    *offset_p = addr;
+ 	}
+     }
+ 
+   if (!*addr)
+     *addr = const0_rtx;
+ }
+ 
+ /* Returns address for TARGET_MEM_REF with parameters given by ADDR.
+    If REALLY_EXPAND is false, just make fake registers instead 
+    of really expanding the operands, and perform the expansion in-place
+    by using one of the "templates".  */
+ 
+ rtx
+ addr_for_mem_ref (struct mem_address *addr, bool really_expand)
+ {
+   rtx address, sym, bse, idx, st, off;
+   static bool templates_initialized = false;
+   struct mem_addr_template *templ;
+ 
+   if (addr->step && !integer_onep (addr->step))
+     st = immed_double_const (TREE_INT_CST_LOW (addr->step),
+ 			     TREE_INT_CST_HIGH (addr->step), Pmode);
+   else
+     st = NULL_RTX;
+ 
+   if (addr->offset && !integer_zerop (addr->offset))
+     off = immed_double_const (TREE_INT_CST_LOW (addr->offset),
+ 			      TREE_INT_CST_HIGH (addr->offset), Pmode);
+   else
+     off = NULL_RTX;
+ 
+   if (!really_expand)
+     {
+       /* Reuse the templates for addresses, so that we do not waste memory.  */
+       if (!templates_initialized)
+ 	{
+ 	  unsigned i;
+ 
+ 	  templates_initialized = true;
+ 	  sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("test_symbol"));
+ 	  bse = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER);
+ 	  idx = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER + 1);
+ 
+ 	  for (i = 0; i < 32; i++)
+ 	    gen_addr_rtx ((i & 16 ? sym : NULL_RTX),
+ 			  (i & 8 ? bse : NULL_RTX),
+ 			  (i & 4 ? idx : NULL_RTX),
+ 			  (i & 2 ? const0_rtx : NULL_RTX),
+ 			  (i & 1 ? const0_rtx : NULL_RTX),
+ 			  &templates[i].ref,
+ 			  &templates[i].step_p,
+ 			  &templates[i].off_p);
+ 	}
+ 
+       templ = templates + TEMPL_IDX (addr->symbol, addr->base, addr->index,
+ 				     st, off);
+       if (st)
+ 	*templ->step_p = st;
+       if (off)
+ 	*templ->off_p = off;
+ 
+       return templ->ref;
+     }
+ 
+   /* Otherwise really expand the expressions.  */
+   sym = (addr->symbol
+ 	 ? expand_expr (build_addr (addr->symbol), NULL_RTX, Pmode, EXPAND_NORMAL)
+ 	 : NULL_RTX);
+   bse = (addr->base
+ 	 ? expand_expr (addr->base, NULL_RTX, Pmode, EXPAND_NORMAL)
+ 	 : NULL_RTX);
+   idx = (addr->index
+ 	 ? expand_expr (addr->index, NULL_RTX, Pmode, EXPAND_NORMAL)
+ 	 : NULL_RTX);
+ 
+   gen_addr_rtx (sym, bse, idx, st, off, &address, NULL, NULL);
+   return address;
+ }
+ 
+ /* Returns address of MEM_REF in TYPE.  */
+ 
+ tree
+ tree_mem_ref_addr (tree type, tree mem_ref)
+ {
+   tree addr = NULL_TREE;
+   tree act_elem;
+   tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
+ 
+   act_elem = TMR_INDEX (mem_ref);
+   if (act_elem)
+     {
+       act_elem = fold_convert (type, act_elem);
+ 
+       if (step)
+ 	act_elem = fold_build2 (MULT_EXPR, type, act_elem,
+ 				fold_convert (type, step));
+       addr = act_elem;
+     }
+ 
+   act_elem = TMR_BASE (mem_ref);
+   if (act_elem)
+     {
+       act_elem = fold_convert (type, act_elem);
+ 
+       if (addr)
+ 	addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
+       else
+ 	addr = act_elem;
+     }
+ 
+   act_elem = TMR_SYMBOL (mem_ref);
+   if (act_elem)
+     {
+       act_elem = fold_convert (type, build_addr (act_elem));
+       if (addr)
+ 	addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
+       else
+ 	addr = act_elem;
+     }
+ 
+   if (!zero_p (offset))
+     {
+       act_elem = fold_convert (type, offset);
+ 
+       if (addr)
+ 	addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
+       else
+ 	addr = act_elem;
+     }
+ 
+   if (!addr)
+     addr = build_int_cst (type, 0);
+ 
+   return addr;
+ }
+ 
+ /* Returns true if a memory reference in MODE and with parameters given by
+    ADDR is valid on the current target.  */
+ 
+ static bool
+ valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr)
+ {
+   rtx address;
+ 
+   address = addr_for_mem_ref (addr, false);
+   if (!address)
+     return false;
+ 
+   return memory_address_p (mode, address);
+ }
+ 
+ /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
+    is valid on the current target and if so, creates and returns the
+    TARGET_MEM_REF.  */
+ 
+ static tree
+ create_mem_ref_raw (tree type, struct mem_address *addr)
+ {
+   if (!valid_mem_ref_p (TYPE_MODE (type), addr))
+     return NULL_TREE;
+ 
+   if (addr->step && integer_onep (addr->step))
+     addr->step = NULL_TREE;
+ 
+   if (addr->offset && zero_p (addr->offset))
+     addr->offset = NULL_TREE;
+ 
+   return build5 (TARGET_MEM_REF, type,
+ 		 addr->symbol, addr->base, addr->index,
+ 		 addr->step, addr->offset);
+ }
+ 
+ /* Adds register REG to the address PARTS, multiplied by MUL.  */
+ 
+ static void
+ add_reg_to_parts (struct mem_address *parts, tree reg, tree mul)
+ {
+   tree tmp;
+ 
+   if (zero_p (mul))
+     return;
+   mul = fold_convert (ptr_type_node, mul);
+ 
+   /* If REG is INDEX already, just adjust the step.  */
+   if (parts->index
+       && operand_equal_p (parts->index, reg, 0))
+     {
+       if (parts->step)
+ 	parts->step
+ 		= fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
+ 					   parts->step, mul);
+       else
+ 	parts->step
+ 		= fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
+ 					   mul,
+ 					   build_int_cst_type (ptr_type_node,
+ 							       1));
+ 
+       if (zero_p (parts->step))
+ 	{
+ 	  parts->step = NULL_TREE;
+ 	  parts->index = NULL_TREE;
+ 	}
+ 
+       return;
+     }
+ 
+   /* Equal to base; try putting it to the step with an appropriate index.  */
+   if (parts->base
+       && operand_equal_p (parts->base, reg, 0))
+     {
+       mul = fold_binary_to_constant (PLUS_EXPR, ptr_type_node, mul,
+ 				     build_int_cst_type (ptr_type_node, 1));
+       if (zero_p (mul))
+ 	{
+ 	  parts->base = NULL_TREE;
+ 	  return;
+ 	}
+ 
+       if (!parts->step)
+ 	{
+ 	  parts->base = parts->index;
+ 	  parts->index = fold_convert (ptr_type_node, reg);
+ 	  parts->step = mul;
+ 	  return;
+ 	}
+ 
+       /* MUL * REG + STEP * INDEX.  If MUL == STEP, just add REG to INDEX.  */
+       if (operand_equal_p (parts->step, mul, 0))
+ 	{
+ 	  parts->base = NULL_TREE;
+ 	  parts->index = fold_build2 (PLUS_EXPR, ptr_type_node,
+ 				      fold_convert (ptr_type_node, reg),
+ 				      parts->index);
+ 	  return;
+ 	}
+ 
+       /* Replace base by MUL * BASE.  */
+       parts->base = fold_build2 (MULT_EXPR, ptr_type_node,
+ 				 fold_convert (ptr_type_node, reg), mul);
+       return;
+     }
+ 
+   /* Step 1 and free BASE.  */
+   if (integer_onep (mul) && !parts->base)
+     {
+       parts->base = reg;
+       return;
+     }
+ 
+   /* Maybe we can move value from INDEX to BASE, thus enabling us to
+      put REG to index.  */
+   if (parts->index
+       && !parts->step
+       && !parts->base)
+     {
+       parts->base = parts->index;
+       parts->index = NULL_TREE;
+     }
+ 
+   /* Free INDEX.  */
+   if (!parts->index)
+     {
+       parts->index = fold_convert (ptr_type_node, reg);
+       parts->step = mul;
+       return;
+     }
+ 
+   /* Both BASE and INDEX are full, or STEP != 1 and MUL != 1, and
+      BASE and INDEX is different from REG.  Check whether
+      step is the same as MUL.  */
+   if (!integer_onep (mul)
+       && parts->step
+       && operand_equal_p (parts->step, mul, 0))
+     {
+       parts->index = fold_build2 (PLUS_EXPR, ptr_type_node,
+ 				  fold_convert (ptr_type_node, reg),
+ 				  parts->index);
+       return;
+     }
+ 
+   /* Otherwise add MUL * REG to BASE.  */
+   if (integer_onep (mul))
+     tmp = fold_convert (ptr_type_node, reg);
+   else
+     tmp = fold_build2 (MULT_EXPR, ptr_type_node,
+ 		       fold_convert (ptr_type_node, reg), mul);
+ 
+   if (parts->base)
+     tmp = fold_build2 (PLUS_EXPR, ptr_type_node,
+ 		       tmp, parts->base);
+   parts->base = tmp;
+ }
+ 
+ /* Returns true if OBJ is an object whose address is a link time constant.  */
+ 
+ static bool
+ fixed_address_object_p (tree obj)
+ {
+   return (TREE_CODE (obj) == VAR_DECL
+ 	  && (TREE_STATIC (obj)
+ 	      || DECL_EXTERNAL (obj)));
+ }
+ 
+ /* Adds symbol SYM to the address PARTS.  */
+ 
+ static void
+ add_symbol_to_parts (struct mem_address *parts, tree sym)
+ {
+   if (!parts->symbol
+       && fixed_address_object_p (sym))
+     {
+       parts->symbol = sym;
+       return;
+     }
+ 
+   add_reg_to_parts (parts, build_addr (sym),
+ 		    build_int_cst_type (ptr_type_node, 1));
+ }
+ 
+ /* Adds offset OFF to the address PARTS.  */
+ 
+ static void
+ add_offset_to_parts (struct mem_address *parts, tree off)
+ {
+   off = fold_convert (ptr_type_node, off);
+ 
+   if (!parts->offset)
+     parts->offset = off;
+   else
+     parts->offset
+ 	    = fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
+ 				       parts->offset, off);
+ }
+ 
+ /* Sets the address PARTS to sum of addresses P0 and P1.  */
+ 
+ static void
+ add_parts (struct mem_address *p0, struct mem_address *p1,
+ 	   struct mem_address *parts)
+ {
+   *parts = *p0;
+ 
+   if (p1->offset)
+     add_offset_to_parts (parts, p1->offset);
+ 
+   if (p1->index)
+     {
+       tree mul = p1->step;
+ 
+       if (!mul)
+ 	mul = build_int_cst_type (ptr_type_node, 1);
+       add_reg_to_parts (parts, p1->index, mul);
+     }
+ 
+   if (p1->base)
+     add_reg_to_parts (parts, p1->base, build_int_cst_type (ptr_type_node, 1));
+ 
+   if (p1->symbol)
+     add_symbol_to_parts (parts, p1->symbol);
+ }
+ 
+ /* Sets the address PARTs to difference of addresses P0 and P1.  */
+ 
+ static void
+ rem_parts (struct mem_address *p0, struct mem_address *p1,
+ 	   struct mem_address *parts)
+ {
+   tree tmp;
+ 
+   *parts = *p0;
+ 
+   if (p1->offset)
+     {
+       tmp = fold_unary_to_constant (NEGATE_EXPR, ptr_type_node, p1->offset);
+       add_offset_to_parts (parts, tmp);
+     }
+ 
+   if (p1->index)
+     {
+       if (p1->step)
+ 	tmp = fold_unary_to_constant (NEGATE_EXPR, ptr_type_node,
+ 				      p1->step);
+       else
+ 	tmp = build_int_cst_type (ptr_type_node, -1);
+       add_reg_to_parts (parts, p1->index, tmp);
+     }
+ 
+   if (p1->base)
+     add_reg_to_parts (parts, p1->base,
+ 		      build_int_cst_type (ptr_type_node, -1));
+ 
+   if (p1->symbol)
+     {
+       /* if the symbols are equal, cancel them; otherwise,
+ 	 simply subtract its address.  */
+       if (p0->symbol
+ 	  && operand_equal_p (p0->symbol, p1->symbol, 0))
+ 	parts->symbol = NULL_TREE;
+       else
+ 	{
+ 	  add_reg_to_parts (parts,
+ 			    build_addr (p1->symbol),
+ 			    build_int_cst_type (ptr_type_node, -1));
+ 	}
+     }
+ }
+ 
+ /* Sets the address PARTs to MUL times addresses P0.  */
+ 
+ static void
+ mul_parts (struct mem_address *p0,
+ 	   tree mul, struct mem_address *parts)
+ {
+   parts->symbol = NULL_TREE;
+   parts->base = NULL_TREE;
+ 
+   if (p0->offset)
+     parts->offset = fold_binary_to_constant (MULT_EXPR, ptr_type_node, mul,
+ 					     p0->offset);
+   else
+     parts->offset = NULL_TREE;
+ 
+   if (p0->index)
+     {
+       parts->index = p0->index;
+       if (p0->step)
+ 	parts->step = fold_binary_to_constant (MULT_EXPR, ptr_type_node, mul,
+ 					       p0->step);
+       else
+ 	parts->step = mul;
+     }
+   else
+     {
+       parts->index = NULL_TREE;
+       parts->step = NULL_TREE;
+     }
+ 
+   if (p0->base)
+     add_reg_to_parts (parts, p0->base, mul);
+ 
+   if (p0->symbol)
+     add_reg_to_parts (parts, build_addr (p0->symbol), mul);
+ }
+ 
+ /* Splits address ADDR into PARTS.  */
+ 
+ static void
+ addr_to_parts (tree addr, struct mem_address *parts)
+ {
+   tree op0, op1;
+   enum tree_code code;
+   struct mem_address p0, p1;
+ 
+   STRIP_NOPS (addr);
+   code = TREE_CODE (addr);
+ 
+   switch (code)
+     {
+     case SSA_NAME:
+       parts->symbol = NULL_TREE;
+       parts->base = fold_convert (ptr_type_node, addr);
+       parts->index = NULL_TREE;
+       parts->step = NULL_TREE;
+       parts->offset = NULL_TREE;
+       return;
+ 
+     case INTEGER_CST:
+       parts->symbol = NULL_TREE;
+       parts->base = NULL_TREE;
+       parts->index = NULL_TREE;
+       parts->step = NULL_TREE;
+       parts->offset = fold_convert (ptr_type_node, addr);
+       return;
+ 
+     case PLUS_EXPR:
+     case MINUS_EXPR:
+       op0 = TREE_OPERAND (addr, 0);
+       op1 = TREE_OPERAND (addr, 1);
+       addr_to_parts (op0, &p0);
+       addr_to_parts (op1, &p1);
+ 
+       if (code == PLUS_EXPR)
+ 	add_parts (&p0, &p1, parts);
+       else
+ 	rem_parts (&p0, &p1, parts);
+       return;
+ 
+     case MULT_EXPR:
+       op0 = TREE_OPERAND (addr, 0);
+       op1 = TREE_OPERAND (addr, 1);
+ 
+       if (TREE_CODE (op1) != INTEGER_CST)
+ 	break;
+       addr_to_parts (op0, &p0);
+       mul_parts (&p0, op1, parts);
+       return;
+ 
+     case ADDR_EXPR:
+       {
+ 	tree core, off;
+ 	enum machine_mode mode;
+ 	int unsignedp, volatilep;
+ 	HOST_WIDE_INT bitsize, bitoff;
+ 
+ 	core = get_inner_reference (TREE_OPERAND (addr, 0), &bitsize, &bitoff,
+ 				    &off, &mode, &unsignedp, &volatilep,
+ 				    false);
+ 	gcc_assert (bitoff % BITS_PER_UNIT == 0);
+ 
+ 	if (off)
+ 	  addr_to_parts (off, &p0);
+ 	else
+ 	  {
+ 	    p0.symbol = NULL_TREE;
+ 	    p0.base = NULL_TREE;
+ 	    p0.index = NULL_TREE;
+ 	    p0.step = NULL_TREE;
+ 	    p0.offset = NULL_TREE;
+ 	  }
+ 
+ 	if (bitoff)
+ 	  add_offset_to_parts (&p0,
+ 			       build_int_cst_type (ptr_type_node,
+ 						   bitoff / BITS_PER_UNIT));
+ 
+ 	if (TREE_CODE (core) == INDIRECT_REF)
+ 	  {
+ 	    addr_to_parts (TREE_OPERAND (core, 0), &p1);
+ 	    add_parts (&p0, &p1, parts);
+ 	  }
+ 	else
+ 	  {
+ 	    add_symbol_to_parts (&p0, core);
+ 	    *parts = p0;
+ 	  }
+ 	return;
+       }
+ 
+     default:
+       break;
+     }
+ 
+   parts->symbol = NULL_TREE;
+   parts->base = fold_convert (ptr_type_node, addr);
+   parts->index = NULL_TREE;
+   parts->step = NULL_TREE;
+   parts->offset = NULL_TREE;
+   return;
+ }
+ 
+ /* Force the PARTS to register.  */
+ 
+ static void
+ gimplify_mem_ref_parts (block_stmt_iterator *bsi, struct mem_address *parts)
+ {
+   if (parts->base)
+     parts->base = force_gimple_operand_bsi (bsi, parts->base,
+ 					    true, NULL_TREE);
+   if (parts->index)
+     parts->index = force_gimple_operand_bsi (bsi, parts->index,
+ 					     true, NULL_TREE);
+ }
+ 
+ /* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
+    computations are emitted in front of BSI.  TYPE is the mode
+    of created memory reference.  */
+ 
+ tree
+ create_mem_ref (block_stmt_iterator *bsi, tree type, tree addr)
+ {
+   tree mem_ref, tmp;
+   tree addr_type = build_pointer_type (type);
+   struct mem_address parts;
+ 
+   addr_to_parts (addr, &parts);
+   gimplify_mem_ref_parts (bsi, &parts);
+   mem_ref = create_mem_ref_raw (type, &parts);
+   if (mem_ref)
+     return mem_ref;
+ 
+   /* The expression is too complicated.  Try making it simpler.  */
+ 
+   if (parts.step && !integer_onep (parts.step))
+     {
+       /* Move the multiplication to index.  */
+       gcc_assert (parts.index);
+       parts.index = force_gimple_operand_bsi (bsi,
+ 					      build2 (MULT_EXPR, addr_type,
+ 						      parts.index, parts.step),
+ 					      true, NULL_TREE);
+       parts.step = NULL_TREE;
+   
+       mem_ref = create_mem_ref_raw (type, &parts);
+       if (mem_ref)
+ 	return mem_ref;
+     }
+ 
+   if (parts.symbol)
+     {
+       tmp = build_addr (parts.symbol);
+     
+       /* Add the symbol to base, eventually forcing it to register.  */
+       if (parts.base)
+ 	parts.base = force_gimple_operand_bsi (bsi,
+ 					       build2 (PLUS_EXPR, addr_type,
+ 						       parts.base, tmp),
+ 					       true, NULL_TREE);
+       else
+ 	parts.base = tmp;
+       parts.symbol = NULL_TREE;
+ 
+       mem_ref = create_mem_ref_raw (type, &parts);
+       if (mem_ref)
+ 	return mem_ref;
+     }
+ 
+   if (parts.base)
+     {
+       /* Add base to index.  */
+       if (parts.index)
+ 	parts.index = force_gimple_operand_bsi (bsi,
+ 						build2 (PLUS_EXPR, addr_type,
+ 							parts.base,
+ 							parts.index),
+ 						true, NULL_TREE);
+       else
+ 	parts.index = parts.base;
+       parts.base = NULL_TREE;
+ 
+       mem_ref = create_mem_ref_raw (type, &parts);
+       if (mem_ref)
+ 	return mem_ref;
+     }
+ 
+   if (parts.offset && !integer_zerop (parts.offset))
+     {
+       /* Try adding offset to index.  */
+       if (parts.index)
+ 	parts.index = force_gimple_operand_bsi (bsi, 
+ 						build2 (PLUS_EXPR, addr_type,
+ 							parts.index,
+ 							parts.offset),
+ 						true, NULL_TREE);
+       else
+ 	parts.index = parts.offset, bsi;
+ 
+       parts.offset = NULL_TREE;
+ 
+       mem_ref = create_mem_ref_raw (type, &parts);
+       if (mem_ref)
+ 	return mem_ref;
+     }
+ 
+   /* Verify that the address is in the simplest possible shape
+      (only a register).  If we cannot create such a memory reference,
+      something is really wrong.  */
+   gcc_assert (parts.symbol == NULL_TREE);
+   gcc_assert (parts.base == NULL_TREE);
+   gcc_assert (!parts.step || integer_onep (parts.step));
+   gcc_assert (!parts.offset || integer_zerop (parts.offset));
+   gcc_unreachable ();
+ }
+ 
+ /* Copies components of the address from OP to ADDR.  */
+ 
+ void
+ get_address_description (tree op, struct mem_address *addr)
+ {
+   addr->symbol = TMR_SYMBOL (op);
+   addr->base = TMR_BASE (op);
+   addr->index = TMR_INDEX (op);
+   addr->step = TMR_STEP (op);
+   addr->offset = TMR_OFFSET (op);
+ }
+ 
+ /* Copies the additional information attached to target_mem_ref FROM to TO.  */
+ 
+ void
+ copy_mem_ref_info (tree to, tree from)
+ {
+   /* Copy the annotation, to preserve the aliasing information.  */
+   get_tmr_ann (to)->tag = tmr_ann (from)->tag;
+ 
+   /* And the info about the original reference.  */
+   tmr_ann (to)->original = tmr_ann (from)->original;
+ }
+ 
+ /* Move constants in target_mem_ref REF to offset.  Returns the new target
+    mem ref if anything changes, NULL_TREE otherwise.  */
+ 
+ tree
+ maybe_fold_tmr (tree ref)
+ {
+   struct mem_address addr;
+   bool changed = false;
+   tree ret, off;
+ 
+   get_address_description (ref, &addr);
+ 
+   if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
+     {
+       if (addr.offset)
+ 	addr.offset = fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
+ 					       addr.offset, addr.base);
+       else
+ 	addr.offset = addr.base;
+ 
+       addr.base = NULL_TREE;
+       changed = true;
+     }
+ 
+   if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
+     {
+       off = addr.index;
+       if (addr.step)
+ 	{
+ 	  off = fold_binary_to_constant (MULT_EXPR, ptr_type_node,
+ 					 off, addr.step);
+ 	  addr.step = NULL_TREE;
+ 	}
+ 
+       if (addr.offset)
+ 	{
+ 	  addr.offset = fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
+ 						 addr.offset, off);
+ 	}
+       else
+ 	addr.offset = off;
+ 
+       addr.index = NULL_TREE;
+       changed = true;
+     }
+ 
+   if (!changed)
+     return NULL_TREE;
+   
+   ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
+   if (!ret)
+     return NULL_TREE;
+ 
+   copy_mem_ref_info (ret, ref);
+   return ret;
+ }
+ 
+ /* Dump PARTS to FILE.  */
+ 
+ extern void dump_mem_address (FILE *, struct mem_address *);
+ void
+ dump_mem_address (FILE *file, struct mem_address *parts)
+ {
+   if (parts->symbol)
+     {
+       fprintf (file, "symbol: ");
+       print_generic_expr (file, parts->symbol, TDF_SLIM);
+       fprintf (file, "\n");
+     }
+   if (parts->base)
+     {
+       fprintf (file, "base: ");
+       print_generic_expr (file, parts->base, TDF_SLIM);
+       fprintf (file, "\n");
+     }
+   if (parts->index)
+     {
+       fprintf (file, "index: ");
+       print_generic_expr (file, parts->index, TDF_SLIM);
+       fprintf (file, "\n");
+     }
+   if (parts->step)
+     {
+       fprintf (file, "step: ");
+       print_generic_expr (file, parts->step, TDF_SLIM);
+       fprintf (file, "\n");
+     }
+   if (parts->offset)
+     {
+       fprintf (file, "offset: ");
+       print_generic_expr (file, parts->offset, TDF_SLIM);
+       fprintf (file, "\n");
+     }
+ }
+ 
+ #include "gt-tree-ssa-address.h"
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-ccp.c,v
retrieving revision 2.62
diff -c -3 -p -r2.62 tree-ssa-ccp.c
*** tree-ssa-ccp.c	3 Apr 2005 10:27:49 -0000	2.62
--- tree-ssa-ccp.c	4 Apr 2005 11:37:37 -0000
*************** maybe_fold_stmt_addition (tree expr)
*** 1734,1740 ****
    return t;
  }
  
- 
  /* Subroutine of fold_stmt called via walk_tree.  We perform several
     simplifications of EXPR_P, mostly having to do with pointer arithmetic.  */
  
--- 1734,1739 ----
*************** fold_stmt_r (tree *expr_p, int *walk_sub
*** 1808,1813 ****
--- 1807,1816 ----
        }
        break;
  
+     case TARGET_MEM_REF:
+       t = maybe_fold_tmr (expr);
+       break;
+ 
      default:
        return NULL_TREE;
      }
Index: tree-ssa-loop-im.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop-im.c,v
retrieving revision 2.33
diff -c -3 -p -r2.33 tree-ssa-loop-im.c
*** tree-ssa-loop-im.c	31 Mar 2005 16:01:53 -0000	2.33
--- tree-ssa-loop-im.c	4 Apr 2005 11:37:37 -0000
*************** for_each_index (tree *addr_p, bool (*cbc
*** 196,201 ****
--- 196,212 ----
  	case RESULT_DECL:
  	  return true;
  
+ 	case TARGET_MEM_REF:
+ 	  idx = &TMR_BASE (*addr_p);
+ 	  if (*idx
+ 	      && !cbck (*addr_p, idx, data))
+ 	    return false;
+ 	  idx = &TMR_INDEX (*addr_p);
+ 	  if (*idx
+ 	      && !cbck (*addr_p, idx, data))
+ 	    return false;
+ 	  return true;
+ 
  	default:
      	  gcc_unreachable ();
  	}
Index: tree-ssa-loop-ivopts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop-ivopts.c,v
retrieving revision 2.55
diff -c -3 -p -r2.55 tree-ssa-loop-ivopts.c
*** tree-ssa-loop-ivopts.c	3 Apr 2005 10:27:51 -0000	2.55
--- tree-ssa-loop-ivopts.c	4 Apr 2005 11:37:37 -0000
*************** may_be_unaligned_p (tree ref)
*** 1480,1485 ****
--- 1480,1490 ----
    int unsignedp, volatilep;
    unsigned base_align;
  
+   /* TARGET_MEM_REFs are translated directly to valid MEMs on the target,
+      thus they are not missaligned.  */
+   if (TREE_CODE (ref) == TARGET_MEM_REF)
+     return false;
+ 
    /* The test below is basically copy of what expr.c:normal_inner_ref
       does to check whether the object must be loaded by parts when
       STRICT_ALIGNMENT is true.  */
*************** may_be_unaligned_p (tree ref)
*** 1502,1508 ****
  static void
  find_interesting_uses_address (struct ivopts_data *data, tree stmt, tree *op_p)
  {
!   tree base = unshare_expr (*op_p), step = NULL;
    struct iv *civ;
    struct ifs_ivopts_data ifs_ivopts_data;
  
--- 1507,1513 ----
  static void
  find_interesting_uses_address (struct ivopts_data *data, tree stmt, tree *op_p)
  {
!   tree base = *op_p, step = NULL;
    struct iv *civ;
    struct ifs_ivopts_data ifs_ivopts_data;
  
*************** find_interesting_uses_address (struct iv
*** 1516,1535 ****
        && may_be_unaligned_p (base))
      goto fail;
  
!   ifs_ivopts_data.ivopts_data = data;
!   ifs_ivopts_data.stmt = stmt;
!   ifs_ivopts_data.step_p = &step;
!   if (!for_each_index (&base, idx_find_step, &ifs_ivopts_data)
!       || zero_p (step))
!     goto fail;
  
!   gcc_assert (TREE_CODE (base) != ALIGN_INDIRECT_REF);
!   gcc_assert (TREE_CODE (base) != MISALIGNED_INDIRECT_REF);
  
!   if (TREE_CODE (base) == INDIRECT_REF)
!     base = TREE_OPERAND (base, 0);
    else
!     base = build_addr (base);
  
    civ = alloc_iv (base, step);
    record_use (data, op_p, civ, stmt, USE_ADDRESS);
--- 1521,1587 ----
        && may_be_unaligned_p (base))
      goto fail;
  
!   base = unshare_expr (base);
! 
!   if (TREE_CODE (base) == TARGET_MEM_REF)
!     {
!       tree type = build_pointer_type (TREE_TYPE (base));
!       tree astep;
! 
!       if (TMR_BASE (base)
! 	  && TREE_CODE (TMR_BASE (base)) == SSA_NAME)
! 	{
! 	  civ = get_iv (data, TMR_BASE (base));
! 	  if (!civ)
! 	    goto fail;
! 
! 	  TMR_BASE (base) = civ->base;
! 	  step = civ->step;
! 	}
!       if (TMR_INDEX (base)
! 	  && TREE_CODE (TMR_INDEX (base)) == SSA_NAME)
! 	{
! 	  civ = get_iv (data, TMR_INDEX (base));
! 	  if (!civ)
! 	    goto fail;
  
! 	  TMR_INDEX (base) = civ->base;
! 	  astep = civ->step;
  
! 	  if (astep)
! 	    {
! 	      if (TMR_STEP (base))
! 		astep = fold (build2 (MULT_EXPR, type, TMR_STEP (base),
! 				      astep));
! 
! 	      if (step)
! 		step = fold (build2 (PLUS_EXPR, type, step, astep));
! 	      else
! 		step = astep;
! 	    }
! 	}
! 
!       if (zero_p (step))
! 	goto fail;
!       base = tree_mem_ref_addr (type, base);
!     }
    else
!     {
!       ifs_ivopts_data.ivopts_data = data;
!       ifs_ivopts_data.stmt = stmt;
!       ifs_ivopts_data.step_p = &step;
!       if (!for_each_index (&base, idx_find_step, &ifs_ivopts_data)
! 	  || zero_p (step))
! 	goto fail;
! 
!       gcc_assert (TREE_CODE (base) != ALIGN_INDIRECT_REF);
!       gcc_assert (TREE_CODE (base) != MISALIGNED_INDIRECT_REF);
! 
!       if (TREE_CODE (base) == INDIRECT_REF)
! 	base = TREE_OPERAND (base, 0);
!       else
! 	base = build_addr (base);
!     }
  
    civ = alloc_iv (base, step);
    record_use (data, op_p, civ, stmt, USE_ADDRESS);
*************** unshare_and_remove_ssa_names (tree ref)
*** 4782,4852 ****
    return ref;
  }
  
! /* Rewrites base of memory access OP with expression WITH in statement
!    pointed to by BSI.  */
  
! static void
! rewrite_address_base (block_stmt_iterator *bsi, tree *op, tree with)
  {
!   tree bvar, var, new_var, new_name, copy, name;
!   tree orig;
  
!   var = bvar = get_base_address (*op);
! 
!   if (!var || TREE_CODE (with) != SSA_NAME)
!     goto do_rewrite;
  
-   gcc_assert (TREE_CODE (var) != ALIGN_INDIRECT_REF);
-   gcc_assert (TREE_CODE (var) != MISALIGNED_INDIRECT_REF);
    if (TREE_CODE (var) == INDIRECT_REF)
      var = TREE_OPERAND (var, 0);
    if (TREE_CODE (var) == SSA_NAME)
      {
!       name = var;
        var = SSA_NAME_VAR (var);
      }
!   else if (DECL_P (var))
!     name = NULL_TREE;
!   else
!     goto do_rewrite;
!     
!   if (var_ann (var)->type_mem_tag)
!     var = var_ann (var)->type_mem_tag;
! 
!   /* We need to add a memory tag for the variable.  But we do not want
!      to add it to the temporary used for the computations, since this leads
!      to problems in redundancy elimination when there are common parts
!      in two computations referring to the different arrays.  So we copy
!      the variable to a new temporary.  */
!   copy = build2 (MODIFY_EXPR, void_type_node, NULL_TREE, with);
!   if (name)
!     new_name = duplicate_ssa_name (name, copy);
!   else
      {
!       new_var = create_tmp_var (TREE_TYPE (with), "ruatmp");
!       add_referenced_tmp_var (new_var);
!       var_ann (new_var)->type_mem_tag = var;
!       new_name = make_ssa_name (new_var, copy);
!     }
!   TREE_OPERAND (copy, 0) = new_name;
!   bsi_insert_before (bsi, copy, BSI_SAME_STMT);
!   with = new_name;
! 
! do_rewrite:
! 
!   orig = NULL_TREE;
!   gcc_assert (TREE_CODE (*op) != ALIGN_INDIRECT_REF);
!   gcc_assert (TREE_CODE (*op) != MISALIGNED_INDIRECT_REF);
! 
!   if (TREE_CODE (*op) == INDIRECT_REF)
!     orig = REF_ORIGINAL (*op);
!   if (!orig)
!     orig = unshare_and_remove_ssa_names (*op);
  
!   *op = build1 (INDIRECT_REF, TREE_TYPE (*op), with);
  
!   /* Record the original reference, for purposes of alias analysis.  */
!   REF_ORIGINAL (*op) = orig;
  }
  
  /* Rewrites USE (address that is an iv) using candidate CAND.  */
--- 4834,4893 ----
    return ref;
  }
  
! /* Extract the alias analysis info for the memory reference REF.  There are
!    several ways how this information may be stored and what precisely is
!    its semantics depending on the type of the reference, but there always is
!    somewhere hidden one _DECL node that is used to determine the set of
!    virtual operands for the reference.  The code below deciphers this jungle
!    and extracts this single useful piece of information.  */
  
! static tree
! get_ref_tag (tree ref)
  {
!   tree var = get_base_address (ref);
!   tree tag;
  
!   if (!var)
!     return NULL_TREE;
  
    if (TREE_CODE (var) == INDIRECT_REF)
      var = TREE_OPERAND (var, 0);
    if (TREE_CODE (var) == SSA_NAME)
      {
!       if (SSA_NAME_PTR_INFO (var))
! 	{
! 	  tag = SSA_NAME_PTR_INFO (var)->name_mem_tag;
! 	  if (tag)
! 	    return tag;
! 	}
!  
        var = SSA_NAME_VAR (var);
      }
!  
!   if (DECL_P (var))
      {
!       tag = var_ann (var)->type_mem_tag;
!       if (tag)
! 	return tag;
  
!       return var;
!     }
  
!   return NULL_TREE;
! }
! 
! /* Copies the reference information from OLD_REF to NEW_REF.  */
! 
! static void
! copy_ref_info (tree new_ref, tree old_ref)
! {
!   if (TREE_CODE (old_ref) == TARGET_MEM_REF)
!     new_ref->common.ann = tree_ann (old_ref);
!   else
!     {
!       get_tmr_ann (new_ref)->tag = get_ref_tag (old_ref);
!       tmr_ann (new_ref)->original = unshare_and_remove_ssa_names (old_ref);
!     }
  }
  
  /* Rewrites USE (address that is an iv) using candidate CAND.  */
*************** static void
*** 4855,4870 ****
  rewrite_use_address (struct ivopts_data *data,
  		     struct iv_use *use, struct iv_cand *cand)
  {
    tree comp = unshare_expr (get_computation (data->current_loop,
  					     use, cand));
    block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
!   tree stmts;
!   tree op = force_gimple_operand (comp, &stmts, true, NULL_TREE);
! 
!   if (stmts)
!     bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
  
!   rewrite_address_base (&bsi, use->op_p, op);
  }
  
  /* Rewrites USE (the condition such that one of the arguments is an iv) using
--- 4896,4909 ----
  rewrite_use_address (struct ivopts_data *data,
  		     struct iv_use *use, struct iv_cand *cand)
  {
+   /* TODO -- produce TARGET_MEM_REF directly.  */
    tree comp = unshare_expr (get_computation (data->current_loop,
  					     use, cand));
    block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
!   tree ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), comp);
  
!   copy_ref_info (ref, *use->op_p);
!   *use->op_p = ref;
  }
  
  /* Rewrites USE (the condition such that one of the arguments is an iv) using
Index: tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 2.70
diff -c -3 -p -r2.70 tree-ssa-operands.c
*** tree-ssa-operands.c	30 Mar 2005 22:10:47 -0000	2.70
--- tree-ssa-operands.c	4 Apr 2005 11:37:37 -0000
*************** static void note_addressable (tree, stmt
*** 135,140 ****
--- 135,141 ----
  static void get_expr_operands (tree, tree *, int);
  static void get_asm_expr_operands (tree);
  static void get_indirect_ref_operands (tree, tree, int);
+ static void get_tmr_operands (tree, tree, int);
  static void get_call_expr_operands (tree, tree);
  static inline void append_def (tree *);
  static inline void append_use (tree *);
*************** get_expr_operands (tree stmt, tree *expr
*** 1099,1104 ****
--- 1100,1109 ----
        get_indirect_ref_operands (stmt, expr, flags);
        return;
  
+     case TARGET_MEM_REF:
+       get_tmr_operands (stmt, expr, flags);
+       return;
+ 
      case ARRAY_REF:
      case ARRAY_RANGE_REF:
        /* Treat array references as references to the virtual variable
*************** get_indirect_ref_operands (tree stmt, tr
*** 1479,1484 ****
--- 1484,1513 ----
    get_expr_operands (stmt, pptr, opf_none);
  }
  
+ /* A subroutine of get_expr_operands to handle TARGET_MEM_REF.  */
+ 
+ static void
+ get_tmr_operands (tree stmt, tree expr, int flags)
+ {
+   tmr_ann_t ann = tmr_ann (expr);
+ 
+   /* First record the real operands.  */
+   get_expr_operands (stmt, &TMR_BASE (expr), opf_none);
+   get_expr_operands (stmt, &TMR_INDEX (expr), opf_none);
+ 
+   /* MEM_REFs should never be killing.  */
+   flags &= ~opf_kill_def;
+ 
+   if (TMR_SYMBOL (expr))
+     note_addressable (TMR_SYMBOL (expr), stmt_ann (stmt));
+ 
+   if (ann->tag)
+     add_stmt_operand (&ann->tag, stmt_ann (stmt), flags);
+   else
+     /* Something weird, so ensure we will be careful.  */
+     stmt_ann (stmt)->has_volatile_ops = true;
+ }
+ 
  /* A subroutine of get_expr_operands to handle CALL_EXPR.  */
  
  static void
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.472
diff -c -3 -p -r1.472 tree.c
*** tree.c	30 Mar 2005 21:34:29 -0000	1.472
--- tree.c	4 Apr 2005 11:37:37 -0000
*************** copy_node_stat (tree node MEM_STAT_DECL)
*** 441,446 ****
--- 441,449 ----
    TREE_VISITED (t) = 0;
    t->common.ann = 0;
  
+   if (code == TARGET_MEM_REF)
+     copy_mem_ref_info (t, node);
+ 
    if (TREE_CODE_CLASS (code) == tcc_declaration)
      DECL_UID (t) = next_decl_uid++;
    else if (TREE_CODE_CLASS (code) == tcc_type)
*************** build4_stat (enum tree_code code, tree t
*** 2704,2715 ****
    return t;
  }
  
  /* Backup definition for non-gcc build compilers.  */
  
  tree
  (build) (enum tree_code code, tree tt, ...)
  {
!   tree t, arg0, arg1, arg2, arg3;
    int length = TREE_CODE_LENGTH (code);
    va_list p;
  
--- 2707,2748 ----
    return t;
  }
  
+ tree
+ build5_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
+ 	     tree arg2, tree arg3, tree arg4 MEM_STAT_DECL)
+ {
+   bool constant, read_only, side_effects, invariant;
+   tree t;
+ 
+   gcc_assert (TREE_CODE_LENGTH (code) == 5);
+ 
+   t = make_node_stat (code PASS_MEM_STAT);
+   TREE_TYPE (t) = tt;
+ 
+   side_effects = TREE_SIDE_EFFECTS (t);
+ 
+   PROCESS_ARG(0);
+   PROCESS_ARG(1);
+   PROCESS_ARG(2);
+   PROCESS_ARG(3);
+   PROCESS_ARG(4);
+ 
+   TREE_SIDE_EFFECTS (t) = side_effects;
+ 
+   TREE_THIS_VOLATILE (t)
+     = (code != TARGET_MEM_REF
+        && TREE_CODE_CLASS (code) == tcc_reference
+        && arg0 && TREE_THIS_VOLATILE (arg0));
+ 
+   return t;
+ }
+ 
  /* Backup definition for non-gcc build compilers.  */
  
  tree
  (build) (enum tree_code code, tree tt, ...)
  {
!   tree t, arg0, arg1, arg2, arg3, arg4;
    int length = TREE_CODE_LENGTH (code);
    va_list p;
  
*************** tree
*** 2741,2746 ****
--- 2774,2787 ----
        arg3 = va_arg (p, tree);
        t = build4 (code, tt, arg0, arg1, arg2, arg3);
        break;
+     case 5:
+       arg0 = va_arg (p, tree);
+       arg1 = va_arg (p, tree);
+       arg2 = va_arg (p, tree);
+       arg3 = va_arg (p, tree);
+       arg4 = va_arg (p, tree);
+       t = build5 (code, tt, arg0, arg1, arg2, arg3, arg4);
+       break;
      default:
        gcc_unreachable ();
      }
Index: tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.114
diff -c -3 -p -r1.114 tree.def
*** tree.def	30 Mar 2005 21:34:31 -0000	1.114
--- tree.def	4 Apr 2005 11:37:37 -0000
*************** DEFTREECODE (WITH_SIZE_EXPR, "with_size_
*** 921,926 ****
--- 921,934 ----
     generated by the builtin targetm.vectorize.mask_for_load_builtin_decl.  */
  DEFTREECODE (REALIGN_LOAD_EXPR, "realign_load", tcc_expression, 3)
  
+ /* Low-level memory addressing.  Operands are SYMBOL (static or global
+    variable), BASE (register), INDEX (register), STEP (integer constant),
+    OFFSET (integer constant).  Corresponding address is
+    SYMBOL + BASE + STEP * INDEX + OFFSET.  Only variations and values valid on
+    the target are allowed.  */
+ 
+ DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 5)
+ 
  /*
  Local variables:
  mode:c
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.709
diff -c -3 -p -r1.709 tree.h
*** tree.h	29 Mar 2005 16:10:02 -0000	1.709
--- tree.h	4 Apr 2005 11:37:38 -0000
*************** struct tree_vec GTY(())
*** 1177,1186 ****
  #define TREE_OPERAND(NODE, I) TREE_OPERAND_CHECK (NODE, I)
  #define TREE_COMPLEXITY(NODE) (EXPR_CHECK (NODE)->exp.complexity)
  
- /* In INDIRECT_REF, ALIGN_INDIRECT_REF, MISALIGNED_INDIRECT_REF.  */
- #define REF_ORIGINAL(NODE) TREE_CHAIN (TREE_CHECK3 (NODE, 	\
- 	INDIRECT_REF, ALIGN_INDIRECT_REF, MISALIGNED_INDIRECT_REF))
- 
  /* In a LOOP_EXPR node.  */
  #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
  
--- 1177,1182 ----
*************** struct tree_vec GTY(())
*** 1246,1251 ****
--- 1242,1254 ----
  #define CASE_HIGH(NODE)         	TREE_OPERAND (CASE_LABEL_EXPR_CHECK (NODE), 1)
  #define CASE_LABEL(NODE)		TREE_OPERAND (CASE_LABEL_EXPR_CHECK (NODE), 2)
  
+ /* The operands of a TARGET_MEM_REF.  */
+ #define TMR_SYMBOL(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 0))
+ #define TMR_BASE(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 1))
+ #define TMR_INDEX(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 2))
+ #define TMR_STEP(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 3))
+ #define TMR_OFFSET(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 4))
+ 
  /* The operands of a BIND_EXPR.  */
  #define BIND_EXPR_VARS(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 0))
  #define BIND_EXPR_BODY(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 1))
*************** extern tree build3_stat (enum tree_code,
*** 2869,2874 ****
--- 2872,2880 ----
  extern tree build4_stat (enum tree_code, tree, tree, tree, tree,
  			 tree MEM_STAT_DECL);
  #define build4(c,t1,t2,t3,t4,t5) build4_stat (c,t1,t2,t3,t4,t5 MEM_STAT_INFO)
+ extern tree build5_stat (enum tree_code, tree, tree, tree, tree, tree,
+ 			 tree MEM_STAT_DECL);
+ #define build5(c,t1,t2,t3,t4,t5,t6) build5_stat (c,t1,t2,t3,t4,t5,t6 MEM_STAT_INFO)
  
  extern tree build_int_cst (tree, HOST_WIDE_INT);
  extern tree build_int_cst_type (tree, HOST_WIDE_INT);
*************** extern tree get_base_address (tree t);
*** 3953,3956 ****
--- 3959,3966 ----
  /* In tree-vectorizer.c.  */
  extern void vect_set_verbosity_level (const char *);
  
+ /* In tree-ssa-address.c.  */
+ extern tree tree_mem_ref_addr (tree, tree);
+ extern void copy_mem_ref_info (tree, tree);
+ 
  #endif  /* GCC_TREE_H  */
Index: doc/c-tree.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/c-tree.texi,v
retrieving revision 1.72
diff -c -3 -p -r1.72 c-tree.texi
*** doc/c-tree.texi	5 Mar 2005 19:56:27 -0000	1.72
--- doc/c-tree.texi	4 Apr 2005 11:37:41 -0000
*************** This macro returns the attributes on the
*** 1712,1717 ****
--- 1712,1718 ----
  @tindex EXACT_DIV_EXPR
  @tindex ARRAY_REF
  @tindex ARRAY_RANGE_REF
+ @tindex TARGET_MEM_REF
  @tindex LT_EXPR
  @tindex LE_EXPR
  @tindex GT_EXPR
*************** meanings.  The type of these expressions
*** 2103,2108 ****
--- 2104,2125 ----
  type is the same as that of the first operand.  The range of that array
  type determines the amount of data these expressions access.
  
+ @item TARGET_MEM_REF
+ These nodes represent memory accesses whose address directly map to
+ an addressing mode of the target architecture.  The first argument
+ is @code{TMR_SYMBOL} and must be a @code{VAR_DECL} of an object with
+ a fixed address.  The second argument is @code{TMR_BASE} and the
+ third one is @code{TMR_INDEX}.  The fourth argument is
+ @code{TMR_STEP} and must be an @code{INTEGER_CST}.  The fifth
+ argument is @code{TMR_OFFSET} and must be an @code{INTEGER_CST}.
+ Any of the arguments may be NULL if the appropriate component
+ does not appear in the address.  Address of the @code{TARGET_MEM_REF}
+ is determined in the following way.
+ 
+ @smallexample
+ &TMR_SYMBOL + TMR_BASE + TMR_INDEX * TMR_STEP + TMR_OFFSET
+ @end smallexample
+ 
  @item LT_EXPR
  @itemx LE_EXPR
  @itemx GT_EXPR
Index: doc/tree-ssa.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tree-ssa.texi,v
retrieving revision 1.19
diff -c -3 -p -r1.19 tree-ssa.texi
*** doc/tree-ssa.texi	31 Mar 2005 17:13:31 -0000	1.19
--- doc/tree-ssa.texi	4 Apr 2005 11:37:42 -0000
*************** void f()
*** 633,638 ****
--- 633,644 ----
                          op2 -> var
  
     compref      : inner-compref
+                 | TARGET_MEM_REF
+                         op0 -> ID
+                         op1 -> val
+                         op2 -> val
+                         op3 -> CONST
+                         op4 -> CONST
                  | REALPART_EXPR
                          op0 -> inner-compref
                  | IMAGPART_EXPR



More information about the Gcc-patches mailing list