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] TARGET_MEM_REF, version 3


Hello,

> > > > ! /* 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)
> > > 
> > > I have no clue whether or not this is correct.  You'll have to get a
> > > ruling from Diego on this.
> > 
> This looks fine to me, but it should be moved into
> tree-ssa-alias.c.  It's not so much a "jungle" as it needs to
> be aware of the two levels of aliasing information we have for
> pointers.  Given a pointer P_i, if P_i has flow-sensitive
> aliasing information, it will have a name tag.  If not,
> flow-insensitive information is associated to the base symbol 'P'
> in the form of a type tag.  If the base address is a non-pointer,
> then it uses the object itself as the tag.
> 
> If this creates issues with alias analysis we should fix the
> aliaser.  I'm already on the hook for addressing the call to
> add_type_alias in the vectorizer.
> 
> Zdenek, let me know of any aliasing problems you find with
> TARGET_MEM_REF.

None except for the bugs in vectorizer (not related to ivopts -- the
problems are revealed already directly after the vectorizer with the
patch to check that operands of the statements are up-to-date,
http://gcc.gnu.org/ml/gcc-patches/2005-04/msg01810.html).

> On Wed, Apr 13, 2005 at 01:22:21AM +0200, Zdenek Dvorak wrote:
> 
> > Moreorless for consistency; the annotations contain the tag for virtual
> > operands for the TARGET_MEM_REF, and such information is stored in
> > the annotations for all other memory reference types.  Also, neither
> > the tag nor the original reference look like "expression operand" to
> > me.  Of course, if you prefer I will turn them into operands of
> > the TARGET_MEM_REF.
> > 
> That would be my preference as well.  No need to create
> annotations for permanent attributes.

Done.

I have made a few other changes:
-- simplified the generation of TARGET_MEM_REFs using the affine decompositions
   now used by ivopts
-- added a testcase where we produce suboptimal code without the TARGET_MEM_REFs
-- updated outcomes of testcases in the testsuite that used to pass by luck only.

Bootstrapped & regtested on x86_64 and ppc.  Just for sure, I have also
rerun the spec benchmarks on i686; the outcome is still more or less neutral
(minor improvement on specint, minor loss on specfp, no significant
improvements or regressions on any single test).

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.
	* tree-eh.c (tree_could_trap_p): Handle TARGET_MEM_REFs.
	* tree-flow.h (struct mem_address): New.
	(struct affine_tree_combination): Moved from tree-ssa-loop-ivopts.c.
	(create_mem_ref, addr_for_mem_ref, get_address_description,
	maybe_fold_tmr, multiplier_allowed_in_address_p,
	multiply_by_cost):  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, build_addr_strip_iref): Removed.
	(struct affine_tree_combination): Moved to tree-flow.h.
	(get_ref_tag, copy_ref_info): New functions.
	(rewrite_use_address): Produce TARGET_MEM_REFs.
	(tree_ssa_iv_optimize): Do not call update_ssa
	and rewrite_into_loop_closed_ssa.
	(tree_to_aff_combination): Use build_fold_addr_expr instead of
	build_addr_strip_iref.
	(unshare_aff_combination): New function.
	(fold_affine_sum): Removed.
	(get_computation_at): Use get_computation_aff.  Unshare the result.
	(get_computation_aff, multiplier_allowed_in_address_p): New function.
	(multiply_by_cost): Exported.
	(get_address_cost): Use multiplier_allowed_in_address_p.
	* 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 7 arguments.
	(build7_stat): New function.
	* tree.def (TARGET_MEM_DEF): New.
	* tree.h (REF_ORIGINAL): Removed.
	(TMR_SYMBOL, TMR_BASE, TMR_INDEX, TMR_STEP, TMR_OFFSET, TMR_ORIGINAL,
	TMR_TAG, build7): New macros.
	(build7_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.

	* gcc.dg/tree-ssa/loop-2.c: Update outcome.
	* gcc.dg/tree-ssa/loop-3.c: Update outcome.
	* gcc.dg/tree-ssa/loop-4.c: Update outcome.
	* gcc.dg/tree-ssa/loop-9.c: New test.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1476
diff -c -3 -p -r1.1476 Makefile.in
*** Makefile.in	23 Apr 2005 00:59:19 -0000	1.1476
--- Makefile.in	1 May 2005 20:27:20 -0000
*************** C_OBJS = c-lang.o stub-objc.o $(C_AND_OB
*** 923,938 ****
  OBJS-common = \
   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-uncprop.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-dom.o domwalk.o tree-tailcall.o gimple-low.o tree-iterator.o	   \
   tree-phinodes.o tree-ssanames.o tree-sra.o tree-complex.o tree-ssa-loop.o \
   tree-ssa-loop-niter.o tree-ssa-loop-manip.o tree-ssa-threadupdate.o	   \
   tree-vectorizer.o tree-vect-analyze.o tree-vect-transform.o		   \
!  tree-ssa-loop-ivcanon.o tree-ssa-propagate.o	 	   		   \
   tree-ssa-loop-ivopts.o tree-if-conv.o tree-ssa-loop-unswitch.o		   \
   alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o	  	   \
   cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o		   \
--- 923,938 ----
  OBJS-common = \
   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-uncprop.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-dom.o domwalk.o tree-tailcall.o gimple-low.o tree-iterator.o	   \
   tree-phinodes.o tree-ssanames.o tree-sra.o tree-complex.o tree-ssa-loop.o \
   tree-ssa-loop-niter.o tree-ssa-loop-manip.o tree-ssa-threadupdate.o	   \
   tree-vectorizer.o tree-vect-analyze.o tree-vect-transform.o		   \
!  tree-ssa-loop-ivcanon.o tree-ssa-propagate.o tree-ssa-address.o	   \
   tree-ssa-loop-ivopts.o tree-if-conv.o tree-ssa-loop-unswitch.o		   \
   alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o	  	   \
   cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o		   \
*************** tree-ssa-loop.o : tree-ssa-loop.c $(TREE
*** 1740,1745 ****
--- 1740,1750 ----
     $(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
*** 2477,2483 ****
    $(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 \
--- 2482,2488 ----
    $(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
*** 2501,2507 ****
  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-profile.h \
  gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \
  gt-tree-phinodes.h gt-tree-nested.h \
  gt-tree-ssa-operands.h gt-tree-ssa-propagate.h \
--- 2506,2512 ----
  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-profile.h gt-tree-ssa-address.h \
  gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \
  gt-tree-phinodes.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.788
diff -c -3 -p -r1.788 expr.c
*** expr.c	28 Apr 2005 05:03:03 -0000	1.788
--- expr.c	1 May 2005 20:27:20 -0000
*************** expand_expr_real_1 (tree exp, rtx target
*** 6847,6853 ****
      case INDIRECT_REF:
        {
  	tree exp1 = TREE_OPERAND (exp, 0);
- 	tree orig;
  
  	if (modifier != EXPAND_WRITE)
  	  {
--- 6847,6852 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 6870,6879 ****
  
  	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.  */
