OSDN Git Service

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