OSDN Git Service

2007-08-16 H.J. Lu <hongjiu.lu@intel.com>
[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 }
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   parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
426                              parts->base,
427                              fold_convert (sizetype, elt));
428 }
429
430 /* Finds the most expensive multiplication in ADDR that can be
431    expressed in an addressing mode and move the corresponding
432    element(s) to PARTS.  */
433
434 static void
435 most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr)
436 {
437   HOST_WIDE_INT coef;
438   double_int best_mult, amult, amult_neg;
439   unsigned best_mult_cost = 0, acost;
440   tree mult_elt = NULL_TREE, elt;
441   unsigned i, j;
442   enum tree_code op_code;
443
444   best_mult = double_int_zero;
445   for (i = 0; i < addr->n; i++)
446     {
447       if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
448         continue;
449
450       /* FIXME: Should use the correct memory mode rather than Pmode.  */
451
452       coef = double_int_to_shwi (addr->elts[i].coef);
453       if (coef == 1
454           || !multiplier_allowed_in_address_p (coef, Pmode))
455         continue;
456
457       acost = multiply_by_cost (coef, Pmode);
458
459       if (acost > best_mult_cost)
460         {
461           best_mult_cost = acost;
462           best_mult = addr->elts[i].coef;
463         }
464     }
465
466   if (!best_mult_cost)
467     return;
468
469   /* Collect elements multiplied by best_mult.  */
470   for (i = j = 0; i < addr->n; i++)
471     {
472       amult = addr->elts[i].coef;
473       amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
474  
475       if (double_int_equal_p (amult, best_mult))
476         op_code = PLUS_EXPR;
477       else if (double_int_equal_p (amult_neg, best_mult))
478         op_code = MINUS_EXPR;
479       else
480         {
481           addr->elts[j] = addr->elts[i];
482           j++;
483           continue;
484         }
485
486       elt = fold_convert (sizetype, addr->elts[i].val);
487       if (mult_elt)
488         mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
489       else if (op_code == PLUS_EXPR)
490         mult_elt = elt;
491       else
492         mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
493     }
494   addr->n = j;
495   
496   parts->index = mult_elt;
497   parts->step = double_int_to_tree (sizetype, best_mult);
498 }
499
500 /* Splits address ADDR into PARTS.
501    
502    TODO -- be more clever about the distribution of the elements of ADDR
503    to PARTS.  Some architectures do not support anything but single
504    register in address, possibly with a small integer offset; while
505    create_mem_ref will simplify the address to an acceptable shape
506    later, it would be more efficient to know that asking for complicated
507    addressing modes is useless.  */
508
509 static void
510 addr_to_parts (aff_tree *addr, struct mem_address *parts)
511 {
512   tree part;
513   unsigned i;
514
515   parts->symbol = NULL_TREE;
516   parts->base = NULL_TREE;
517   parts->index = NULL_TREE;
518   parts->step = NULL_TREE;
519
520   if (!double_int_zero_p (addr->offset))
521     parts->offset = double_int_to_tree (sizetype, addr->offset);
522   else
523     parts->offset = NULL_TREE;
524
525   /* Try to find a symbol.  */
526   move_fixed_address_to_symbol (parts, addr);
527
528   /* First move the most expensive feasible multiplication
529      to index.  */
530   most_expensive_mult_to_index (parts, addr);
531
532   /* Try to find a base of the reference.  Since at the moment
533      there is no reliable way how to distinguish between pointer and its
534      offset, this is just a guess.  */
535   if (!parts->symbol)
536     move_pointer_to_base (parts, addr);
537
538   /* Then try to process the remaining elements.  */
539   for (i = 0; i < addr->n; i++)
540     {
541       part = fold_convert (sizetype, addr->elts[i].val);
542       if (!double_int_one_p (addr->elts[i].coef))
543         part = fold_build2 (MULT_EXPR, sizetype, part,
544                             double_int_to_tree (sizetype, addr->elts[i].coef));
545       add_to_parts (parts, part);
546     }
547   if (addr->rest)
548     add_to_parts (parts, fold_convert (sizetype, addr->rest));
549 }
550
551 /* Force the PARTS to register.  */
552
553 static void
554 gimplify_mem_ref_parts (block_stmt_iterator *bsi, struct mem_address *parts)
555 {
556   if (parts->base)
557     parts->base = force_gimple_operand_bsi (bsi, parts->base,
558                                             true, NULL_TREE,
559                                             true, BSI_SAME_STMT);
560   if (parts->index)
561     parts->index = force_gimple_operand_bsi (bsi, parts->index,
562                                              true, NULL_TREE,
563                                              true, BSI_SAME_STMT);
564 }
565
566 /* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
567    computations are emitted in front of BSI.  TYPE is the mode
568    of created memory reference.  */
569
570 tree
571 create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr)
572 {
573   tree mem_ref, tmp;
574   tree atype;
575   struct mem_address parts;
576
577   addr_to_parts (addr, &parts);
578   gimplify_mem_ref_parts (bsi, &parts);
579   mem_ref = create_mem_ref_raw (type, &parts);
580   if (mem_ref)
581     return mem_ref;
582
583   /* The expression is too complicated.  Try making it simpler.  */
584
585   if (parts.step && !integer_onep (parts.step))
586     {
587       /* Move the multiplication to index.  */
588       gcc_assert (parts.index);
589       parts.index = force_gimple_operand_bsi (bsi,
590                                 fold_build2 (MULT_EXPR, sizetype,
591                                              parts.index, parts.step),
592                                 true, NULL_TREE, true, BSI_SAME_STMT);
593       parts.step = NULL_TREE;
594   
595       mem_ref = create_mem_ref_raw (type, &parts);
596       if (mem_ref)
597         return mem_ref;
598     }
599
600   if (parts.symbol)
601     {
602       tmp = build_addr (parts.symbol, current_function_decl);
603       gcc_assert (is_gimple_val (tmp));
604     
605       /* Add the symbol to base, eventually forcing it to register.  */
606       if (parts.base)
607         {
608           gcc_assert (useless_type_conversion_p
609                                 (sizetype, TREE_TYPE (parts.base)));
610
611           if (parts.index)
612             {
613               atype = TREE_TYPE (tmp);
614               parts.base = force_gimple_operand_bsi (bsi,
615                         fold_build2 (PLUS_EXPR, atype,
616                                      fold_convert (atype, parts.base),
617                                      tmp),
618                         true, NULL_TREE, true, BSI_SAME_STMT);
619             }
620           else
621             {
622               parts.index = parts.base;
623               parts.base = tmp;
624             }
625         }
626       else
627         parts.base = tmp;
628       parts.symbol = NULL_TREE;
629
630       mem_ref = create_mem_ref_raw (type, &parts);
631       if (mem_ref)
632         return mem_ref;
633     }
634
635   if (parts.index)
636     {
637       /* Add index to base.  */
638       if (parts.base)
639         {
640           atype = TREE_TYPE (parts.base);
641           parts.base = force_gimple_operand_bsi (bsi,
642                         fold_build2 (PLUS_EXPR, atype,
643                                      parts.base,
644                                      fold_convert (atype, parts.index)),
645                         true, NULL_TREE, true, BSI_SAME_STMT);
646         }
647       else
648         parts.base = parts.index;
649       parts.index = NULL_TREE;
650
651       mem_ref = create_mem_ref_raw (type, &parts);
652       if (mem_ref)
653         return mem_ref;
654     }
655
656   if (parts.offset && !integer_zerop (parts.offset))
657     {
658       /* Try adding offset to base.  */
659       if (parts.base)
660         {
661           atype = TREE_TYPE (parts.base);
662           parts.base = force_gimple_operand_bsi (bsi, 
663                         fold_build2 (POINTER_PLUS_EXPR, atype,
664                                      parts.base,
665                                      fold_convert (sizetype, parts.offset)),
666                         true, NULL_TREE, true, BSI_SAME_STMT);
667         }
668       else
669         parts.base = parts.offset;
670
671       parts.offset = NULL_TREE;
672
673       mem_ref = create_mem_ref_raw (type, &parts);
674       if (mem_ref)
675         return mem_ref;
676     }
677
678   /* Verify that the address is in the simplest possible shape
679      (only a register).  If we cannot create such a memory reference,
680      something is really wrong.  */
681   gcc_assert (parts.symbol == NULL_TREE);
682   gcc_assert (parts.index == NULL_TREE);
683   gcc_assert (!parts.step || integer_onep (parts.step));
684   gcc_assert (!parts.offset || integer_zerop (parts.offset));
685   gcc_unreachable ();
686 }
687
688 /* Copies components of the address from OP to ADDR.  */
689
690 void
691 get_address_description (tree op, struct mem_address *addr)
692 {
693   addr->symbol = TMR_SYMBOL (op);
694   addr->base = TMR_BASE (op);
695   addr->index = TMR_INDEX (op);
696   addr->step = TMR_STEP (op);
697   addr->offset = TMR_OFFSET (op);
698 }
699
700 /* Copies the additional information attached to target_mem_ref FROM to TO.  */
701
702 void
703 copy_mem_ref_info (tree to, tree from)
704 {
705   /* Copy the annotation, to preserve the aliasing information.  */
706   TMR_TAG (to) = TMR_TAG (from);
707
708   /* And the info about the original reference.  */
709   TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
710 }
711
712 /* Move constants in target_mem_ref REF to offset.  Returns the new target
713    mem ref if anything changes, NULL_TREE otherwise.  */
714
715 tree
716 maybe_fold_tmr (tree ref)
717 {
718   struct mem_address addr;
719   bool changed = false;
720   tree ret, off;
721
722   get_address_description (ref, &addr);
723
724   if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
725     {
726       if (addr.offset)
727         addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
728                         addr.offset,
729                         fold_convert (sizetype, addr.base));
730       else
731         addr.offset = addr.base;
732
733       addr.base = NULL_TREE;
734       changed = true;
735     }
736
737   if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
738     {
739       off = addr.index;
740       if (addr.step)
741         {
742           off = fold_binary_to_constant (MULT_EXPR, sizetype,
743                                          off, addr.step);
744           addr.step = NULL_TREE;
745         }
746
747       if (addr.offset)
748         {
749           addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
750                                                  addr.offset, off);
751         }
752       else
753         addr.offset = off;
754
755       addr.index = NULL_TREE;
756       changed = true;
757     }
758
759   if (!changed)
760     return NULL_TREE;
761   
762   ret = create_mem_ref_raw (TREE_TYPE (ref), &addr);
763   if (!ret)
764     return NULL_TREE;
765
766   copy_mem_ref_info (ret, ref);
767   return ret;
768 }
769
770 /* Dump PARTS to FILE.  */
771
772 extern void dump_mem_address (FILE *, struct mem_address *);
773 void
774 dump_mem_address (FILE *file, struct mem_address *parts)
775 {
776   if (parts->symbol)
777     {
778       fprintf (file, "symbol: ");
779       print_generic_expr (file, parts->symbol, TDF_SLIM);
780       fprintf (file, "\n");
781     }
782   if (parts->base)
783     {
784       fprintf (file, "base: ");
785       print_generic_expr (file, parts->base, TDF_SLIM);
786       fprintf (file, "\n");
787     }
788   if (parts->index)
789     {
790       fprintf (file, "index: ");
791       print_generic_expr (file, parts->index, TDF_SLIM);
792       fprintf (file, "\n");
793     }
794   if (parts->step)
795     {
796       fprintf (file, "step: ");
797       print_generic_expr (file, parts->step, TDF_SLIM);
798       fprintf (file, "\n");
799     }
800   if (parts->offset)
801     {
802       fprintf (file, "offset: ");
803       print_generic_expr (file, parts->offset, TDF_SLIM);
804       fprintf (file, "\n");
805     }
806 }
807
808 #include "gt-tree-ssa-address.h"