OSDN Git Service

2009-10-26 Ben Elliston <bje@au.ibm.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, addr_space_t as,
309                  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_addr_space_p (mode, address, as);
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), TYPE_ADDR_SPACE (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 build6 (TARGET_MEM_REF, type,
337                  addr->symbol, addr->base, addr->index,
338                  addr->step, addr->offset, 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                                                ADDR_SPACE_GENERIC))
462         continue;
463
464       acost = multiply_by_cost (coef, Pmode, speed);
465
466       if (acost > best_mult_cost)
467         {
468           best_mult_cost = acost;
469           best_mult = addr->elts[i].coef;
470         }
471     }
472
473   if (!best_mult_cost)
474     return;
475
476   /* Collect elements multiplied by best_mult.  */
477   for (i = j = 0; i < addr->n; i++)
478     {
479       amult = addr->elts[i].coef;
480       amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
481  
482       if (double_int_equal_p (amult, best_mult))
483         op_code = PLUS_EXPR;
484       else if (double_int_equal_p (amult_neg, best_mult))
485         op_code = MINUS_EXPR;
486       else
487         {
488           addr->elts[j] = addr->elts[i];
489           j++;
490           continue;
491         }
492
493       elt = fold_convert (sizetype, addr->elts[i].val);
494       if (mult_elt)
495         mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
496       else if (op_code == PLUS_EXPR)
497         mult_elt = elt;
498       else
499         mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
500     }
501   addr->n = j;
502   
503   parts->index = mult_elt;
504   parts->step = double_int_to_tree (sizetype, best_mult);
505 }
506
507 /* Splits address ADDR into PARTS.
508    
509    TODO -- be more clever about the distribution of the elements of ADDR
510    to PARTS.  Some architectures do not support anything but single
511    register in address, possibly with a small integer offset; while
512    create_mem_ref will simplify the address to an acceptable shape
513    later, it would be more efficient to know that asking for complicated
514    addressing modes is useless.  */
515
516 static void
517 addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
518 {
519   tree part;
520   unsigned i;
521
522   parts->symbol = NULL_TREE;
523   parts->base = NULL_TREE;
524   parts->index = NULL_TREE;
525   parts->step = NULL_TREE;
526
527   if (!double_int_zero_p (addr->offset))
528     parts->offset = double_int_to_tree (sizetype, addr->offset);
529   else
530     parts->offset = NULL_TREE;
531
532   /* Try to find a symbol.  */
533   move_fixed_address_to_symbol (parts, addr);
534
535   /* First move the most expensive feasible multiplication
536      to index.  */
537   most_expensive_mult_to_index (parts, addr, speed);
538
539   /* Try to find a base of the reference.  Since at the moment
540      there is no reliable way how to distinguish between pointer and its
541      offset, this is just a guess.  */
542   if (!parts->symbol)
543     move_pointer_to_base (parts, addr);
544
545   /* Then try to process the remaining elements.  */
546   for (i = 0; i < addr->n; i++)
547     {
548       part = fold_convert (sizetype, addr->elts[i].val);
549       if (!double_int_one_p (addr->elts[i].coef))
550         part = fold_build2 (MULT_EXPR, sizetype, part,
551                             double_int_to_tree (sizetype, addr->elts[i].coef));
552       add_to_parts (parts, part);
553     }
554   if (addr->rest)
555     add_to_parts (parts, fold_convert (sizetype, addr->rest));
556 }
557
558 /* Force the PARTS to register.  */
559
560 static void
561 gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
562 {
563   if (parts->base)
564     parts->base = force_gimple_operand_gsi (gsi, parts->base,
565                                             true, NULL_TREE,
566                                             true, GSI_SAME_STMT);
567   if (parts->index)
568     parts->index = force_gimple_operand_gsi (gsi, parts->index,
569                                              true, NULL_TREE,
570                                              true, GSI_SAME_STMT);
571 }
572
573 /* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
574    computations are emitted in front of GSI.  TYPE is the mode
575    of created memory reference.  */
576
577 tree
578 create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
579                 bool speed)
580 {
581   tree mem_ref, tmp;
582   tree atype;
583   struct mem_address parts;
584
585   addr_to_parts (addr, &parts, speed);
586   gimplify_mem_ref_parts (gsi, &parts);
587   mem_ref = create_mem_ref_raw (type, &parts);
588   if (mem_ref)
589     return mem_ref;
590
591   /* The expression is too complicated.  Try making it simpler.  */
592
593   if (parts.step && !integer_onep (parts.step))
594     {
595       /* Move the multiplication to index.  */
596       gcc_assert (parts.index);
597       parts.index = force_gimple_operand_gsi (gsi,
598                                 fold_build2 (MULT_EXPR, sizetype,
599                                              parts.index, parts.step),
600                                 true, NULL_TREE, true, GSI_SAME_STMT);
601       parts.step = NULL_TREE;
602   
603       mem_ref = create_mem_ref_raw (type, &parts);
604       if (mem_ref)
605         return mem_ref;
606     }
607
608   if (parts.symbol)
609     {
610       tmp = build_addr (parts.symbol, current_function_decl);
611       gcc_assert (is_gimple_val (tmp));
612     
613       /* Add the symbol to base, eventually forcing it to register.  */
614       if (parts.base)
615         {
616           gcc_assert (useless_type_conversion_p
617                                 (sizetype, TREE_TYPE (parts.base)));
618
619           if (parts.index)
620             {
621               atype = TREE_TYPE (tmp);
622               parts.base = force_gimple_operand_gsi (gsi,
623                         fold_build2 (POINTER_PLUS_EXPR, atype,
624                                      tmp,
625                                      fold_convert (sizetype, parts.base)),
626                         true, NULL_TREE, true, GSI_SAME_STMT);
627             }
628           else
629             {
630               parts.index = parts.base;
631               parts.base = tmp;
632             }
633         }
634       else
635         parts.base = tmp;
636       parts.symbol = NULL_TREE;
637
638       mem_ref = create_mem_ref_raw (type, &parts);
639       if (mem_ref)
640         return mem_ref;
641     }
642
643   if (parts.index)
644     {
645       /* Add index to base.  */
646       if (parts.base)
647         {
648           atype = TREE_TYPE (parts.base);
649           parts.base = force_gimple_operand_gsi (gsi,
650                         fold_build2 (POINTER_PLUS_EXPR, atype,
651                                      parts.base,
652                                      parts.index),
653                         true, NULL_TREE, true, GSI_SAME_STMT);
654         }
655       else
656         parts.base = parts.index;
657       parts.index = NULL_TREE;
658
659       mem_ref = create_mem_ref_raw (type, &parts);
660       if (mem_ref)
661         return mem_ref;
662     }
663
664   if (parts.offset && !integer_zerop (parts.offset))
665     {
666       /* Try adding offset to base.  */
667       if (parts.base)
668         {
669           atype = TREE_TYPE (parts.base);
670           parts.base = force_gimple_operand_gsi (gsi, 
671                         fold_build2 (POINTER_PLUS_EXPR, atype,
672                                      parts.base,
673                                      fold_convert (sizetype, parts.offset)),
674                         true, NULL_TREE, true, GSI_SAME_STMT);
675         }
676       else
677         parts.base = parts.offset;
678
679       parts.offset = NULL_TREE;
680
681       mem_ref = create_mem_ref_raw (type, &parts);
682       if (mem_ref)
683         return mem_ref;
684     }
685
686   /* Verify that the address is in the simplest possible shape
687      (only a register).  If we cannot create such a memory reference,
688      something is really wrong.  */
689   gcc_assert (parts.symbol == NULL_TREE);
690   gcc_assert (parts.index == NULL_TREE);
691   gcc_assert (!parts.step || integer_onep (parts.step));
692   gcc_assert (!parts.offset || integer_zerop (parts.offset));
693   gcc_unreachable ();
694 }
695
696 /* Copies components of the address from OP to ADDR.  */
697
698 void
699 get_address_description (tree op, struct mem_address *addr)
700 {
701   addr->symbol = TMR_SYMBOL (op);
702   addr->base = TMR_BASE (op);
703   addr->index = TMR_INDEX (op);
704   addr->step = TMR_STEP (op);
705   addr->offset = TMR_OFFSET (op);
706 }
707
708 /* Copies the additional information attached to target_mem_ref FROM to TO.  */
709
710 void
711 copy_mem_ref_info (tree to, tree 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"