This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] TARGET_MEM_REF, version 3
- From: Zdenek Dvorak <rakdver at atrey dot karlin dot mff dot cuni dot cz>
- To: Diego Novillo <dnovillo at redhat dot com>
- Cc: Richard Henderson <rth at redhat dot com>, gcc-patches at gcc dot gnu dot org,stevenb at suse dot de
- Date: Mon, 2 May 2005 10:56:26 +0200
- Subject: [patch] TARGET_MEM_REF, version 3
- References: <20050404202502.GA12195@atrey.karlin.mff.cuni.cz> <20050409064441.GA12217@redhat.com> <20050412232221.GA21081@atrey.karlin.mff.cuni.cz> <20050425164146.GA32357@topo.toronto.redhat.com>
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-*-* } } } */