--- 6869,6875 ----
  
  	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
*** 6905,6910 ****
--- 6901,6918 ----
  	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_ORIGINAL (exp), 0);
+       }
+       return temp;
+ 
      case ARRAY_REF:
  
        {
Index: tree-eh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-eh.c,v
retrieving revision 2.33
diff -c -3 -p -r2.33 tree-eh.c
*** tree-eh.c	25 Apr 2005 17:24:28 -0000	2.33
--- tree-eh.c	1 May 2005 20:27:20 -0000
*************** tree_could_trap_p (tree expr)
*** 1871,1876 ****
--- 1871,1883 ----
   restart:
    switch (code)
      {
+     case TARGET_MEM_REF:
+       /* For TARGET_MEM_REFs use the information based on the original
+ 	 reference.  */
+       expr = TMR_ORIGINAL (expr);
+       code = TREE_CODE (expr);
+       goto restart;
+ 
      case COMPONENT_REF:
      case REALPART_EXPR:
      case IMAGPART_EXPR:
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 2.99
diff -c -3 -p -r2.99 tree-flow.h
*** tree-flow.h	27 Apr 2005 15:58:46 -0000	2.99
--- tree-flow.h	1 May 2005 20:27:20 -0000
*************** void insert_edge_copies (tree, basic_blo
*** 782,793 ****
  extern void linear_transform_loops (struct loops *);
  
  /* In tree-ssa-loop-ivopts.c  */
! extern bool expr_invariant_in_loop_p (struct loop *, tree);
  
  /* In gimplify.c  */
  tree force_gimple_operand (tree, tree *, bool, tree);
  tree force_gimple_operand_bsi (block_stmt_iterator *, tree, bool, tree);
  
  #include "tree-flow-inline.h"
  
  #endif /* _TREE_FLOW_H  */
--- 782,837 ----
  extern void linear_transform_loops (struct loops *);
  
  /* In tree-ssa-loop-ivopts.c  */
! bool expr_invariant_in_loop_p (struct loop *, tree);
! bool multiplier_allowed_in_address_p (HOST_WIDE_INT);
! unsigned multiply_by_cost (HOST_WIDE_INT, enum machine_mode);
  
  /* In gimplify.c  */
  tree force_gimple_operand (tree, tree *, bool, tree);
  tree force_gimple_operand_bsi (block_stmt_iterator *, tree, bool, tree);
  
+ /* In tree-ssa-address.c  */
+ 
+ /* Affine combination of trees.  We keep track of at most MAX_AFF_ELTS elements
+    to make things simpler; this is sufficient in most cases.  */
+ 
+ #define MAX_AFF_ELTS 8
+ 
+ struct affine_tree_combination
+ {
+   /* Type of the result of the combination.  */
+   tree type;
+ 
+   /* Mask modulo that the operations are performed.  */
+   unsigned HOST_WIDE_INT mask;
+ 
+   /* Constant offset.  */
+   unsigned HOST_WIDE_INT offset;
+ 
+   /* Number of elements of the combination.  */
+   unsigned n;
+ 
+   /* Elements and their coefficients.  */
+   tree elts[MAX_AFF_ELTS];
+   unsigned HOST_WIDE_INT coefs[MAX_AFF_ELTS];
+ 
+   /* Remainder of the expression.  */
+   tree rest;
+ };
+ 
+ /* Description of a memory address.  */
+ 
+ struct mem_address
+ {
+   tree symbol, base, index, step, offset;
+ };
+ 
+ tree create_mem_ref (block_stmt_iterator *, tree, 
+ 		     struct affine_tree_combination *);
+ 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.38
diff -c -3 -p -r2.38 tree-mudflap.c
*** tree-mudflap.c	23 Apr 2005 21:27:59 -0000	2.38
--- tree-mudflap.c	1 May 2005 20:27:20 -0000
*************** mf_xform_derefs_1 (block_stmt_iterator *
*** 838,843 ****
--- 838,851 ----
                             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 (0, "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.57
diff -c -3 -p -r2.57 tree-pretty-print.c
*** tree-pretty-print.c	11 Apr 2005 15:05:30 -0000	2.57
--- tree-pretty-print.c	1 May 2005 20:27:20 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 444,449 ****
--- 444,507 ----
        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_ORIGINAL (node), 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	1 May 2005 20:27:20 -0000
***************
*** 0 ****
--- 1,705 ----
+ /* 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"
+ 
+ /* TODO -- handling of symbols (according to Richard Hendersons
+    comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
+    
+    There are at least 5 different kinds of symbols that we can run up against:
+ 
+      (1) binds_local_p, small data area.
+      (2) binds_local_p, eg local statics
+      (3) !binds_local_p, eg global variables
+      (4) thread local, local_exec
+      (5) thread local, !local_exec
+ 
+    Now, (1) won't appear often in an array context, but it certainly can.
+    All you have to do is set -GN high enough, or explicitly mark any
+    random object __attribute__((section (".sdata"))).
+ 
+    All of these affect whether or not a symbol is in fact a valid address.
+    The only one tested here is (3).  And that result may very well
+    be incorrect for (4) or (5).
+ 
+    An incorrect result here does not cause incorrect results out the
+    back end, because the expander in expr.c validizes the address.  However
+    it would be nice to improve the handling here in order to produce more
+    precise results.  */
+ 
+ /* 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))
+ 
+ /* 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_MULT (Pmode, act_elem, step);
+ 
+ 	  if (step_p)
+ 	    *step_p = &XEXP (act_elem, 1);
+ 	}
+ 
+       *addr = act_elem;
+     }
+ 
+   if (base)
+     {
+       if (*addr)
+ 	*addr = gen_rtx_PLUS (Pmode, *addr, base);
+       else
+ 	*addr = base;
+     }
+ 
+   if (symbol)
+     {
+       act_elem = symbol;
+       if (offset)
+ 	{
+ 	  act_elem = gen_rtx_CONST (Pmode,
+ 				    gen_rtx_PLUS (Pmode, act_elem, offset));
+ 	  if (offset_p)
+ 	    *offset_p = &XEXP (XEXP (act_elem, 0), 1);
+ 	}
+ 
+       if (*addr)
+ 	*addr = gen_rtx_PLUS (Pmode, *addr, act_elem);
+       else
+ 	*addr = act_elem;
+     }
+   else if (offset)
+     {
+       if (*addr)
+ 	{
+ 	  *addr = gen_rtx_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 build7 (TARGET_MEM_REF, type,
+ 		 addr->symbol, addr->base, addr->index,
+ 		 addr->step, addr->offset, NULL, NULL);
+ }
+ 
+ /* 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 COEF * ELT to PARTS.  TYPE is the type of the address we
+    construct.  */
+ 
+ static void
+ add_to_parts (struct mem_address *parts, tree type, tree elt,
+ 	      unsigned HOST_WIDE_INT coef)
+ {
+   /* Check if this is a symbol.  */
+   if (!parts->symbol
+       && coef == 1
+       && TREE_CODE (elt) == ADDR_EXPR
+       && fixed_address_object_p (TREE_OPERAND (elt, 0)))
+     {
+       parts->symbol = TREE_OPERAND (elt, 0);
+       return;
+     }
+ 
+   if (coef != 1)
+     elt = fold_build2 (MULT_EXPR, type, fold_convert (type, elt),
+ 		       build_int_cst_type (type, coef));
+   else
+     elt = fold_convert (type, elt);
+ 
+   if (!parts->base)
+     {
+       parts->base = elt;
+       return;
+     }
+ 
+   if (!parts->index)
+     {
+       parts->index = elt;
+       return;
+     }
+ 
+   /* Add ELT to base.  */
+   parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
+ }
+ 
+ /* Finds the most expensive multiplication in ADDR that can be
+    expressed in an addressing mode and move the corresponding
+    element(s) to PARTS.  TYPE is the type of the address we
+    construct.  */
+ 
+ static void
+ most_expensive_mult_to_index (struct mem_address *parts, tree type,
+ 			      struct affine_tree_combination *addr)
+ {
+   unsigned HOST_WIDE_INT best_mult = 0;
+   unsigned best_mult_cost = 0, acost;
+   tree mult_elt = NULL_TREE, elt;
+   unsigned i, j;
+ 
+   for (i = 0; i < addr->n; i++)
+     {
+       if (addr->coefs[i] == 1
+ 	  || !multiplier_allowed_in_address_p (addr->coefs[i]))
+ 	continue;
+       
+       acost = multiply_by_cost (addr->coefs[i], Pmode);
+ 
+       if (acost > best_mult_cost)
+ 	{
+ 	  best_mult_cost = acost;
+ 	  best_mult = addr->coefs[i];
+ 	}
+     }
+ 
+   if (!best_mult)
+     return;
+ 
+   for (i = j = 0; i < addr->n; i++)
+     {
+       if (addr->coefs[i] != best_mult)
+ 	{
+ 	  addr->coefs[j] = addr->coefs[i];
+ 	  addr->elts[j] = addr->elts[i];
+ 	  j++;
+ 	  continue;
+ 	}
+ 
+       elt = fold_convert (type, addr->elts[i]);
+       if (!mult_elt)
+ 	mult_elt = elt;
+       else
+ 	mult_elt = fold_build2 (PLUS_EXPR, type, mult_elt, elt);
+     }
+   addr->n = j;
+ 
+   parts->index = mult_elt;
+   parts->step = build_int_cst_type (type, best_mult);
+ }
+ 
+ /* Splits address ADDR into PARTS.
+    
+    TODO -- be more clever about the distribution of the elements of ADDR
+    to PARTS.  Some architectures do not support anything but single
+    register in address, possibly with a small integer offset; while
+    create_mem_ref will simplify the address to an acceptable shape
+    later, it would be a small bit more efficient to know that asking
+    for complicated addressing modes is useless.  */
+ 
+ static void
+ addr_to_parts (struct affine_tree_combination *addr, tree type,
+ 	       struct mem_address *parts)
+ {
+   unsigned i;
+ 
+   parts->symbol = NULL_TREE;
+   parts->base = NULL_TREE;
+   parts->index = NULL_TREE;
+   parts->step = NULL_TREE;
+ 
+   if (addr->offset)
+     parts->offset = build_int_cst_type (type, addr->offset);
+   else
+     parts->offset = NULL_TREE;
+ 
+   /* First move the most expensive feasible multiplication
+      to index.  */
+   most_expensive_mult_to_index (parts, type, addr);
+ 
+   /* Then try to process the remaining elements.  */
+   for (i = 0; i < addr->n; i++)
+     add_to_parts (parts, type, addr->elts[i], addr->coefs[i]);
+   if (addr->rest)
+     add_to_parts (parts, type, addr->rest, 1);
+ }
+ 
+ /* 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,
+ 		struct affine_tree_combination *addr)
+ {
+   tree mem_ref, tmp;
+   tree addr_type = build_pointer_type (type);
+   struct mem_address parts;
+ 
+   addr_to_parts (addr, addr_type, &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.  */
+   TMR_TAG (to) = TMR_TAG (from);
+ 
+   /* And the info about the original reference.  */
+   TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
+ }
+ 
+ /* 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.67
diff -c -3 -p -r2.67 tree-ssa-ccp.c
*** tree-ssa-ccp.c	21 Apr 2005 18:05:24 -0000	2.67
--- tree-ssa-ccp.c	1 May 2005 20:27:20 -0000
*************** maybe_fold_stmt_addition (tree expr)
*** 1799,1805 ****
    return t;
  }
  
- 
  /* Subroutine of fold_stmt called via walk_tree.  We perform several
     simplifications of EXPR_P, mostly having to do with pointer arithmetic.  */
  
--- 1799,1804 ----
*************** fold_stmt_r (tree *expr_p, int *walk_sub
*** 1873,1878 ****
--- 1872,1881 ----
        }
        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.38
diff -c -3 -p -r2.38 tree-ssa-loop-im.c
*** tree-ssa-loop-im.c	23 Apr 2005 00:59:29 -0000	2.38
--- tree-ssa-loop-im.c	1 May 2005 20:27:20 -0000
*************** for_each_index (tree *addr_p, bool (*cbc
*** 197,202 ****
--- 197,213 ----
  	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.67
diff -c -3 -p -r2.67 tree-ssa-loop-ivopts.c
*** tree-ssa-loop-ivopts.c	1 May 2005 15:30:05 -0000	2.67
--- tree-ssa-loop-ivopts.c	1 May 2005 20:27:20 -0000
*************** may_be_unaligned_p (tree ref)
*** 1493,1498 ****
--- 1493,1503 ----
    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)
*** 1510,1540 ****
    return false;
  }
  
- /* Builds ADDR_EXPR of object OBJ.  If OBJ is an INDIRECT_REF, the indirect_ref
-    is stripped instead.  */
- 
- static tree
- build_addr_strip_iref (tree obj)
- {
-   tree type;
- 
-   if (TREE_CODE (obj) == INDIRECT_REF)
-     {
-       type = build_pointer_type (TREE_TYPE (obj));
-       obj = fold_convert (type, TREE_OPERAND (obj, 0));
-     }
-   else
-     obj = build_addr (obj);
- 
-   return obj;
- }
- 
  /* Finds addresses in *OP_P inside STMT.  */
  
  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;
  
--- 1515,1526 ----
    return false;
  }
  
  /* Finds addresses in *OP_P inside STMT.  */
  
  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
*** 1553,1569 ****
        && 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);
  
!   base = build_addr_strip_iref (base);
  
    civ = alloc_iv (base, step);
    record_use (data, op_p, civ, stmt, USE_ADDRESS);
--- 1539,1601 ----
        && 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);
! 
!       base = build_fold_addr_expr (base);
!     }
  
    civ = alloc_iv (base, step);
    record_use (data, op_p, civ, stmt, USE_ADDRESS);
