OSDN Git Service

2008-07-28 Richard Guenther <rguenther@suse.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 {
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);
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)
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);
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 {
578   tree mem_ref, tmp;
579   tree atype;
580   struct mem_address parts;
581
582   addr_to_parts (addr, &parts);
583   gimplify_mem_ref_parts (gsi, &parts);
584   mem_ref = create_mem_ref_raw (type, &parts);
585   if (mem_ref)
586     return mem_ref;
587
588   /* The expression is too complicated.  Try making it simpler.  */
589
590   if (parts.step && !integer_onep (parts.step))
591     {
592       /* Move the multiplication to index.  */
593       gcc_assert (parts.index);
594       parts.index = force_gimple_operand_gsi (gsi,
595                                 fold_build2 (MULT_EXPR, sizetype,
596                                              parts.index, parts.step),
597                                 true, NULL_TREE, true, GSI_SAME_STMT);
598       parts.step = NULL_TREE;
599   
600       mem_ref = create_mem_ref_raw (type, &parts);
601       if (mem_ref)
602         return mem_ref;
603     }
604
605   if (parts.symbol)
606     {
607       tmp = build_addr (parts.symbol, current_function_decl);
608       gcc_assert (is_gimple_val (tmp));
609     
610       /* Add the symbol to base, eventually forcing it to register.  */
611       if (parts.base)
612         {
613           gcc_assert (useless_type_conversion_p
614                                 (sizetype, TREE_TYPE (parts.base)));
615
616           if (parts.index)
617             {
618               atype = TREE_TYPE (tmp);
619               parts.base = force_gimple_operand_gsi (gsi,
620                         fold_build2 (PLUS_EXPR, atype,
621                                      fold_convert (atype, parts.base),
622                                      tmp),
623                         true, NULL_TREE, true, GSI_SAME_STMT);
624             }
625           else
626             {
627               parts.index = parts.base;
628               parts.base = tmp;
629             }
630         }
631       else
632         parts.base = tmp;
633       parts.symbol = NULL_TREE;
634
635       mem_ref = create_mem_ref_raw (type, &parts);
636       if (mem_ref)
637         return mem_ref;
638     }
639
640   if (parts.index)
641     {
642       /* Add index to base.  */
643       if (parts.base)
644         {
645           atype = TREE_TYPE (parts.base);
646           parts.base = force_gimple_operand_gsi (gsi,
647                         fold_build2 (POINTER_PLUS_EXPR, atype,
648                                      parts.base,
649                                      parts.index),
650                         true, NULL_TREE, true, GSI_SAME_STMT);
651         }
652       else
653         parts.base = parts.index;
654       parts.index = NULL_TREE;
655
656       mem_ref = create_mem_ref_raw (type, &parts);
657       if (mem_ref)
658         return mem_ref;
659     }
660
661   if (parts.offset && !integer_zerop (parts.offset))
662     {
663       /* Try adding offset to base.  */
664       if (parts.base)
665         {
666           atype = TREE_TYPE (parts.base);
667           parts.base = force_gimple_operand_gsi (gsi, 
668                         fold_build2 (POINTER_PLUS_EXPR, atype,
669                                      parts.base,
670                                      fold_convert (sizetype, parts.offset)),
671                         true, NULL_TREE, true, GSI_SAME_STMT);
672         }
673       else
674         parts.base = parts.offset;
675
676       parts.offset = NULL_TREE;
677
678       mem_ref = create_mem_ref_raw (type, &parts);
679       if (mem_ref)
680         return mem_ref;
681     }
682
683   /* Verify that the address is in the simplest possible shape
684      (only a register).  If we cannot create such a memory reference,
685      something is really wrong.  */
686   gcc_assert (parts.symbol == NULL_TREE);
687   gcc_assert (parts.index == NULL_TREE);
688   gcc_assert (!parts.step || integer_onep (parts.step));
689   gcc_assert (!parts.offset || integer_zerop (parts.offset));
690   gcc_unreachable ();
691 }
692
693 /* Copies components of the address from OP to ADDR.  */
694
695 void
696 get_address_description (tree op, struct mem_address *addr)
697 {
698   addr->symbol = TMR_SYMBOL (op);
699   addr->base = TMR_BASE (op);
700   addr->index = TMR_INDEX (op);
701   addr->step = TMR_STEP (op);
702   addr->offset = TMR_OFFSET (op);
703 }
704
705 /* Copies the additional information attached to target_mem_ref FROM to TO.  */
706
707 void
708 copy_mem_ref_info (tree to, tree from)
709 {
710   /* Copy the annotation, to preserve the aliasing information.  */
711   TMR_TAG (to) = TMR_TAG (from);
712
713   /* And the info about the original reference.  */
714   TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
715 }
716
717 /* Move constants in target_mem_ref REF to offset.  Returns the new target
718    mem ref if anything changes, NULL_TREE otherwise.  */
719
720 tree
721 maybe_fold_tmr (tree ref)
722 {
723   struct mem_address addr;
724   bool changed = false;
725   tree ret, off;
726
727   get_address_description (ref, &addr);
728
729   if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
730     {
731       if (addr.offset)
732         addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
733                         addr.offset,
734                         fold_convert (sizetype, addr.base));
735       else
736         addr.offset = addr.base;
737
738       addr.base = NULL_TREE;
739       changed = true;
740     }
741
742   if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
743     {
744       off = addr.index;
745       if (addr.step)
746         {
747           off = fold_binary_to_constant (MULT_EXPR, sizetype,
748                                          off, addr.step);
749           addr.step = NULL_TREE;
750         }
751
752       if (addr.offset)
753         {
754           addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
755                                                  addr.offset, off);
756         }
757       else
758         addr.offset = off;
759
760       addr.index = NULL_TREE;
761       changed = true;
762     }
763
764   if (!changed)
765     return NULL_TREE;
766   
767   ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
768   if (!ret)
769     return NULL_TREE;
770
771   copy_mem_ref_info (ret, ref);
772   return ret;
773 }
774
775 /* Dump PARTS to FILE.  */
776
777 extern void dump_mem_address (FILE *, struct mem_address *);
778 void
779 dump_mem_address (FILE *file, struct mem_address *parts)
780 {
781   if (parts->symbol)
782     {
783       fprintf (file, "symbol: ");
784       print_generic_expr (file, parts->symbol, TDF_SLIM);
785       fprintf (file, "\n");
786     }
787   if (parts->base)
788     {
789       fprintf (file, "base: ");
790       print_generic_expr (file, parts->base, TDF_SLIM);
791       fprintf (file, "\n");
792     }
793   if (parts->index)
794     {
795       fprintf (file, "index: ");
796       print_generic_expr (file, parts->index, TDF_SLIM);
797       fprintf (file, "\n");
798     }
799   if (parts->step)
800     {
801       fprintf (file, "step: ");
802       print_generic_expr (file, parts->step, TDF_SLIM);
803       fprintf (file, "\n");
804     }
805   if (parts->offset)
806     {
807       fprintf (file, "offset: ");
808       print_generic_expr (file, parts->offset, TDF_SLIM);
809       fprintf (file, "\n");
810     }
811 }
812
813 #include "gt-tree-ssa-address.h"