]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/tree-ssa-address.c
tree.c (reference_alias_ptr_type): New function.
[thirdparty/gcc.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"