*************** strip_offset_1 (tree expr, bool inside_a
*** 1879,1885 ****
        if (op0 == TREE_OPERAND (expr, 0))
  	return orig_expr;
  
!       expr = build_addr_strip_iref (op0);
        return fold_convert (orig_type, expr);
  
      case INDIRECT_REF:
--- 1911,1917 ----
        if (op0 == TREE_OPERAND (expr, 0))
  	return orig_expr;
  
!       expr = build_fold_addr_expr (op0);
        return fold_convert (orig_type, expr);
  
      case INDIRECT_REF:
*************** constant_multiple_of (tree type, tree to
*** 2655,2687 ****
      }
  }
  
- /* Affine combination of trees.  We keep track of at most MAX_AFF_ELTS elements
-    to make things simpler; this is sufficient in most cases.  */
- 
- #define MAX_AFF_ELTS 8
- 
- struct affine_tree_combination
- {
-   /* Type of the result of the combination.  */
-   tree type;
- 
-   /* Mask modulo that the operations are performed.  */
-   unsigned HOST_WIDE_INT mask;
- 
-   /* Constant offset.  */
-   unsigned HOST_WIDE_INT offset;
- 
-   /* Number of elements of the combination.  */
-   unsigned n;
- 
-   /* Elements and their coefficients.  */
-   tree elts[MAX_AFF_ELTS];
-   unsigned HOST_WIDE_INT coefs[MAX_AFF_ELTS];
- 
-   /* Remainder of the expression.  */
-   tree rest;
- };
- 
  /* Sets COMB to CST.  */
  
  static void
