OSDN Git Service

2010-07-06 Uros Bizjak <ubizjak@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-address.c
1 /* Memory address lowering and addressing mode selection.
2    Copyright (C) 2004, 2006, 2007, 2008, 2009, 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 "tm_p.h"
30 #include "basic-block.h"
31 #include "output.h"
32 #include "tree-pretty-print.h"
33 #include "tree-flow.h"
34 #include "tree-dump.h"
35 #include "tree-pass.h"
36 #include "timevar.h"
37 #include "flags.h"
38 #include "tree-inline.h"
39 #include "tree-affine.h"
40
41 /* FIXME: We compute address costs using RTL.  */
42 #include "insn-config.h"
43 #include "rtl.h"
44 #include "recog.h"
45 #include "expr.h"
46 #include "ggc.h"
47 #include "target.h"
48
49 /* TODO -- handling of symbols (according to Richard Hendersons
50    comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
51
52    There are at least 5 different kinds of symbols that we can run up against:
53
54      (1) binds_local_p, small data area.
55      (2) binds_local_p, eg local statics
56      (3) !binds_local_p, eg global variables
57      (4) thread local, local_exec
58      (5) thread local, !local_exec
59
60    Now, (1) won't appear often in an array context, but it certainly can.
61    All you have to do is set -GN high enough, or explicitly mark any
62    random object __attribute__((section (".sdata"))).
63
64    All of these affect whether or not a symbol is in fact a valid address.
65    The only one tested here is (3).  And that result may very well
66    be incorrect for (4) or (5).
67
68    An incorrect result here does not cause incorrect results out the
69    back end, because the expander in expr.c validizes the address.  However
70    it would be nice to improve the handling here in order to produce more
71    precise results.  */
72
73 /* A "template" for memory address, used to determine whether the address is
74    valid for mode.  */
75
76 typedef struct GTY (()) mem_addr_template {
77   rtx ref;                      /* The template.  */
78   rtx * GTY ((skip)) step_p;    /* The point in template where the step should be
79                                    filled in.  */
80   rtx * GTY ((skip)) off_p;     /* The point in template where the offset should
81                                    be filled in.  */
82 } mem_addr_template;
83
84 DEF_VEC_O (mem_addr_template);
85 DEF_VEC_ALLOC_O (mem_addr_template, gc);
86
87 /* The templates.  Each of the low five bits of the index corresponds to one
88    component of TARGET_MEM_REF being present, while the high bits identify
89    the address space.  See TEMPL_IDX.  */
90
91 static GTY(()) VEC (mem_addr_template, gc) *mem_addr_template_list;
92
93 #define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \
94   (((int) (AS) << 5) \
95    | ((SYMBOL != 0) << 4) \
96    | ((BASE != 0) << 3) \
97    | ((INDEX != 0) << 2) \
98    | ((STEP != 0) << 1) \
99    | (OFFSET != 0))
100
101 /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
102    STEP and OFFSET to *ADDR using address mode ADDRESS_MODE.  Stores pointers
103    to where step is placed to *STEP_P and offset to *OFFSET_P.  */
104
105 static void
106 gen_addr_rtx (enum machine_mode address_mode,
107               rtx symbol, rtx base, rtx index, rtx step, rtx offset,
108               rtx *addr, rtx **step_p, rtx **offset_p)
109 {
110   rtx act_elem;
111
112   *addr = NULL_RTX;
113   if (step_p)
114     *step_p = NULL;
115   if (offset_p)
116     *offset_p = NULL;
117
118   if (index)
119     {
120       act_elem = index;
121       if (step)
122         {
123           act_elem = gen_rtx_MULT (address_mode, act_elem, step);
124
125           if (step_p)
126             *step_p = &XEXP (act_elem, 1);
127         }
128
129       *addr = act_elem;
130     }
131
132   if (base)
133     {
134       if (*addr)
135         *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
136       else
137         *addr = base;
138     }
139
140   if (symbol)
141     {
142       act_elem = symbol;
143       if (offset)
144         {
145           act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
146
147           if (offset_p)
148             *offset_p = &XEXP (act_elem, 1);
149
150           if (GET_CODE (symbol) == SYMBOL_REF
151               || GET_CODE (symbol) == LABEL_REF
152               || GET_CODE (symbol) == CONST)
153             act_elem = gen_rtx_CONST (address_mode, act_elem);
154         }
155
156       if (*addr)
157         *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
158       else
159         *addr = act_elem;
160     }
161   else if (offset)
162     {
163       if (*addr)
164         {
165           *addr = gen_rtx_PLUS (address_mode, *addr, offset);
166           if (offset_p)
167             *offset_p = &XEXP (*addr, 1);
168         }
169       else
170         {
171           *addr = offset;
172           if (offset_p)
173             *offset_p = addr;
174         }
175     }
176
177   if (!*addr)
178     *addr = const0_rtx;
179 }
180
181 /* Returns address for TARGET_MEM_REF with parameters given by ADDR
182    in address space AS.
183    If REALLY_EXPAND is false, just make fake registers instead
184    of really expanding the operands, and perform the expansion in-place
185    by using one of the "templates".  */
186
187 rtx
188 addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
189                   bool really_expand)
190 {
191   enum machine_mode address_mode = targetm.addr_space.address_mode (as);
192   rtx address, sym, bse, idx, st, off;
193   struct mem_addr_template *templ;
194
195   if (addr->step && !integer_onep (addr->step))
196     st = immed_double_int_const (tree_to_double_int (addr->step), address_mode);
197   else
198     st = NULL_RTX;
199
200   if (addr->offset && !integer_zerop (addr->offset))
201     off = immed_double_int_const (tree_to_double_int (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, tree alias_ptr_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   /* If possible use a plain MEM_REF instead of a TARGET_MEM_REF.  */
353   if (alias_ptr_type
354       && !addr->index
355       && !addr->step)
356     {
357       tree base, offset;
358       gcc_assert (!addr->symbol ^ !addr->base);
359       if (addr->symbol)
360         base = build_fold_addr_expr (addr->symbol);
361       else
362         base = addr->base;
363       if (addr->offset)
364         offset = fold_convert (alias_ptr_type, addr->offset);
365       else
366         offset = build_int_cst (alias_ptr_type, 0);
367       return fold_build2 (MEM_REF, type, base, offset);
368     }
369
370   return build6 (TARGET_MEM_REF, type,
371                  addr->symbol, addr->base, addr->index,
372                  addr->step, addr->offset, NULL);
373 }
374
375 /* Returns true if OBJ is an object whose address is a link time constant.  */
376
377 static bool
378 fixed_address_object_p (tree obj)
379 {
380   return (TREE_CODE (obj) == VAR_DECL
381           && (TREE_STATIC (obj)
382               || DECL_EXTERNAL (obj))
383           && ! DECL_DLLIMPORT_P (obj));
384 }
385
386 /* If ADDR contains an address of object that is a link time constant,
387    move it to PARTS->symbol.  */
388
389 static void
390 move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
391 {
392   unsigned i;
393   tree val = NULL_TREE;
394
395   for (i = 0; i < addr->n; i++)
396     {
397       if (!double_int_one_p (addr->elts[i].coef))
398         continue;
399
400       val = addr->elts[i].val;
401       if (TREE_CODE (val) == ADDR_EXPR
402           && fixed_address_object_p (TREE_OPERAND (val, 0)))
403         break;
404     }
405
406   if (i == addr->n)
407     return;
408
409   parts->symbol = TREE_OPERAND (val, 0);
410   aff_combination_remove_elt (addr, i);
411 }
412
413 /* If ADDR contains an instance of BASE_HINT, move it to PARTS->base.  */
414
415 static void
416 move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
417                    aff_tree *addr)
418 {
419   unsigned i;
420   tree val = NULL_TREE;
421   int qual;
422
423   for (i = 0; i < addr->n; i++)
424     {
425       if (!double_int_one_p (addr->elts[i].coef))
426         continue;
427
428       val = addr->elts[i].val;
429       if (operand_equal_p (val, base_hint, 0))
430         break;
431     }
432
433   if (i == addr->n)
434     return;
435
436   /* Cast value to appropriate pointer type.  We cannot use a pointer
437      to TYPE directly, as the back-end will assume registers of pointer
438      type are aligned, and just the base itself may not actually be.
439      We use void pointer to the type's address space instead.  */
440   qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
441   type = build_qualified_type (void_type_node, qual);
442   parts->base = fold_convert (build_pointer_type (type), val);
443   aff_combination_remove_elt (addr, i);
444 }
445
446 /* If ADDR contains an address of a dereferenced pointer, move it to
447    PARTS->base.  */
448
449 static void
450 move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
451 {
452   unsigned i;
453   tree val = NULL_TREE;
454
455   for (i = 0; i < addr->n; i++)
456     {
457       if (!double_int_one_p (addr->elts[i].coef))
458         continue;
459
460       val = addr->elts[i].val;
461       if (POINTER_TYPE_P (TREE_TYPE (val)))
462         break;
463     }
464
465   if (i == addr->n)
466     return;
467
468   parts->base = val;
469   aff_combination_remove_elt (addr, i);
470 }
471
472 /* Adds ELT to PARTS.  */
473
474 static void
475 add_to_parts (struct mem_address *parts, tree elt)
476 {
477   tree type;
478
479   if (!parts->index)
480     {
481       parts->index = fold_convert (sizetype, elt);
482       return;
483     }
484
485   if (!parts->base)
486     {
487       parts->base = elt;
488       return;
489     }
490
491   /* Add ELT to base.  */
492   type = TREE_TYPE (parts->base);
493   if (POINTER_TYPE_P (type))
494     parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
495                                parts->base,
496                                fold_convert (sizetype, elt));
497   else
498     parts->base = fold_build2 (PLUS_EXPR, type,
499                                parts->base, elt);
500 }
501
502 /* Finds the most expensive multiplication in ADDR that can be
503    expressed in an addressing mode and move the corresponding
504    element(s) to PARTS.  */
505
506 static void
507 most_expensive_mult_to_index (tree type, struct mem_address *parts,
508                               aff_tree *addr, bool speed)
509 {
510   addr_space_t as = TYPE_ADDR_SPACE (type);
511   enum machine_mode address_mode = targetm.addr_space.address_mode (as);
512   HOST_WIDE_INT coef;
513   double_int best_mult, amult, amult_neg;
514   unsigned best_mult_cost = 0, acost;
515   tree mult_elt = NULL_TREE, elt;
516   unsigned i, j;
517   enum tree_code op_code;
518
519   best_mult = double_int_zero;
520   for (i = 0; i < addr->n; i++)
521     {
522       if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
523         continue;
524
525       coef = double_int_to_shwi (addr->elts[i].coef);
526       if (coef == 1
527           || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
528         continue;
529
530       acost = multiply_by_cost (coef, address_mode, speed);
531
532       if (acost > best_mult_cost)
533         {
534           best_mult_cost = acost;
535           best_mult = addr->elts[i].coef;
536         }
537     }
538
539   if (!best_mult_cost)
540     return;
541
542   /* Collect elements multiplied by best_mult.  */
543   for (i = j = 0; i < addr->n; i++)
544     {
545       amult = addr->elts[i].coef;
546       amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr);
547
548       if (double_int_equal_p (amult, best_mult))
549         op_code = PLUS_EXPR;
550       else if (double_int_equal_p (amult_neg, best_mult))
551         op_code = MINUS_EXPR;
552       else
553         {
554           addr->elts[j] = addr->elts[i];
555           j++;
556           continue;
557         }
558
559       elt = fold_convert (sizetype, addr->elts[i].val);
560       if (mult_elt)
561         mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
562       else if (op_code == PLUS_EXPR)
563         mult_elt = elt;
564       else
565         mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
566     }
567   addr->n = j;
568
569   parts->index = mult_elt;
570   parts->step = double_int_to_tree (sizetype, best_mult);
571 }
572
573 /* Splits address ADDR for a memory access of type TYPE into PARTS.
574    If BASE_HINT is non-NULL, it specifies an SSA name to be used
575    preferentially as base of the reference.
576
577    TODO -- be more clever about the distribution of the elements of ADDR
578    to PARTS.  Some architectures do not support anything but single
579    register in address, possibly with a small integer offset; while
580    create_mem_ref will simplify the address to an acceptable shape
581    later, it would be more efficient to know that asking for complicated
582    addressing modes is useless.  */
583
584 static void
585 addr_to_parts (tree type, aff_tree *addr, tree base_hint,
586                struct mem_address *parts, bool speed)
587 {
588   tree part;
589   unsigned i;
590
591   parts->symbol = NULL_TREE;
592   parts->base = NULL_TREE;
593   parts->index = NULL_TREE;
594   parts->step = NULL_TREE;
595
596   if (!double_int_zero_p (addr->offset))
597     parts->offset = double_int_to_tree (sizetype, addr->offset);
598   else
599     parts->offset = NULL_TREE;
600
601   /* Try to find a symbol.  */
602   move_fixed_address_to_symbol (parts, addr);
603
604   /* First move the most expensive feasible multiplication
605      to index.  */
606   most_expensive_mult_to_index (type, parts, addr, speed);
607
608   /* Try to find a base of the reference.  Since at the moment
609      there is no reliable way how to distinguish between pointer and its
610      offset, this is just a guess.  */
611   if (!parts->symbol && base_hint)
612     move_hint_to_base (type, parts, base_hint, addr);
613   if (!parts->symbol && !parts->base)
614     move_pointer_to_base (parts, addr);
615
616   /* Then try to process the remaining elements.  */
617   for (i = 0; i < addr->n; i++)
618     {
619       part = fold_convert (sizetype, addr->elts[i].val);
620       if (!double_int_one_p (addr->elts[i].coef))
621         part = fold_build2 (MULT_EXPR, sizetype, part,
622                             double_int_to_tree (sizetype, addr->elts[i].coef));
623       add_to_parts (parts, part);
624     }
625   if (addr->rest)
626     add_to_parts (parts, fold_convert (sizetype, addr->rest));
627 }
628
629 /* Force the PARTS to register.  */
630
631 static void
632 gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
633 {
634   if (parts->base)
635     parts->base = force_gimple_operand_gsi (gsi, parts->base,
636                                             true, NULL_TREE,
637                                             true, GSI_SAME_STMT);
638   if (parts->index)
639     parts->index = force_gimple_operand_gsi (gsi, parts->index,
640                                              true, NULL_TREE,
641                                              true, GSI_SAME_STMT);
642 }
643
644 /* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
645    computations are emitted in front of GSI.  TYPE is the mode
646    of created memory reference.  */
647
648 tree
649 create_mem_ref (gimple_stmt_iterator *gsi, tree type, tree alias_ptr_type,
650                 aff_tree *addr, tree base_hint, bool speed)
651 {
652   tree mem_ref, tmp;
653   tree atype;
654   struct mem_address parts;
655
656   addr_to_parts (type, addr, base_hint, &parts, speed);
657   gimplify_mem_ref_parts (gsi, &parts);
658   mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
659   if (mem_ref)
660     return mem_ref;
661
662   /* The expression is too complicated.  Try making it simpler.  */
663
664   if (parts.step && !integer_onep (parts.step))
665     {
666       /* Move the multiplication to index.  */
667       gcc_assert (parts.index);
668       parts.index = force_gimple_operand_gsi (gsi,
669                                 fold_build2 (MULT_EXPR, sizetype,
670                                              parts.index, parts.step),
671                                 true, NULL_TREE, true, GSI_SAME_STMT);
672       parts.step = NULL_TREE;
673
674       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
675       if (mem_ref)
676         return mem_ref;
677     }
678
679   if (parts.symbol)
680     {
681       tmp = build_addr (parts.symbol, current_function_decl);
682       gcc_assert (is_gimple_val (tmp));
683
684       /* Add the symbol to base, eventually forcing it to register.  */
685       if (parts.base)
686         {
687           gcc_assert (useless_type_conversion_p
688                                 (sizetype, TREE_TYPE (parts.base)));
689
690           if (parts.index)
691             {
692               atype = TREE_TYPE (tmp);
693               parts.base = force_gimple_operand_gsi (gsi,
694                         fold_build2 (POINTER_PLUS_EXPR, atype,
695                                      tmp,
696                                      fold_convert (sizetype, parts.base)),
697                         true, NULL_TREE, true, GSI_SAME_STMT);
698             }
699           else
700             {
701               parts.index = parts.base;
702               parts.base = tmp;
703             }
704         }
705       else
706         parts.base = tmp;
707       parts.symbol = NULL_TREE;
708
709       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
710       if (mem_ref)
711         return mem_ref;
712     }
713
714   if (parts.index)
715     {
716       /* Add index to base.  */
717       if (parts.base)
718         {
719           atype = TREE_TYPE (parts.base);
720           parts.base = force_gimple_operand_gsi (gsi,
721                         fold_build2 (POINTER_PLUS_EXPR, atype,
722                                      parts.base,
723                                      parts.index),
724                         true, NULL_TREE, true, GSI_SAME_STMT);
725         }
726       else
727         parts.base = parts.index;
728       parts.index = NULL_TREE;
729
730       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
731       if (mem_ref)
732         return mem_ref;
733     }
734
735   if (parts.offset && !integer_zerop (parts.offset))
736     {
737       /* Try adding offset to base.  */
738       if (parts.base)
739         {
740           atype = TREE_TYPE (parts.base);
741           parts.base = force_gimple_operand_gsi (gsi,
742                         fold_build2 (POINTER_PLUS_EXPR, atype,
743                                      parts.base,
744                                      fold_convert (sizetype, parts.offset)),
745                         true, NULL_TREE, true, GSI_SAME_STMT);
746         }
747       else
748         parts.base = parts.offset;
749
750       parts.offset = NULL_TREE;
751
752       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
753       if (mem_ref)
754         return mem_ref;
755     }
756
757   /* Verify that the address is in the simplest possible shape
758      (only a register).  If we cannot create such a memory reference,
759      something is really wrong.  */
760   gcc_assert (parts.symbol == NULL_TREE);
761   gcc_assert (parts.index == NULL_TREE);
762   gcc_assert (!parts.step || integer_onep (parts.step));
763   gcc_assert (!parts.offset || integer_zerop (parts.offset));
764   gcc_unreachable ();
765 }
766
767 /* Copies components of the address from OP to ADDR.  */
768
769 void
770 get_address_description (tree op, struct mem_address *addr)
771 {
772   addr->symbol = TMR_SYMBOL (op);
773   addr->base = TMR_BASE (op);
774   addr->index = TMR_INDEX (op);
775   addr->step = TMR_STEP (op);
776   addr->offset = TMR_OFFSET (op);
777 }
778
779 /* Copies the additional information attached to target_mem_ref FROM to TO.  */
780
781 void
782 copy_mem_ref_info (tree to, tree from)
783 {
784   /* And the info about the original reference.  */
785   TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
786   TREE_SIDE_EFFECTS (to) = TREE_SIDE_EFFECTS (from);
787   TREE_THIS_VOLATILE (to) = TREE_THIS_VOLATILE (from);
788 }
789
790 /* Move constants in target_mem_ref REF to offset.  Returns the new target
791    mem ref if anything changes, NULL_TREE otherwise.  */
792
793 tree
794 maybe_fold_tmr (tree ref)
795 {
796   struct mem_address addr;
797   bool changed = false;
798   tree ret, off;
799
800   get_address_description (ref, &addr);
801
802   if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
803     {
804       if (addr.offset)
805         addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
806                         addr.offset,
807                         fold_convert (sizetype, addr.base));
808       else
809         addr.offset = addr.base;
810
811       addr.base = NULL_TREE;
812       changed = true;
813     }
814
815   if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
816     {
817       off = addr.index;
818       if (addr.step)
819         {
820           off = fold_binary_to_constant (MULT_EXPR, sizetype,
821                                          off, addr.step);
822           addr.step = NULL_TREE;
823         }
824
825       if (addr.offset)
826         {
827           addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
828                                                  addr.offset, off);
829         }
830       else
831         addr.offset = off;
832
833       addr.index = NULL_TREE;
834       changed = true;
835     }
836
837   if (!changed)
838     return NULL_TREE;
839
840   ret = create_mem_ref_raw (TREE_TYPE (ref), NULL_TREE, &addr);
841   if (!ret)
842     return NULL_TREE;
843
844   copy_mem_ref_info (ret, ref);
845   return ret;
846 }
847
848 /* Dump PARTS to FILE.  */
849
850 extern void dump_mem_address (FILE *, struct mem_address *);
851 void
852 dump_mem_address (FILE *file, struct mem_address *parts)
853 {
854   if (parts->symbol)
855     {
856       fprintf (file, "symbol: ");
857       print_generic_expr (file, parts->symbol, TDF_SLIM);
858       fprintf (file, "\n");
859     }
860   if (parts->base)
861     {
862       fprintf (file, "base: ");
863       print_generic_expr (file, parts->base, TDF_SLIM);
864       fprintf (file, "\n");
865     }
866   if (parts->index)
867     {
868       fprintf (file, "index: ");
869       print_generic_expr (file, parts->index, TDF_SLIM);
870       fprintf (file, "\n");
871     }
872   if (parts->step)
873     {
874       fprintf (file, "step: ");
875       print_generic_expr (file, parts->step, TDF_SLIM);
876       fprintf (file, "\n");
877     }
878   if (parts->offset)
879     {
880       fprintf (file, "offset: ");
881       print_generic_expr (file, parts->offset, TDF_SLIM);
882       fprintf (file, "\n");
883     }
884 }
885
886 #include "gt-tree-ssa-address.h"