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