--- 2687,2692 ----
*************** tree_to_aff_combination (tree expr, tree
*** 2867,2873 ****
        if (bitpos % BITS_PER_UNIT != 0)
  	break;
        aff_combination_const (comb, type, bitpos / BITS_PER_UNIT);
!       core = build_addr_strip_iref (core);
        if (TREE_CODE (core) == ADDR_EXPR)
  	aff_combination_add_elt (comb, core, 1);
        else
--- 2872,2878 ----
        if (bitpos % BITS_PER_UNIT != 0)
  	break;
        aff_combination_const (comb, type, bitpos / BITS_PER_UNIT);
!       core = build_fold_addr_expr (core);
        if (TREE_CODE (core) == ADDR_EXPR)
  	aff_combination_add_elt (comb, core, 1);
        else
*************** add_elt_to_tree (tree expr, tree type, t
*** 2934,2939 ****
--- 2939,2957 ----
    return fold_build2 (code, type, expr, elt);
  }
  
+ /* Copies the tree elements of COMB to ensure that they are not shared.  */
+ 
+ static void
+ unshare_aff_combination (struct affine_tree_combination *comb)
+ {
+   unsigned i;
+ 
+   for (i = 0; i < comb->n; i++)
+     comb->elts[i] = unshare_expr (comb->elts[i]);
+   if (comb->rest)
+     comb->rest = unshare_expr (comb->rest);
+ }
+ 
  /* Makes tree from the affine combination COMB.  */
  
  static tree
*************** aff_combination_to_tree (struct affine_t
*** 2944,2949 ****
--- 2962,2972 ----
    unsigned i;
    unsigned HOST_WIDE_INT off, sgn;
  
+   /* Handle the special case produced by get_computation_aff when
+      the type does not fit in HOST_WIDE_INT.  */
+   if (comb->n == 0 && comb->offset == 0)
+     return fold_convert (type, expr);
+ 
    gcc_assert (comb->n == MAX_AFF_ELTS || comb->rest == NULL_TREE);
  
    for (i = 0; i < comb->n; i++)
*************** aff_combination_to_tree (struct affine_t
*** 2965,3013 ****
  			  comb->mask);
  }
  
- /* Folds X + RATIO * Y in TYPE.  */
- 
- static tree
- fold_affine_sum (tree type, tree x, tree y, HOST_WIDE_INT ratio)
- {
-   enum tree_code code;
-   tree cst;
-   struct affine_tree_combination cx, cy;
- 
-   if (TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT)
-     {
-       if (ratio == 1)
- 	return fold_build2 (PLUS_EXPR, type, x, y);
-       if (ratio == -1)
- 	return fold_build2 (MINUS_EXPR, type, x, y);
- 
-       if (ratio < 0)
- 	{
- 	  code = MINUS_EXPR;
- 	  ratio = -ratio;
- 	}
-       else
- 	code = PLUS_EXPR;
- 
-       cst = build_int_cst_type (type, ratio);
-       y = fold_build2 (MULT_EXPR, type, y, cst);
-       return fold_build2 (code, type, x, y);
-     }
- 
-   tree_to_aff_combination (x, type, &cx);
-   tree_to_aff_combination (y, type, &cy);
-   aff_combination_scale (&cy, ratio);
-   aff_combination_add (&cx, &cy);
- 
-   return aff_combination_to_tree (&cx);
- }
- 
  /* Determines the expression by that USE is expressed from induction variable
!    CAND at statement AT in LOOP.  */
  
! static tree
! get_computation_at (struct loop *loop,
! 		    struct iv_use *use, struct iv_cand *cand, tree at)
  {
    tree ubase = use->iv->base;
    tree ustep = use->iv->step;
--- 2988,3001 ----
  			  comb->mask);
  }
  
  /* Determines the expression by that USE is expressed from induction variable
!    CAND at statement AT in LOOP.  The expression is stored in a decomposed
!    form into AFF.  Returns false if USE cannot be expressed using CAND.  */
  
