1/* Memory address lowering and addressing mode selection.
2   Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010
3   Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 3, or (at your option) any
10later version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT
13ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
75typedef 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
83DEF_VEC_O (mem_addr_template);
84DEF_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
90static 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
104static void
105gen_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
186rtx
187addr_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
264tree
265tree_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
324static bool
325valid_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
341static tree
342create_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
360static bool
361fixed_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
372static void
373move_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
398static void
399move_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
432static void
433move_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
457static void
458add_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
489static void
490most_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
567static void
568addr_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
614static void
615gimplify_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
631tree
632create_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
752void
753get_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
764void
765copy_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
776tree
777maybe_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
833extern void dump_mem_address (FILE *, struct mem_address *);
834void
835dump_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"
870