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