! static bool
! get_computation_aff (struct loop *loop,
! 		     struct iv_use *use, struct iv_cand *cand, tree at,
! 		     struct affine_tree_combination *aff)
  {
    tree ubase = use->iv->base;
    tree ustep = use->iv->step;
*************** get_computation_at (struct loop *loop,
*** 3019,3029 ****
    tree ratio;
    unsigned HOST_WIDE_INT ustepi, cstepi;
    HOST_WIDE_INT ratioi;
  
    if (TYPE_PRECISION (utype) > TYPE_PRECISION (ctype))
      {
        /* We do not have a precision to express the values of use.  */
!       return NULL_TREE;
      }
  
    expr = var_at_stmt (loop, cand, at);
--- 3007,3018 ----
    tree ratio;
    unsigned HOST_WIDE_INT ustepi, cstepi;
    HOST_WIDE_INT ratioi;
+   struct affine_tree_combination cbase_aff, expr_aff;
  
    if (TYPE_PRECISION (utype) > TYPE_PRECISION (ctype))
      {
        /* We do not have a precision to express the values of use.  */
!       return false;
      }
  
    expr = var_at_stmt (loop, cand, at);
*************** get_computation_at (struct loop *loop,
*** 3061,3067 ****
  	  /* TODO maybe consider case when ustep divides cstep and the ratio is
  	     a power of 2 (so that the division is fast to execute)?  We would
  	     need to be much more careful with overflows etc. then.  */
! 	  return NULL_TREE;
  	}
  
        ratio = build_int_cst_type (uutype, ratioi);
--- 3050,3056 ----
  	  /* TODO maybe consider case when ustep divides cstep and the ratio is
  	     a power of 2 (so that the division is fast to execute)?  We would
  	     need to be much more careful with overflows etc. then.  */
! 	  return false;
  	}
  
        ratio = build_int_cst_type (uutype, ratioi);
*************** get_computation_at (struct loop *loop,
*** 3070,3076 ****
      {
        ratio = constant_multiple_of (uutype, ustep, cstep);
        if (!ratio)
! 	return NULL_TREE;
  
        /* Ratioi is only used to detect special cases when the multiplicative
  	 factor is 1 or -1, so if we cannot convert ratio to HOST_WIDE_INT,
--- 3059,3065 ----
      {
        ratio = constant_multiple_of (uutype, ustep, cstep);
        if (!ratio)
! 	return false;
  
        /* Ratioi is only used to detect special cases when the multiplicative
  	 factor is 1 or -1, so if we cannot convert ratio to HOST_WIDE_INT,
*************** get_computation_at (struct loop *loop,
*** 3099,3132 ****
       happen, fold is able to apply the distributive law to obtain this form
       anyway.  */
  
!   if (ratioi == 1)
!     {
!       delta = fold_affine_sum (uutype, ubase, cbase, -1);
!       expr = fold_build2 (PLUS_EXPR, uutype, expr, delta);
!     }
!   else if (ratioi == -1)
!     {
!       delta = fold_affine_sum (uutype, ubase, cbase, 1);
!       expr = fold_build2 (MINUS_EXPR, uutype, delta, expr);
!     }
!   else
      {
!       if (ratioi)
! 	delta = fold_affine_sum (uutype, ubase, cbase, -ratioi);
        else
  	{
! 	  delta = fold_build2 (MULT_EXPR, uutype, ratio, cbase);
! 	  delta = fold_affine_sum (uutype, ubase, delta, -1);
  	}
!       expr = fold_build2 (MULT_EXPR, uutype, ratio, expr);
!       expr = fold_build2 (PLUS_EXPR, uutype, delta, expr);
      }
  
!   return fold_convert (utype, expr);
  }
  
  /* Determines the expression by that USE is expressed from induction variable
!    CAND in LOOP.  */
  
  static tree
  get_computation (struct loop *loop, struct iv_use *use, struct iv_cand *cand)
--- 3088,3158 ----
       happen, fold is able to apply the distributive law to obtain this form
       anyway.  */
  
!   if (TYPE_PRECISION (uutype) > HOST_BITS_PER_WIDE_INT)
      {
!       /* Let's compute in trees and just return the result in AFF.  This case
! 	 should not be very common, and fold itself is not that bad either,
! 	 so making the aff. functions more complicated to handle this case
! 	 is not that urgent.  */
!       if (ratioi == 1)
! 	{
! 	  delta = fold_build2 (MINUS_EXPR, uutype, ubase, cbase);
! 	  expr = fold_build2 (PLUS_EXPR, uutype, expr, delta);
! 	}
!       else if (ratioi == -1)
! 	{
! 	  delta = fold_build2 (PLUS_EXPR, uutype, ubase, cbase);
! 	  expr = fold_build2 (MINUS_EXPR, uutype, delta, expr);
! 	}
        else
  	{
! 	  delta = fold_build2 (MULT_EXPR, uutype, cbase, ratio);
! 	  delta = fold_build2 (MINUS_EXPR, uutype, ubase, delta);
! 	  expr = fold_build2 (MULT_EXPR, uutype, ratio, expr);
! 	  expr = fold_build2 (PLUS_EXPR, uutype, delta, expr);
  	}
! 
!       aff->type = uutype;
!       aff->n = 0;
!       aff->offset = 0;
!       aff->mask = 0;
!       aff->rest = expr;
!       return true;
      }
  
!   /* If we got here, the types fits in HOST_WIDE_INT, thus it must be
!      possible to compute ratioi.  */
!   gcc_assert (ratioi);
! 
!   tree_to_aff_combination (ubase, uutype, aff);
!   tree_to_aff_combination (cbase, uutype, &cbase_aff);
!   tree_to_aff_combination (expr, uutype, &expr_aff);
!   aff_combination_scale (&cbase_aff, -ratioi);
!   aff_combination_scale (&expr_aff, ratioi);
!   aff_combination_add (aff, &cbase_aff);
!   aff_combination_add (aff, &expr_aff);
! 
!   return true;
  }
  
  /* Determines the expression by that USE is expressed from induction variable
!    CAND at statement AT in LOOP.  The computation is unshared.  */
! 
! static tree
! get_computation_at (struct loop *loop,
! 		    struct iv_use *use, struct iv_cand *cand, tree at)
! {
!   struct affine_tree_combination aff;
!   tree type = TREE_TYPE (use->iv->base);
! 
!   if (!get_computation_aff (loop, use, cand, at, &aff))
!     return NULL_TREE;
!   unshare_aff_combination (&aff);
!   return fold_convert (type, aff_combination_to_tree (&aff));
! }
! 
! /* Determines the expression by that USE is expressed from induction variable
!    CAND in LOOP.  The computation is unshared.  */
  
  static tree
  get_computation (struct loop *loop, struct iv_use *use, struct iv_cand *cand)
*************** mbc_entry_eq (const void *entry1, const 
*** 3198,3204 ****
  
  /* Returns cost of multiplication by constant CST in MODE.  */
  
! static unsigned
  multiply_by_cost (HOST_WIDE_INT cst, enum machine_mode mode)
  {
    static htab_t costs;
--- 3224,3230 ----
  
  /* Returns cost of multiplication by constant CST in MODE.  */
  
! unsigned
  multiply_by_cost (HOST_WIDE_INT cst, enum machine_mode mode)
  {
    static htab_t costs;
*************** multiply_by_cost (HOST_WIDE_INT cst, enu
*** 3236,3241 ****
--- 3262,3308 ----
    return cost;
  }
  
+ /* Returns true if multiplying by RATIO is allowed in address.  */
+ 
+ bool
+ multiplier_allowed_in_address_p (HOST_WIDE_INT ratio)
+ {
+ #define MAX_RATIO 128
+   static sbitmap valid_mult;
+   
+   if (!valid_mult)
+     {
+       rtx reg1 = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER);
+       rtx addr;
+       HOST_WIDE_INT i;
+ 
+       valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
+       sbitmap_zero (valid_mult);
+       addr = gen_rtx_fmt_ee (MULT, Pmode, reg1, NULL_RTX);
+       for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
+ 	{
+ 	  XEXP (addr, 1) = gen_int_mode (i, Pmode);
+ 	  if (memory_address_p (Pmode, addr))
+ 	    SET_BIT (valid_mult, i + MAX_RATIO);
+ 	}
+ 
+       if (dump_file && (dump_flags & TDF_DETAILS))
+ 	{
+ 	  fprintf (dump_file, "  allowed multipliers:");
+ 	  for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
+ 	    if (TEST_BIT (valid_mult, i + MAX_RATIO))
+ 	      fprintf (dump_file, " %d", (int) i);
+ 	  fprintf (dump_file, "\n");
+ 	  fprintf (dump_file, "\n");
+ 	}
+     }
+ 
+   if (ratio > MAX_RATIO || ratio < -MAX_RATIO)
+     return false;
+ 
+   return TEST_BIT (valid_mult, ratio + MAX_RATIO);
+ }
+ 
  /* Returns cost of address in shape symbol + var + OFFSET + RATIO * index.
     If SYMBOL_PRESENT is false, symbol is omitted.  If VAR_PRESENT is false,
     variable is omitted.  The created memory accesses MODE.
*************** static unsigned
*** 3246,3253 ****
  get_address_cost (bool symbol_present, bool var_present,
  		  unsigned HOST_WIDE_INT offset, HOST_WIDE_INT ratio)
  {
! #define MAX_RATIO 128
!   static sbitmap valid_mult;
    static HOST_WIDE_INT rat, off;
    static HOST_WIDE_INT min_offset, max_offset;
    static unsigned costs[2][2][2][2];
--- 3313,3319 ----
  get_address_cost (bool symbol_present, bool var_present,
  		  unsigned HOST_WIDE_INT offset, HOST_WIDE_INT ratio)
  {
!   static bool initialized = false;
    static HOST_WIDE_INT rat, off;
    static HOST_WIDE_INT min_offset, max_offset;
    static unsigned costs[2][2][2][2];
*************** get_address_cost (bool symbol_present, b
*** 3259,3267 ****
    unsigned HOST_WIDE_INT mask;
    unsigned bits;
  
!   if (!valid_mult)
      {
        HOST_WIDE_INT i;
  
        reg1 = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER);
  
--- 3325,3334 ----
    unsigned HOST_WIDE_INT mask;
    unsigned bits;
  
!   if (!initialized)
      {
        HOST_WIDE_INT i;
+       initialized = true;
  
        reg1 = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER);
  
*************** get_address_cost (bool symbol_present, b
*** 3290,3318 ****
  	  fprintf (dump_file, "  max offset %d\n", (int) max_offset);
  	}
  
-       valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
-       sbitmap_zero (valid_mult);
        rat = 1;
!       addr = gen_rtx_fmt_ee (MULT, Pmode, reg1, NULL_RTX);
!       for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
! 	{
! 	  XEXP (addr, 1) = GEN_INT (i);
! 	  if (memory_address_p (Pmode, addr))
! 	    {
! 	      SET_BIT (valid_mult, i + MAX_RATIO);
! 	      rat = i;
! 	    }
! 	}
! 
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	{
! 	  fprintf (dump_file, "  allowed multipliers:");
! 	  for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
! 	    if (TEST_BIT (valid_mult, i + MAX_RATIO))
! 	      fprintf (dump_file, " %d", (int) i);
! 	  fprintf (dump_file, "\n");
! 	  fprintf (dump_file, "\n");
! 	}
      }
  
    bits = GET_MODE_BITSIZE (Pmode);
--- 3357,3369 ----
  	  fprintf (dump_file, "  max offset %d\n", (int) max_offset);
  	}
  
        rat = 1;
!       for (i = 2; i <= MAX_RATIO; i++)
! 	if (multiplier_allowed_in_address_p (i))
! 	  {
! 	    rat = i;
! 	    break;
! 	  }
      }
  
    bits = GET_MODE_BITSIZE (Pmode);
*************** get_address_cost (bool symbol_present, b
*** 3326,3333 ****
    offset_p = (s_offset != 0
  	      && min_offset <= s_offset && s_offset <= max_offset);
    ratio_p = (ratio != 1
! 	     && -MAX_RATIO <= ratio && ratio <= MAX_RATIO
! 	     && TEST_BIT (valid_mult, ratio + MAX_RATIO));
  
    if (ratio != 1 && !ratio_p)
      cost += multiply_by_cost (ratio, Pmode);
--- 3377,3383 ----
    offset_p = (s_offset != 0
  	      && min_offset <= s_offset && s_offset <= max_offset);
    ratio_p = (ratio != 1
! 	     && multiplier_allowed_in_address_p (ratio));
  
    if (ratio != 1 && !ratio_p)
      cost += multiply_by_cost (ratio, Pmode);
*************** rewrite_use_nonlinear_expr (struct ivopt
*** 5303,5310 ****
  	return;
      }
  
!   comp = unshare_expr (get_computation (data->current_loop,
! 					use, cand));
    switch (TREE_CODE (use->stmt))
      {
      case PHI_NODE:
--- 5353,5359 ----
  	return;
      }
  
!   comp = get_computation (data->current_loop, use, cand);
    switch (TREE_CODE (use->stmt))
      {
      case PHI_NODE:
*************** unshare_and_remove_ssa_names (tree ref)
*** 5389,5467 ****
    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_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;
!     
!   /* 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
      {
!       tree tag = var_ann (var)->type_mem_tag;
!       tree new_ptr = create_tmp_var (TREE_TYPE (with), "ruatmp");
!       add_referenced_tmp_var (new_ptr);
        if (tag)
! 	var_ann (new_ptr)->type_mem_tag = tag;
!       else
! 	add_type_alias (new_ptr, var);
!       new_name = make_ssa_name (new_ptr, copy);
!     }
! 
!   TREE_OPERAND (copy, 0) = new_name;
!   update_stmt (copy);
!   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;
  
!   /* Virtual operands in the original statement may have to be renamed
!      because of the replacement.  */
!   mark_new_vars_to_rename (bsi_stmt (*bsi));
  }
  
  /* Rewrites USE (address that is an iv) using candidate CAND.  */
--- 5438,5497 ----
    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)
!     copy_mem_ref_info (new_ref, old_ref);
!   else
!     {
!       TMR_TAG (new_ref) = get_ref_tag (old_ref);
!       TMR_ORIGINAL (new_ref) = unshare_and_remove_ssa_names (old_ref);
!     }
  }
  
  /* Rewrites USE (address that is an iv) using candidate CAND.  */
