OSDN Git Service

2008-10-23 Tobias Grosser <grosser@fim.uni-passau.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-address.c
1 /* Memory address lowering and addressing mode selection.
2    Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
3    
4 This file is part of GCC.
5    
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10    
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15    
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19
20 /* Utility functions for manipulation with TARGET_MEM_REFs -- tree expressions
21    that directly map to addressing modes of the target.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "rtl.h"
29 #include "tm_p.h"
30 #include "hard-reg-set.h"
31 #include "basic-block.h"
32 #include "output.h"
33 #include "diagnostic.h"
34 #include "tree-flow.h"
35 #include "tree-dump.h"
36 #include "tree-pass.h"
37 #include "timevar.h"
38 #include "flags.h"
39 #include "tree-inline.h"
40 #include "insn-config.h"
41 #include "recog.h"
42 #include "expr.h"
43 #include "ggc.h"
44 #include "tree-affine.h"
45
46 /* TODO -- handling of symbols (according to Richard Hendersons
47    comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
48    
49    There are at least 5 different kinds of symbols that we can run up against:
50
51      (1) binds_local_p, small data area.
52      (2) binds_local_p, eg local statics
53      (3) !binds_local_p, eg global variables
54      (4) thread local, local_exec
55      (5) thread local, !local_exec
56
57    Now, (1) won't appear often in an array context, but it certainly can.
58    All you have to do is set -GN high enough, or explicitly mark any
59    random object __attribute__((section (".sdata"))).
60
61    All of these affect whether or not a symbol is in fact a valid address.
62    The only one tested here is (3).  And that result may very well
63    be incorrect for (4) or (5).
64
65    An incorrect result here does not cause incorrect results out the
66    back end, because the expander in expr.c validizes the address.  However
67    it would be nice to improve the handling here in order to produce more
68    precise results.  */
69
70 /* A "template" for memory address, used to determine whether the address is
71    valid for mode.  */
72
73 struct mem_addr_template GTY (())
74 {
75   rtx ref;                      /* The template.  */
76   rtx * GTY ((skip)) step_p;    /* The point in template where the step should be
77                                    filled in.  */
78   rtx * GTY ((skip)) off_p;     /* The point in template where the offset should
79                                    be filled in.  */
80 };
81
82 /* The templates.  Each of the five bits of the index corresponds to one
83    component of TARGET_MEM_REF being present, see TEMPL_IDX.  */
84
85 static GTY (()) struct mem_addr_template templates[32];
86
87 #define TEMPL_IDX(SYMBOL, BASE, INDEX, STEP, OFFSET) \
88   (((SYMBOL != 0) << 4) \
89    | ((BASE != 0) << 3) \
90    | ((INDEX != 0) << 2) \
91    | ((STEP != 0) << 1) \
92    | (OFFSET != 0))
93
94 /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
95    STEP and OFFSET to *ADDR.  Stores pointers to where step is placed to
96    *STEP_P and offset to *OFFSET_P.  */
97
98 static void
99 gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset,
100               rtx *addr, rtx **step_p, rtx **offset_p)
101 {
102   rtx act_elem;
103
104   *addr = NULL_RTX;
105   if (step_p)
106     *step_p = NULL;
107   if (offset_p)
108     *offset_p = NULL;
109
110   if (index)
111     {
112       act_elem = index;
113       if (step)
114         {
115           act_elem = gen_rtx_MULT (Pmode, act_elem, step);
116
117           if (step_p)
118             *step_p = &XEXP (act_elem, 1);
119         }
120
121       *addr = act_elem;
122     }
123
124   if (base)
125     {
126       if (*addr)
127         *addr = simplify_gen_binary (PLUS, Pmode, base, *addr);
128       else
129         *addr = base;
130     }
131
132   if (symbol)
133     {
134       act_elem = symbol;
135       if (offset)
136         {
137           act_elem = gen_rtx_PLUS (Pmode, act_elem, offset);
138
139           if (offset_p)
140             *offset_p = &XEXP (act_elem, 1);
141
142           if (GET_CODE (symbol) == SYMBOL_REF
143               || GET_CODE (symbol) == LABEL_REF
144               || GET_CODE (symbol) == CONST)
145             act_elem = gen_rtx_CONST (Pmode, act_elem);
146         }
147
148       if (*addr)
149         *addr = gen_rtx_PLUS (Pmode, *addr, act_elem);
150       else
151         *addr = act_elem;
152     }
153   else if (offset)
154     {
155       if (*addr)
156         {
157           *addr = gen_rtx_PLUS (Pmode, *addr, offset);
158           if (offset_p)
159             *offset_p = &XEXP (*addr, 1);
160         }
161       else
162         {
163           *addr = offset;
164           if (offset_p)
165             *offset_p = addr;
166         }
167     }
168
169   if (!*addr)
170     *addr = const0_rtx;
171 }
172
173 /* Returns address for TARGET_MEM_REF with parameters given by ADDR.
174    If REALLY_EXPAND is false, just make fake registers instead 
175    of really expanding the operands, and perform the expansion in-place
176    by using one of the "templates".  */
177
178 rtx
179 addr_for_mem_ref (struct mem_address *addr, bool really_expand)
180 {
181   rtx address, sym, bse, idx, st, off;
182   static bool templates_initialized = false;
183   struct mem_addr_template *templ;
184
185   if (addr->step && !integer_onep (addr->step))
186     st = immed_double_const (TREE_INT_CST_LOW (addr->step),
187                              TREE_INT_CST_HIGH (addr->step), Pmode);
188   else
189     st = NULL_RTX;
190
191   if (addr->offset && !integer_zerop (addr->offset))
192     off = immed_double_const (TREE_INT_CST_LOW (addr->offset),
193                               TREE_INT_CST_HIGH (addr->offset), Pmode);
194   else
195     off = NULL_RTX;
196
197   if (!really_expand)
198     {
199       /* Reuse the templates for addresses, so that we do not waste memory.  */
200       if (!templates_initialized)
201         {
202           unsigned i;
203
204           templates_initialized = true;
205           sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("test_symbol"));
206           bse = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1);
207           idx = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 2);
208
209           for (i = 0; i < 32; i++)
210             gen_addr_rtx ((i & 16 ? sym : NULL_RTX),
211                           (i & 8 ? bse : NULL_RTX),
212                           (i & 4 ? idx : NULL_RTX),
213                           (i & 2 ? const0_rtx : NULL_RTX),
214                           (i & 1 ? const0_rtx : NULL_RTX),
215                           &templates[i].ref,
216                           &templates[i].step_p,
217                           &templates[i].off_p);
218         }
219
220       templ = templates + TEMPL_IDX (addr->symbol, addr->base, addr->index,
221                                      st, off);
222       if (st)
223         *templ->step_p = st;
224       if (off)
225         *templ->off_p = off;
226
227       return templ->ref;
228     }
229
230   /* Otherwise really expand the expressions.  */
231   sym = (addr->symbol
232          ? expand_expr (build_addr (addr->symbol, current_function_decl),
233                         NULL_RTX, Pmode, EXPAND_NORMAL)
234          : NULL_RTX);
235   bse = (addr->base
236          ? expand_expr (addr->base, NULL_RTX, Pmode, EXPAND_NORMAL)
237          : NULL_RTX);
238   idx = (addr->index
239          ? expand_expr (addr->index, NULL_RTX, Pmode, EXPAND_NORMAL)
240          : NULL_RTX);
241
242   gen_addr_rtx (sym, bse, idx, st, off, &address, NULL, NULL);
243   return address;
244 }
245
246 /* Returns address of MEM_REF in TYPE.  */
247
248 tree
249 tree_mem_ref_addr (tree type, tree mem_ref)
250 {
251   tree addr;
252   tree act_elem;
253   tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
254   tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
255   tree addr_base = NULL_TREE, addr_off = NULL_TREE;
256
257   if (sym)
258     addr_base = fold_convert (type, build_addr (sym, current_function_decl));
259   else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
260     {
261       addr_base = fold_convert (type, base);
262       base = NULL_TREE;
263     }
264
265   act_elem = TMR_INDEX (mem_ref);
266   if (act_elem)
267     {
268       if (step)
269         act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
270       addr_off = act_elem;
271     }
272
273   act_elem = base;
274   if (act_elem)
275     {
276       if (addr_off)
277         addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
278       else
279         addr_off = act_elem;
280     }
281
282   if (offset && !integer_zerop (offset))
283     {
284       if (addr_off)
285         addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
286       else
287         addr_off = offset;
288     }
289
290   if (addr_off)
291     {
292       if (addr_base)
293         addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off);
294       else
295         addr = fold_convert (type, addr_off);
296     }
297   else if (addr_base)
298     addr = addr_base;
299   else
300     addr = build_int_cst (type, 0);
301
302   return addr;
303 }
304
305 /* Returns true if a memory reference in MODE and with parameters given by
306    ADDR is valid on the current target.  */
307
308 static bool
309 valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr)
310 {
311   rtx address;
312
313   address = addr_for_mem_ref (addr, false);
314   if (!address)
315     return false;
316
317   return memory_address_p (mode, address);
318 }
319
320 /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
321    is valid on the current target and if so, creates and returns the
322    TARGET_MEM_REF.  */
323
324 static tree
325 create_mem_ref_raw (tree type, struct mem_address *addr)
326 {
327   if (!valid_mem_ref_p (TYPE_MODE (type), addr))
328     return NULL_TREE;
329
330   if (addr->step && integer_onep (addr->step))
331     addr->step = NULL_TREE;
332
333   if (addr->offset && integer_zerop (addr->offset))
334     addr->offset = NULL_TREE;
335
336   return build7 (TARGET_MEM_REF, type,
337                  addr->symbol, addr->base, addr->index,
338                  addr->step, addr->offset, NULL, NULL);
339 }
340
341 /* Returns true if OBJ is an object whose address is a link time constant.  */
342
343 static bool
344 fixed_address_object_p (tree obj)
345 {
346   return (TREE_CODE (obj) == VAR_DECL
347           && (TREE_STATIC (obj)
348               || DECL_EXTERNAL (obj))
349           && ! DECL_DLLIMPORT_P (obj));
350 }
351
352 /* If ADDR contains an address of object that is a link time constant,
353    move it to PARTS->symbol.  */
354
355 static void
356 move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
357 {
358   unsigned i;
359   tree val = NULL_TREE;
360
361   for (i = 0; i < addr->n; i++)
362     {
363       if (!double_int_one_p (addr->elts[i].coef))
364         continue;
365
366       val = addr->elts[i].val;
367       if (TREE_CODE (val) == ADDR_EXPR
368           && fixed_address_object_p (TREE_OPERAND (val, 0)))
369         break;
370     }
371
372   if (i == addr->n)
373     return;
374
375   parts->symbol = TREE_OPERAND (val, 0);
376   aff_combination_remove_elt (addr, i);
377 }
378
379 /* If ADDR contains an address of a dereferenced pointer, move it to
380    PARTS->base.  */
381
382 static void
383 move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
384 {
385   unsigned i;
386   tree val = NULL_TREE;
387
388   for (i = 0; i < addr->n; i++)
389     {
390       if (!double_int_one_p (addr->elts[i].coef))
391         continue;
392
393       val = addr->elts[i].val;
394       if (POINTER_TYPE_P (TREE_TYPE (val)))
395         break;
396     }
397
398   if (i == addr->n)
399     return;
400
401   parts->base = val;
402   aff_combination_remove_elt (addr, i);
403 }
404
405 /* Adds ELT to PARTS.  */
406
407 static void
408 add_to_parts (struct mem_address *parts, tree elt)
409 {
410   tree type;
411
412   if (!parts->index)
413     {
414       parts->index = fold_convert (sizetype, elt);
415       return;
416     }
417
418   if (!parts->base)
419     {
420       parts->base = elt;
421       return;
422     }
423
424   /* Add ELT to base.  */
425   type = TREE_TYPE (parts->base);
426   if (POINTER_TYPE_P (type))
427     parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
428                                parts->base,
429                                fold_convert (sizetype, elt));
430   else
431     parts->base = fold_build2 (PLUS_EXPR, type,
432                                parts->base, elt);
433 }
434
435 /* Finds the most expensive multiplication in ADDR that can be
436    expressed in an addressing mode and move the corresponding
437    element(s) to PARTS.  */
438
439 static void
440 most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
441                               bool speed)
442 {
443   HOST_WIDE_INT coef;
444   double_int best_mult, amult, amult_neg;
445   unsigned best_mult_cost = 0, acost;
446   tree mult_elt = NULL_TREE, elt;
447   unsigned i, j;
448   enum tree_code op_code;
449
450   best_mult = double_int_zero;
451   for (i = 0; i < addr->n; i++)
452     {
453       if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
454         continue;
455
456       /* FIXME: Should use the correct memory mode rather than Pmode.  */
457
458       coef = double_int_to_shwi (addr->elts[i].coef);
459       if (coef == 1
460           || !multiplier_allowed_in_address_p (coef, Pmode))
461         continue;
462
463       acost = multiply_by_cost (coef, Pmode, speed);
464
465       if (acost > best_mult_cost)
466         {
467           best_mult_cost = acost;
468           best_mult = addr->elts[i].coef;
469         }
470     }
471
472   if (!best_mult_cost)
473     return;
474
475   /* Collect elements multiplied by best_mult.  */
476   for (i = j = 0; i < addr->n; i++)
477     {
478       amult = addr->elts[i].coef;
479       amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
480  
481       if (double_int_equal_p (amult, best_mult))
482         op_code = PLUS_EXPR;
483       else if (double_int_equal_p (amult_neg, best_mult))
484         op_code = MINUS_EXPR;
485       else
486         {
487           addr->elts[j] = addr->elts[i];
488           j++;
489           continue;
490         }
491
492       elt = fold_convert (sizetype, addr->elts[i].val);
493       if (mult_elt)
494         mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
495       else if (op_code == PLUS_EXPR)
496         mult_elt = elt;
497       else
498         mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
499     }
500   addr->n = j;
501   
502   parts->index = mult_elt;
503   parts->step = double_int_to_tree (sizetype, best_mult);
504 }
505
506 /* Splits address ADDR into PARTS.
507    
508    TODO -- be more clever about the distribution of the elements of ADDR
509    to PARTS.  Some architectures do not support anything but single
510    register in address, possibly with a small integer offset; while
511    create_mem_ref will simplify the address to an acceptable shape
512    later, it would be more efficient to know that asking for complicated
513    addressing modes is useless.  */
514
515 static void
516 addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
517 {
518   tree part;
519   unsigned i;
520
521   parts->symbol = NULL_TREE;
522   parts->base = NULL_TREE;
523   parts->index = NULL_TREE;
524   parts->step = NULL_TREE;
525
526   if (!double_int_zero_p (addr->offset))
527     parts->offset = double_int_to_tree (sizetype, addr->offset);
528   else
529     parts->offset = NULL_TREE;
530
531   /* Try to find a symbol.  */
532   move_fixed_address_to_symbol (parts, addr);
533
534   /* First move the most expensive feasible multiplication
535      to index.  */
536   most_expensive_mult_to_index (parts, addr, speed);
537
538   /* Try to find a base of the reference.  Since at the moment
539      there is no reliable way how to distinguish between pointer and its
540      offset, this is just a guess.  */
541   if (!parts->symbol)
542     move_pointer_to_base (parts, addr);
543
544   /* Then try to process the remaining elements.  */
545   for (i = 0; i < addr->n; i++)
546     {
547       part = fold_convert (sizetype, addr->elts[i].val);
548       if (!double_int_one_p (addr->elts[i].coef))
549         part = fold_build2 (MULT_EXPR, sizetype, part,
550                             double_int_to_tree (sizetype, addr->elts[i].coef));
551       add_to_parts (parts, part);
552     }
553   if (addr->rest)
554     add_to_parts (parts, fold_convert (sizetype, addr->rest));
555 }
556
557 /* Force the PARTS to register.  */
558
559 static void
560 gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
561 {
562   if (parts->base)
563     parts->base = force_gimple_operand_gsi (gsi, parts->base,
564                                             true, NULL_TREE,
565                                             true, GSI_SAME_STMT);
566   if (parts->index)
567     parts->index = force_gimple_operand_gsi (gsi, parts->index,
568                                              true, NULL_TREE,
569                                              true, GSI_SAME_STMT);
570 }
571
572 /* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
573    computations are emitted in front of GSI.  TYPE is the mode
574    of created memory reference.  */
575
576 tree
577 create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
578                 bool speed)
579 {
580   tree mem_ref, tmp;
581   tree atype;
582   struct mem_address parts;
583
584   addr_to_parts (addr, &parts, speed);
585   gimplify_mem_ref_parts (gsi, &parts);
586   mem_ref = create_mem_ref_raw (type, &parts);
587   if (mem_ref)
588     return mem_ref;
589
590   /* The expression is too complicated.  Try making it simpler.  */
591
592   if (parts.step && !integer_onep (parts.step))
593     {
594       /* Move the multiplication to index.  */
595       gcc_assert (parts.index);
596       parts.index = force_gimple_operand_gsi (gsi,
597                                 fold_build2 (MULT_EXPR, sizetype,
598                                              parts.index, parts.step),
599                                 true, NULL_TREE, true, GSI_SAME_STMT);
600       parts.step = NULL_TREE;
601   
602       mem_ref = create_mem_ref_raw (type, &parts);
603       if (mem_ref)
604         return mem_ref;
605     }
606
607   if (parts.symbol)
608     {
609       tmp = build_addr (parts.symbol, current_function_decl);
610       gcc_assert (is_gimple_val (tmp));
611     
612       /* Add the symbol to base, eventually forcing it to register.  */
613       if (parts.base)
614         {
615           gcc_assert (useless_type_conversion_p
616                                 (sizetype, TREE_TYPE (parts.base)));
617
618           if (parts.index)
619             {
620               atype = TREE_TYPE (tmp);
621               parts.base = force_gimple_operand_gsi (gsi,
622                         fold_build2 (PLUS_EXPR, atype,
623                                      fold_convert (atype, parts.base),
624                                      tmp),
625                         true, NULL_TREE, true, GSI_SAME_STMT);
626             }
627           else
628             {
629               parts.index = parts.base;
630               parts.base = tmp;
631             }
632         }
633       else
634         parts.base = tmp;
635       parts.symbol = NULL_TREE;
636
637       mem_ref = create_mem_ref_raw (type, &parts);
638       if (mem_ref)
639         return mem_ref;
640     }
641
642   if (parts.index)
643     {
644       /* Add index to base.  */
645       if (parts.base)
646         {
647           atype = TREE_TYPE (parts.base);
648           parts.base = force_gimple_operand_gsi (gsi,
649                         fold_build2 (POINTER_PLUS_EXPR, atype,
650                                      parts.base,
651                                      parts.index),
652                         true, NULL_TREE, true, GSI_SAME_STMT);
653         }
654       else
655         parts.base = parts.index;
656       parts.index = NULL_TREE;
657
658       mem_ref = create_mem_ref_raw (type, &parts);
659       if (mem_ref)
660         return mem_ref;
661     }
662
663   if (parts.offset && !integer_zerop (parts.offset))
664     {
665       /* Try adding offset to base.  */
666       if (parts.base)
667         {
668           atype = TREE_TYPE (parts.base);
669           parts.base = force_gimple_operand_gsi (gsi, 
670                         fold_build2 (POINTER_PLUS_EXPR, atype,
671                                      parts.base,
672                                      fold_convert (sizetype, parts.offset)),
673                         true, NULL_TREE, true, GSI_SAME_STMT);
674         }
675       else
676         parts.base = parts.offset;
677
678       parts.offset = NULL_TREE;
679
680       mem_ref = create_mem_ref_raw (type, &parts);
681       if (mem_ref)
682         return mem_ref;
683     }
684
685   /* Verify that the address is in the simplest possible shape
686      (only a register).  If we cannot create such a memory reference,
687      something is really wrong.  */
688   gcc_assert (parts.symbol == NULL_TREE);
689   gcc_assert (parts.index == NULL_TREE);
690   gcc_assert (!parts.step || integer_onep (parts.step));
691   gcc_assert (!parts.offset || integer_zerop (parts.offset));
692   gcc_unreachable ();
693 }
694
695 /* Copies components of the address from OP to ADDR.  */
696
697 void
698 get_address_description (tree op, struct mem_address *addr)
699 {
700   addr->symbol = TMR_SYMBOL (op);
701   addr->base = TMR_BASE (op);
702   addr->index = TMR_INDEX (op);
703   addr->step = TMR_STEP (op);
704   addr->offset = TMR_OFFSET (op);
705 }
706
707 /* Copies the additional information attached to target_mem_ref FROM to TO.  */
708
709 void
710 copy_mem_ref_info (tree to, tree from)
711 {
712   /* Copy the annotation, to preserve the aliasing information.  */
713   TMR_TAG (to) = TMR_TAG (from);
714
715   /* And the info about the original reference.  */
716   TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
717 }
718
719 /* Move constants in target_mem_ref REF to offset.  Returns the new target
720    mem ref if anything changes, NULL_TREE otherwise.  */
721
722 tree
723 maybe_fold_tmr (tree ref)
724 {
725   struct mem_address addr;
726   bool changed = false;
727   tree ret, off;
728
729   get_address_description (ref, &addr);
730
731   if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
732     {
733       if (addr.offset)
734         addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
735                         addr.offset,
736                         fold_convert (sizetype, addr.base));
737       else
738         addr.offset = addr.base;
739
740       addr.base = NULL_TREE;
741       changed = true;
742     }
743
744   if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
745     {
746       off = addr.index;
747       if (addr.step)
748         {
749           off = fold_binary_to_constant (MULT_EXPR, sizetype,
750                                          off, addr.step);
751           addr.step = NULL_TREE;
752         }
753
754       if (addr.offset)
755         {
756           addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
757                                                  addr.offset, off);
758         }
759       else
760         addr.offset = off;
761
762       addr.index = NULL_TREE;
763       changed = true;
764     }
765
766   if (!changed)
767     return NULL_TREE;
768   
769   ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
770   if (!ret)
771     return NULL_TREE;
772
773   copy_mem_ref_info (ret, ref);
774   return ret;
775 }
776
777 /* Dump PARTS to FILE.  */
778
779 extern void dump_mem_address (FILE *, struct mem_address *);
780 void
781 dump_mem_address (FILE *file, struct mem_address *parts)
782 {
783   if (parts->symbol)
784     {
785       fprintf (file, "symbol: ");
786       print_generic_expr (file, parts->symbol, TDF_SLIM);
787       fprintf (file, "\n");
788     }
789   if (parts->base)
790     {
791       fprintf (file, "base: ");
792       print_generic_expr (file, parts->base, TDF_SLIM);
793       fprintf (file, "\n");
794     }
795   if (parts->index)
796     {
797       fprintf (file, "index: ");
798       print_generic_expr (file, parts->index, TDF_SLIM);
799       fprintf (file, "\n");
800     }
801   if (parts->step)
802     {
803       fprintf (file, "step: ");
804       print_generic_expr (file, parts->step, TDF_SLIM);
805       fprintf (file, "\n");
806     }
807   if (parts->offset)
808     {
809       fprintf (file, "offset: ");
810       print_generic_expr (file, parts->offset, TDF_SLIM);
811       fprintf (file, "\n");
812     }
813 }
814
815 #include "gt-tree-ssa-address.h"