OSDN Git Service

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