*************** static void
*** 5470,5485 ****
  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
--- 5500,5515 ----
  rewrite_use_address (struct ivopts_data *data,
  		     struct iv_use *use, struct iv_cand *cand)
  {
!   struct affine_tree_combination aff;
    block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
!   tree ref;
  
!   get_computation_aff (data->current_loop, use, cand, use->stmt, &aff);
!   unshare_aff_combination (&aff);
  
!   ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff);
!   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
*************** rewrite_use_compare (struct ivopts_data 
*** 5516,5522 ****
  
    /* The induction variable elimination failed; just express the original
       giv.  */
!   comp = unshare_expr (get_computation (data->current_loop, use, cand));
  
    cond = *use->op_p;
    op_p = &TREE_OPERAND (cond, 0);
--- 5546,5552 ----
  
    /* The induction variable elimination failed; just express the original
       giv.  */
!   comp = get_computation (data->current_loop, use, cand);
  
    cond = *use->op_p;
    op_p = &TREE_OPERAND (cond, 0);
*************** rewrite_use_outer (struct ivopts_data *d
*** 5683,5689 ****
  	value = get_computation_at (data->current_loop,
  				    use, cand, last_stmt (exit->src));
  
-       value = unshare_expr (value);
        op = force_gimple_operand (value, &stmts, true, SSA_NAME_VAR (tgt));
  	  
        /* If we will preserve the iv anyway and we would need to perform
--- 5713,5718 ----
*************** tree_ssa_iv_optimize (struct loops *loop
*** 5988,6012 ****
  	loop = loop->outer;
      }
  
-   /* FIXME.  IV opts introduces new aliases and call-clobbered
-      variables, which need to be renamed.  However, when we call the
-      renamer, not all statements will be scanned for operands.  In
-      particular, the newly introduced aliases may appear in statements
-      that are considered "unmodified", so the renamer will not get a
-      chance to rename those operands.
- 
-      Work around this problem by forcing an operand re-scan on every
-      statement.  This will not be necessary once the new operand
-      scanner is implemented.  */
-   if (need_ssa_update_p ())
-     {
-       basic_block bb;
-       block_stmt_iterator si;
-       FOR_EACH_BB (bb)
- 	for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
- 	  update_stmt (bsi_stmt (si));
-     }
- 
-   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
    tree_ssa_iv_optimize_finalize (loops, &data);
  }
--- 6017,6021 ----
Index: tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 2.79
diff -c -3 -p -r2.79 tree-ssa-operands.c
*** tree-ssa-operands.c	29 Apr 2005 15:34:45 -0000	2.79
--- tree-ssa-operands.c	1 May 2005 20:27:20 -0000
*************** static void note_addressable (tree, stmt
*** 133,138 ****
--- 133,139 ----
  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
*** 1324,1329 ****
--- 1325,1334 ----
        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
*** 1705,1710 ****
--- 1710,1739 ----
    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)
+ {
+   tree tag = TMR_TAG (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 (tag)
+     add_stmt_operand (&tag, stmt_ann (stmt), flags);
+   else
+     /* Something weird, so ensure that 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.477
diff -c -3 -p -r1.477 tree.c
*** tree.c	1 May 2005 08:08:07 -0000	1.477
--- tree.c	1 May 2005 20:27:20 -0000
*************** build4_stat (enum tree_code code, tree t
*** 2707,2718 ****
    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,2747 ----
    return t;
  }
  
+ tree
+ build7_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
+ 	     tree arg2, tree arg3, tree arg4, tree arg5,
+ 	     tree arg6 MEM_STAT_DECL)
+ {
+   bool constant, read_only, side_effects, invariant;
+   tree t;
+ 
+   gcc_assert (code == TARGET_MEM_REF);
+ 
+   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);
+   PROCESS_ARG(5);
+   PROCESS_ARG(6);
+ 
+   TREE_SIDE_EFFECTS (t) = side_effects;
+   TREE_THIS_VOLATILE (t) = 0;
+ 
+   return t;
+ }
+ 
  /* Backup definition for non-gcc build compilers.  */
  
  tree
  (build) (enum tree_code code, tree tt, ...)
  {
!   tree t, arg0, arg1, arg2, arg3, arg4, arg5, arg6;
    int length = TREE_CODE_LENGTH (code);
    va_list p;
  
*************** tree
*** 2744,2749 ****
--- 2773,2788 ----
        arg3 = va_arg (p, tree);
        t = build4 (code, tt, arg0, arg1, arg2, arg3);
        break;
+     case 7:
+       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);
+       arg5 = va_arg (p, tree);
+       arg6 = va_arg (p, tree);
+       t = build7 (code, tt, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
+       break;
      default:
        gcc_unreachable ();
      }
Index: tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.115
diff -c -3 -p -r1.115 tree.def
*** tree.def	9 Apr 2005 01:37:28 -0000	1.115
--- tree.def	1 May 2005 20:27:20 -0000
*************** DEFTREECODE (WITH_SIZE_EXPR, "with_size_
*** 935,940 ****
--- 935,952 ----
     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.
+    
+    The sixth argument is the reference to the original memory access, which
+    is preserved for the purposes of the RTL alias analysis.  The seventh
+    argument is a tag representing results of the tree level alias analysis.  */
+ 
+ DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 7)
+ 
  /*
  Local variables:
  mode:c
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.724
diff -c -3 -p -r1.724 tree.h
*** tree.h	29 Apr 2005 20:27:51 -0000	1.724
--- tree.h	1 May 2005 20:27:20 -0000
*************** struct tree_vec GTY(())
*** 1171,1180 ****
  #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)
  
--- 1171,1176 ----
*************** struct tree_vec GTY(())
*** 1240,1245 ****
--- 1236,1250 ----
  #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))
+ #define TMR_ORIGINAL(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 5))
+ #define TMR_TAG(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 6))
+ 
  /* 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,
*** 2890,2895 ****
--- 2895,2904 ----
  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 build7_stat (enum tree_code, tree, tree, tree, tree, tree,
+ 			 tree, tree, tree MEM_STAT_DECL);
+ #define build7(c,t1,t2,t3,t4,t5,t6,t7,t8) \
+   build7_stat (c,t1,t2,t3,t4,t5,t6,t7,t8 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);
*** 3979,3982 ****
--- 3988,3995 ----
  /* 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	1 May 2005 20:27:21 -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,2129 ----
  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
+ 
+ The sixth argument is the reference to the original memory access, which
+ is preserved for the purposes of the RTL alias analysis.  The seventh
+ argument is a tag representing the results of tree level alias analysis.
+ 
  @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.25
diff -c -3 -p -r1.25 tree-ssa.texi
*** doc/tree-ssa.texi	29 Apr 2005 15:06:07 -0000	1.25
--- doc/tree-ssa.texi	1 May 2005 20:27:21 -0000
*************** void f()
*** 632,637 ****
--- 632,643 ----
                          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
Index: testsuite/gcc.dg/tree-ssa/loop-2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/tree-ssa/loop-2.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 loop-2.c
*** testsuite/gcc.dg/tree-ssa/loop-2.c	31 Mar 2005 18:34:15 -0000	1.3
--- testsuite/gcc.dg/tree-ssa/loop-2.c	1 May 2005 20:27:21 -0000
*************** void xxx(void)
*** 21,29 ****
      arr_base[iter].y = 17 * iter;
  }
  
! /* Access to arr_base[iter].y should be strength reduced.  */
  
! /* { dg-final { scan-tree-dump-times "arr_base\[^\\n\\r\]*=" 0 "vars" } } */
  
  /* 17 * iter should be strength reduced.  */
  
--- 21,32 ----
      arr_base[iter].y = 17 * iter;
  }
  
! /* Access to arr_base[iter].y should be strength reduced, i.e., there should
!    be no multiplication.  */
  
! /* { dg-final { scan-tree-dump-times " \\* \[^\\n\\r\]*=" 0 "vars" } } */
! /* { dg-final { scan-tree-dump-times "\[^\\n\\r\]*= \\* " 0 "vars" } } */
! /* { dg-final { scan-tree-dump-times "MEM" 1 "vars" } } */
  
  /* 17 * iter should be strength reduced.  */
  
Index: testsuite/gcc.dg/tree-ssa/loop-3.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/tree-ssa/loop-3.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 loop-3.c
*** testsuite/gcc.dg/tree-ssa/loop-3.c	31 Mar 2005 18:34:15 -0000	1.2
--- testsuite/gcc.dg/tree-ssa/loop-3.c	1 May 2005 20:27:21 -0000
*************** void xxx(void)
*** 20,26 ****
  /* Access to arr_base[iter].y should not be strength reduced, since
     we have a memory mode including multiplication by 4.  */
  
! /* { dg-final { scan-tree-dump-times "arr_base.*=" 1 "vars" } } */
  
  /* And original induction variable should be preserved.  */
  
--- 20,27 ----
  /* Access to arr_base[iter].y should not be strength reduced, since
     we have a memory mode including multiplication by 4.  */
  
! /* { dg-final { scan-tree-dump-times "MEM" 1 "vars" } } */
! /* { dg-final { scan-tree-dump-times "step:" 1 "vars" } } */
  
  /* And original induction variable should be preserved.  */
  
Index: testsuite/gcc.dg/tree-ssa/loop-4.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/tree-ssa/loop-4.c,v
retrieving revision 1.4
diff -c -3 -p -r1.4 loop-4.c
*** testsuite/gcc.dg/tree-ssa/loop-4.c	31 Mar 2005 18:34:15 -0000	1.4
--- testsuite/gcc.dg/tree-ssa/loop-4.c	1 May 2005 20:27:21 -0000
*************** void xxx(void)
*** 32,40 ****
     -- induction variable with base 0, the memory access of form
        *(iv + &arr_base[0].y) = ...
  
!    In any case, we should not have 'arr_base.[^0].* ='  */
  
! /* { dg-final { scan-tree-dump-times "arr_base.\[^0\]\[^\\n\\r\]*=" 0 "vars" } } */
  
  /* And the original induction variable should be eliminated.  */
  
--- 32,42 ----
     -- induction variable with base 0, the memory access of form
        *(iv + &arr_base[0].y) = ...
  
!    In any case, we should not have any multiplication.  */
  
! /* { dg-final { scan-tree-dump-times " \\* \[^\\n\\r\]*=" 0 "vars" } } */
! /* { dg-final { scan-tree-dump-times "\[^\\n\\r\]*= \\* " 0 "vars" } } */
! /* { dg-final { scan-tree-dump-times "MEM" 1 "vars" } } */
  
  /* And the original induction variable should be eliminated.  */
  
Index: testsuite/gcc.dg/tree-ssa/loop-9.c
===================================================================
RCS file: testsuite/gcc.dg/tree-ssa/loop-9.c
diff -N testsuite/gcc.dg/tree-ssa/loop-9.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/tree-ssa/loop-9.c	1 May 2005 20:27:21 -0000
***************
*** 0 ****
--- 1,24 ----
+ /* Without TARGET_MEM_REFs, dom creates code like
+    
+    i1 = 4 * i;
+    *(p + i1) = i;
+    *(p + i1 + 4) = i
+    
+    causing us to have unnecessary multiplication by 4 in the
+    result.  */
+ 
+ /* { dg-do compile } */
+ /* { dg-options "-O1" } */
+ 
+ void foo (int *p)
+ {
+   int i;
+ 
+   for (i = 0; i < 100; i++)
+     {
+       p[i] = i;
+       p[i + 1] = i;
+     }
+ }
+ 
+ /* { dg-final { scan-assembler-times "lea" 0 { target i?86-*-* x86_64-*-* } } } */


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