OSDN Git Service

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