OSDN Git Service

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