]>
Commit | Line | Data |
---|---|---|
ac182688 | 1 | /* Memory address lowering and addressing mode selection. |
8893239d | 2 | Copyright (C) 2004, 2006 Free Software Foundation, Inc. |
ac182688 ZD |
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 2, 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 COPYING. If not, write to the Free | |
366ccddb KC |
18 | Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
19 | 02110-1301, USA. */ | |
ac182688 ZD |
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" | |
73f30c63 | 45 | #include "tree-affine.h" |
ac182688 ZD |
46 | |
47 | /* TODO -- handling of symbols (according to Richard Hendersons | |
48 | comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html): | |
49 | ||
50 | There are at least 5 different kinds of symbols that we can run up against: | |
51 | ||
52 | (1) binds_local_p, small data area. | |
53 | (2) binds_local_p, eg local statics | |
54 | (3) !binds_local_p, eg global variables | |
55 | (4) thread local, local_exec | |
56 | (5) thread local, !local_exec | |
57 | ||
58 | Now, (1) won't appear often in an array context, but it certainly can. | |
59 | All you have to do is set -GN high enough, or explicitly mark any | |
60 | random object __attribute__((section (".sdata"))). | |
61 | ||
62 | All of these affect whether or not a symbol is in fact a valid address. | |
63 | The only one tested here is (3). And that result may very well | |
64 | be incorrect for (4) or (5). | |
65 | ||
66 | An incorrect result here does not cause incorrect results out the | |
67 | back end, because the expander in expr.c validizes the address. However | |
68 | it would be nice to improve the handling here in order to produce more | |
69 | precise results. */ | |
70 | ||
71 | /* A "template" for memory address, used to determine whether the address is | |
72 | valid for mode. */ | |
73 | ||
74 | struct mem_addr_template GTY (()) | |
75 | { | |
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 | }; | |
82 | ||
83 | /* The templates. Each of the five bits of the index corresponds to one | |
84 | component of TARGET_MEM_REF being present, see TEMPL_IDX. */ | |
85 | ||
86 | static GTY (()) struct mem_addr_template templates[32]; | |
87 | ||
88 | #define TEMPL_IDX(SYMBOL, BASE, INDEX, STEP, OFFSET) \ | |
89 | (((SYMBOL != 0) << 4) \ | |
90 | | ((BASE != 0) << 3) \ | |
91 | | ((INDEX != 0) << 2) \ | |
92 | | ((STEP != 0) << 1) \ | |
93 | | (OFFSET != 0)) | |
94 | ||
95 | /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX, | |
96 | STEP and OFFSET to *ADDR. Stores pointers to where step is placed to | |
97 | *STEP_P and offset to *OFFSET_P. */ | |
98 | ||
99 | static void | |
100 | gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, | |
101 | rtx *addr, rtx **step_p, rtx **offset_p) | |
102 | { | |
103 | rtx act_elem; | |
104 | ||
105 | *addr = NULL_RTX; | |
106 | if (step_p) | |
107 | *step_p = NULL; | |
108 | if (offset_p) | |
109 | *offset_p = NULL; | |
110 | ||
111 | if (index) | |
112 | { | |
113 | act_elem = index; | |
114 | if (step) | |
115 | { | |
116 | act_elem = gen_rtx_MULT (Pmode, act_elem, step); | |
117 | ||
118 | if (step_p) | |
119 | *step_p = &XEXP (act_elem, 1); | |
120 | } | |
121 | ||
122 | *addr = act_elem; | |
123 | } | |
124 | ||
125 | if (base) | |
126 | { | |
127 | if (*addr) | |
128 | *addr = gen_rtx_PLUS (Pmode, *addr, base); | |
129 | else | |
130 | *addr = base; | |
131 | } | |
132 | ||
133 | if (symbol) | |
134 | { | |
135 | act_elem = symbol; | |
136 | if (offset) | |
137 | { | |
8893239d RH |
138 | act_elem = gen_rtx_PLUS (Pmode, act_elem, offset); |
139 | ||
ac182688 | 140 | if (offset_p) |
8893239d RH |
141 | *offset_p = &XEXP (act_elem, 1); |
142 | ||
143 | if (GET_CODE (symbol) == SYMBOL_REF | |
144 | || GET_CODE (symbol) == LABEL_REF | |
145 | || GET_CODE (symbol) == CONST) | |
146 | act_elem = gen_rtx_CONST (Pmode, act_elem); | |
ac182688 ZD |
147 | } |
148 | ||
149 | if (*addr) | |
150 | *addr = gen_rtx_PLUS (Pmode, *addr, act_elem); | |
151 | else | |
152 | *addr = act_elem; | |
153 | } | |
154 | else if (offset) | |
155 | { | |
156 | if (*addr) | |
157 | { | |
158 | *addr = gen_rtx_PLUS (Pmode, *addr, offset); | |
159 | if (offset_p) | |
160 | *offset_p = &XEXP (*addr, 1); | |
161 | } | |
162 | else | |
163 | { | |
164 | *addr = offset; | |
165 | if (offset_p) | |
166 | *offset_p = addr; | |
167 | } | |
168 | } | |
169 | ||
170 | if (!*addr) | |
171 | *addr = const0_rtx; | |
172 | } | |
173 | ||
174 | /* Returns address for TARGET_MEM_REF with parameters given by ADDR. | |
175 | If REALLY_EXPAND is false, just make fake registers instead | |
176 | of really expanding the operands, and perform the expansion in-place | |
177 | by using one of the "templates". */ | |
178 | ||
179 | rtx | |
180 | addr_for_mem_ref (struct mem_address *addr, bool really_expand) | |
181 | { | |
182 | rtx address, sym, bse, idx, st, off; | |
183 | static bool templates_initialized = false; | |
184 | struct mem_addr_template *templ; | |
185 | ||
186 | if (addr->step && !integer_onep (addr->step)) | |
187 | st = immed_double_const (TREE_INT_CST_LOW (addr->step), | |
188 | TREE_INT_CST_HIGH (addr->step), Pmode); | |
189 | else | |
190 | st = NULL_RTX; | |
191 | ||
192 | if (addr->offset && !integer_zerop (addr->offset)) | |
193 | off = immed_double_const (TREE_INT_CST_LOW (addr->offset), | |
194 | TREE_INT_CST_HIGH (addr->offset), Pmode); | |
195 | else | |
196 | off = NULL_RTX; | |
197 | ||
198 | if (!really_expand) | |
199 | { | |
200 | /* Reuse the templates for addresses, so that we do not waste memory. */ | |
201 | if (!templates_initialized) | |
202 | { | |
203 | unsigned i; | |
204 | ||
205 | templates_initialized = true; | |
206 | sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("test_symbol")); | |
03daa27a ZD |
207 | bse = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1); |
208 | idx = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 2); | |
ac182688 ZD |
209 | |
210 | for (i = 0; i < 32; i++) | |
211 | gen_addr_rtx ((i & 16 ? sym : NULL_RTX), | |
212 | (i & 8 ? bse : NULL_RTX), | |
213 | (i & 4 ? idx : NULL_RTX), | |
214 | (i & 2 ? const0_rtx : NULL_RTX), | |
215 | (i & 1 ? const0_rtx : NULL_RTX), | |
216 | &templates[i].ref, | |
217 | &templates[i].step_p, | |
218 | &templates[i].off_p); | |
219 | } | |
220 | ||
221 | templ = templates + TEMPL_IDX (addr->symbol, addr->base, addr->index, | |
222 | st, off); | |
223 | if (st) | |
224 | *templ->step_p = st; | |
225 | if (off) | |
226 | *templ->off_p = off; | |
227 | ||
228 | return templ->ref; | |
229 | } | |
230 | ||
231 | /* Otherwise really expand the expressions. */ | |
232 | sym = (addr->symbol | |
233 | ? expand_expr (build_addr (addr->symbol, current_function_decl), | |
234 | NULL_RTX, Pmode, EXPAND_NORMAL) | |
235 | : NULL_RTX); | |
236 | bse = (addr->base | |
237 | ? expand_expr (addr->base, NULL_RTX, Pmode, EXPAND_NORMAL) | |
238 | : NULL_RTX); | |
239 | idx = (addr->index | |
240 | ? expand_expr (addr->index, NULL_RTX, Pmode, EXPAND_NORMAL) | |
241 | : NULL_RTX); | |
242 | ||
243 | gen_addr_rtx (sym, bse, idx, st, off, &address, NULL, NULL); | |
244 | return address; | |
245 | } | |
246 | ||
247 | /* Returns address of MEM_REF in TYPE. */ | |
248 | ||
249 | tree | |
250 | tree_mem_ref_addr (tree type, tree mem_ref) | |
251 | { | |
820410e0 | 252 | tree addr; |
ac182688 ZD |
253 | tree act_elem; |
254 | tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref); | |
820410e0 ZD |
255 | tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref); |
256 | tree addr_base = NULL_TREE, addr_off = NULL_TREE; | |
ac182688 | 257 | |
820410e0 ZD |
258 | if (sym) |
259 | addr_base = fold_convert (type, build_addr (sym, current_function_decl)); | |
260 | else if (base && POINTER_TYPE_P (TREE_TYPE (base))) | |
ac182688 | 261 | { |
820410e0 ZD |
262 | addr_base = fold_convert (type, base); |
263 | base = NULL_TREE; | |
ac182688 ZD |
264 | } |
265 | ||
820410e0 | 266 | act_elem = TMR_INDEX (mem_ref); |
ac182688 ZD |
267 | if (act_elem) |
268 | { | |
820410e0 ZD |
269 | if (step) |
270 | act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step); | |
271 | addr_off = act_elem; | |
ac182688 ZD |
272 | } |
273 | ||
820410e0 | 274 | act_elem = base; |
ac182688 ZD |
275 | if (act_elem) |
276 | { | |
820410e0 ZD |
277 | if (addr_off) |
278 | addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem); | |
ac182688 | 279 | else |
820410e0 | 280 | addr_off = act_elem; |
ac182688 ZD |
281 | } |
282 | ||
6e682d7e | 283 | if (offset && !integer_zerop (offset)) |
ac182688 | 284 | { |
820410e0 ZD |
285 | if (addr_off) |
286 | addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset); | |
ac182688 | 287 | else |
820410e0 | 288 | addr_off = offset; |
ac182688 ZD |
289 | } |
290 | ||
820410e0 ZD |
291 | if (addr_off) |
292 | { | |
293 | addr = fold_convert (type, addr_off); | |
294 | if (addr_base) | |
295 | addr = fold_build2 (PLUS_EXPR, type, addr_base, addr); | |
296 | } | |
297 | else if (addr_base) | |
298 | addr = addr_base; | |
299 | else | |
ac182688 ZD |
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 | ||
6e682d7e | 333 | if (addr->offset && integer_zerop (addr->offset)) |
ac182688 ZD |
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 | } | |
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 | |
354 | static void | |
820410e0 | 355 | move_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 | ||
381 | static void | |
382 | move_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 | ||
406 | static void | |
407 | add_to_parts (struct mem_address *parts, tree elt) | |
408 | { | |
409 | tree type; | |
410 | ||
ac182688 ZD |
411 | if (!parts->index) |
412 | { | |
413 | parts->index = elt; | |
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 ZD |
424 | type = TREE_TYPE (parts->base); |
425 | parts->base = fold_build2 (PLUS_EXPR, type, | |
426 | parts->base, | |
427 | fold_convert (type, elt)); | |
ac182688 ZD |
428 | } |
429 | ||
430 | /* Finds the most expensive multiplication in ADDR that can be | |
431 | expressed in an addressing mode and move the corresponding | |
820410e0 | 432 | element(s) to PARTS. */ |
ac182688 ZD |
433 | |
434 | static void | |
820410e0 | 435 | most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr) |
ac182688 | 436 | { |
73f30c63 ZD |
437 | HOST_WIDE_INT coef; |
438 | double_int best_mult, amult, amult_neg; | |
ac182688 ZD |
439 | unsigned best_mult_cost = 0, acost; |
440 | tree mult_elt = NULL_TREE, elt; | |
441 | unsigned i, j; | |
73f30c63 | 442 | enum tree_code op_code; |
ac182688 | 443 | |
73f30c63 | 444 | best_mult = double_int_zero; |
ac182688 ZD |
445 | for (i = 0; i < addr->n; i++) |
446 | { | |
73f30c63 ZD |
447 | if (!double_int_fits_in_shwi_p (addr->elts[i].coef)) |
448 | continue; | |
449 | ||
dd5f63f8 | 450 | /* FIXME: Should use the correct memory mode rather than Pmode. */ |
73f30c63 ZD |
451 | |
452 | coef = double_int_to_shwi (addr->elts[i].coef); | |
453 | if (coef == 1 | |
454 | || !multiplier_allowed_in_address_p (coef, Pmode)) | |
ac182688 | 455 | continue; |
73f30c63 ZD |
456 | |
457 | acost = multiply_by_cost (coef, Pmode); | |
ac182688 ZD |
458 | |
459 | if (acost > best_mult_cost) | |
460 | { | |
461 | best_mult_cost = acost; | |
73f30c63 | 462 | best_mult = addr->elts[i].coef; |
ac182688 ZD |
463 | } |
464 | } | |
465 | ||
73f30c63 | 466 | if (!best_mult_cost) |
ac182688 ZD |
467 | return; |
468 | ||
73f30c63 | 469 | /* Collect elements multiplied by best_mult. */ |
ac182688 ZD |
470 | for (i = j = 0; i < addr->n; i++) |
471 | { | |
73f30c63 ZD |
472 | amult = addr->elts[i].coef; |
473 | amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr); | |
474 | ||
475 | if (double_int_equal_p (amult, best_mult)) | |
476 | op_code = PLUS_EXPR; | |
477 | else if (double_int_equal_p (amult_neg, best_mult)) | |
478 | op_code = MINUS_EXPR; | |
479 | else | |
ac182688 | 480 | { |
ac182688 ZD |
481 | addr->elts[j] = addr->elts[i]; |
482 | j++; | |
483 | continue; | |
484 | } | |
73f30c63 | 485 | |
820410e0 | 486 | elt = fold_convert (sizetype, addr->elts[i].val); |
73f30c63 | 487 | if (mult_elt) |
820410e0 | 488 | mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt); |
73f30c63 | 489 | else if (op_code == PLUS_EXPR) |
ac182688 ZD |
490 | mult_elt = elt; |
491 | else | |
820410e0 | 492 | mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt); |
ac182688 ZD |
493 | } |
494 | addr->n = j; | |
73f30c63 | 495 | |
ac182688 | 496 | parts->index = mult_elt; |
820410e0 | 497 | parts->step = double_int_to_tree (sizetype, best_mult); |
ac182688 ZD |
498 | } |
499 | ||
500 | /* Splits address ADDR into PARTS. | |
501 | ||
502 | TODO -- be more clever about the distribution of the elements of ADDR | |
503 | to PARTS. Some architectures do not support anything but single | |
504 | register in address, possibly with a small integer offset; while | |
505 | create_mem_ref will simplify the address to an acceptable shape | |
73f30c63 ZD |
506 | later, it would be more efficient to know that asking for complicated |
507 | addressing modes is useless. */ | |
ac182688 ZD |
508 | |
509 | static void | |
820410e0 | 510 | addr_to_parts (aff_tree *addr, struct mem_address *parts) |
ac182688 | 511 | { |
73f30c63 | 512 | tree part; |
ac182688 ZD |
513 | unsigned i; |
514 | ||
515 | parts->symbol = NULL_TREE; | |
516 | parts->base = NULL_TREE; | |
517 | parts->index = NULL_TREE; | |
518 | parts->step = NULL_TREE; | |
519 | ||
73f30c63 | 520 | if (!double_int_zero_p (addr->offset)) |
820410e0 | 521 | parts->offset = double_int_to_tree (sizetype, addr->offset); |
ac182688 ZD |
522 | else |
523 | parts->offset = NULL_TREE; | |
524 | ||
820410e0 ZD |
525 | /* Try to find a symbol. */ |
526 | move_fixed_address_to_symbol (parts, addr); | |
527 | ||
ac182688 ZD |
528 | /* First move the most expensive feasible multiplication |
529 | to index. */ | |
820410e0 ZD |
530 | most_expensive_mult_to_index (parts, addr); |
531 | ||
532 | /* Try to find a base of the reference. Since at the moment | |
533 | there is no reliable way how to distinguish between pointer and its | |
534 | offset, this is just a guess. */ | |
535 | if (!parts->symbol) | |
536 | move_pointer_to_base (parts, addr); | |
ac182688 ZD |
537 | |
538 | /* Then try to process the remaining elements. */ | |
539 | for (i = 0; i < addr->n; i++) | |
73f30c63 | 540 | { |
820410e0 | 541 | part = fold_convert (sizetype, addr->elts[i].val); |
73f30c63 | 542 | if (!double_int_one_p (addr->elts[i].coef)) |
820410e0 ZD |
543 | part = fold_build2 (MULT_EXPR, sizetype, part, |
544 | double_int_to_tree (sizetype, addr->elts[i].coef)); | |
545 | add_to_parts (parts, part); | |
73f30c63 | 546 | } |
ac182688 | 547 | if (addr->rest) |
820410e0 | 548 | add_to_parts (parts, fold_convert (sizetype, addr->rest)); |
ac182688 ZD |
549 | } |
550 | ||
551 | /* Force the PARTS to register. */ | |
552 | ||
553 | static void | |
554 | gimplify_mem_ref_parts (block_stmt_iterator *bsi, struct mem_address *parts) | |
555 | { | |
556 | if (parts->base) | |
557 | parts->base = force_gimple_operand_bsi (bsi, parts->base, | |
558 | true, NULL_TREE); | |
559 | if (parts->index) | |
560 | parts->index = force_gimple_operand_bsi (bsi, parts->index, | |
561 | true, NULL_TREE); | |
562 | } | |
563 | ||
564 | /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary | |
565 | computations are emitted in front of BSI. TYPE is the mode | |
566 | of created memory reference. */ | |
567 | ||
568 | tree | |
73f30c63 | 569 | create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr) |
ac182688 ZD |
570 | { |
571 | tree mem_ref, tmp; | |
69bd3423 | 572 | tree atype; |
ac182688 ZD |
573 | struct mem_address parts; |
574 | ||
820410e0 | 575 | addr_to_parts (addr, &parts); |
ac182688 ZD |
576 | gimplify_mem_ref_parts (bsi, &parts); |
577 | mem_ref = create_mem_ref_raw (type, &parts); | |
578 | if (mem_ref) | |
579 | return mem_ref; | |
580 | ||
581 | /* The expression is too complicated. Try making it simpler. */ | |
582 | ||
583 | if (parts.step && !integer_onep (parts.step)) | |
584 | { | |
585 | /* Move the multiplication to index. */ | |
586 | gcc_assert (parts.index); | |
587 | parts.index = force_gimple_operand_bsi (bsi, | |
820410e0 ZD |
588 | fold_build2 (MULT_EXPR, sizetype, |
589 | parts.index, parts.step), | |
590 | true, NULL_TREE); | |
ac182688 ZD |
591 | parts.step = NULL_TREE; |
592 | ||
593 | mem_ref = create_mem_ref_raw (type, &parts); | |
594 | if (mem_ref) | |
595 | return mem_ref; | |
596 | } | |
597 | ||
598 | if (parts.symbol) | |
599 | { | |
69bd3423 ZD |
600 | tmp = build_addr (parts.symbol, current_function_decl); |
601 | gcc_assert (is_gimple_val (tmp)); | |
ac182688 ZD |
602 | |
603 | /* Add the symbol to base, eventually forcing it to register. */ | |
604 | if (parts.base) | |
39278c14 | 605 | { |
5f787cbc ZD |
606 | gcc_assert (tree_ssa_useless_type_conversion_1 |
607 | (sizetype, TREE_TYPE (parts.base))); | |
69bd3423 | 608 | |
39278c14 | 609 | if (parts.index) |
69bd3423 ZD |
610 | { |
611 | atype = TREE_TYPE (tmp); | |
612 | parts.base = force_gimple_operand_bsi (bsi, | |
613 | fold_build2 (PLUS_EXPR, atype, | |
614 | fold_convert (atype, parts.base), | |
820410e0 ZD |
615 | tmp), |
616 | true, NULL_TREE); | |
69bd3423 | 617 | } |
39278c14 AK |
618 | else |
619 | { | |
620 | parts.index = parts.base; | |
621 | parts.base = tmp; | |
622 | } | |
623 | } | |
ac182688 ZD |
624 | else |
625 | parts.base = tmp; | |
626 | parts.symbol = NULL_TREE; | |
627 | ||
628 | mem_ref = create_mem_ref_raw (type, &parts); | |
629 | if (mem_ref) | |
630 | return mem_ref; | |
631 | } | |
632 | ||
820410e0 | 633 | if (parts.index) |
ac182688 | 634 | { |
820410e0 ZD |
635 | /* Add index to base. */ |
636 | if (parts.base) | |
637 | { | |
638 | atype = TREE_TYPE (parts.base); | |
639 | parts.base = force_gimple_operand_bsi (bsi, | |
640 | fold_build2 (PLUS_EXPR, atype, | |
641 | parts.base, | |
642 | fold_convert (atype, parts.index)), | |
643 | true, NULL_TREE); | |
644 | } | |
ac182688 | 645 | else |
820410e0 ZD |
646 | parts.base = parts.index; |
647 | parts.index = NULL_TREE; | |
ac182688 ZD |
648 | |
649 | mem_ref = create_mem_ref_raw (type, &parts); | |
650 | if (mem_ref) | |
651 | return mem_ref; | |
652 | } | |
653 | ||
654 | if (parts.offset && !integer_zerop (parts.offset)) | |
655 | { | |
820410e0 ZD |
656 | /* Try adding offset to base. */ |
657 | if (parts.base) | |
658 | { | |
659 | atype = TREE_TYPE (parts.base); | |
660 | parts.base = force_gimple_operand_bsi (bsi, | |
661 | fold_build2 (PLUS_EXPR, atype, | |
662 | parts.base, | |
663 | fold_convert (atype, parts.offset)), | |
664 | true, NULL_TREE); | |
665 | } | |
ac182688 | 666 | else |
cdd76d88 | 667 | parts.base = parts.offset; |
ac182688 ZD |
668 | |
669 | parts.offset = NULL_TREE; | |
670 | ||
671 | mem_ref = create_mem_ref_raw (type, &parts); | |
672 | if (mem_ref) | |
673 | return mem_ref; | |
674 | } | |
675 | ||
676 | /* Verify that the address is in the simplest possible shape | |
677 | (only a register). If we cannot create such a memory reference, | |
678 | something is really wrong. */ | |
679 | gcc_assert (parts.symbol == NULL_TREE); | |
820410e0 | 680 | gcc_assert (parts.index == NULL_TREE); |
ac182688 ZD |
681 | gcc_assert (!parts.step || integer_onep (parts.step)); |
682 | gcc_assert (!parts.offset || integer_zerop (parts.offset)); | |
683 | gcc_unreachable (); | |
684 | } | |
685 | ||
686 | /* Copies components of the address from OP to ADDR. */ | |
687 | ||
688 | void | |
689 | get_address_description (tree op, struct mem_address *addr) | |
690 | { | |
691 | addr->symbol = TMR_SYMBOL (op); | |
692 | addr->base = TMR_BASE (op); | |
693 | addr->index = TMR_INDEX (op); | |
694 | addr->step = TMR_STEP (op); | |
695 | addr->offset = TMR_OFFSET (op); | |
696 | } | |
697 | ||
698 | /* Copies the additional information attached to target_mem_ref FROM to TO. */ | |
699 | ||
700 | void | |
701 | copy_mem_ref_info (tree to, tree from) | |
702 | { | |
703 | /* Copy the annotation, to preserve the aliasing information. */ | |
704 | TMR_TAG (to) = TMR_TAG (from); | |
705 | ||
706 | /* And the info about the original reference. */ | |
707 | TMR_ORIGINAL (to) = TMR_ORIGINAL (from); | |
708 | } | |
709 | ||
710 | /* Move constants in target_mem_ref REF to offset. Returns the new target | |
711 | mem ref if anything changes, NULL_TREE otherwise. */ | |
712 | ||
713 | tree | |
714 | maybe_fold_tmr (tree ref) | |
715 | { | |
716 | struct mem_address addr; | |
717 | bool changed = false; | |
718 | tree ret, off; | |
719 | ||
720 | get_address_description (ref, &addr); | |
721 | ||
722 | if (addr.base && TREE_CODE (addr.base) == INTEGER_CST) | |
723 | { | |
724 | if (addr.offset) | |
820410e0 ZD |
725 | addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype, |
726 | addr.offset, | |
727 | fold_convert (sizetype, addr.base)); | |
ac182688 ZD |
728 | else |
729 | addr.offset = addr.base; | |
730 | ||
731 | addr.base = NULL_TREE; | |
732 | changed = true; | |
733 | } | |
734 | ||
735 | if (addr.index && TREE_CODE (addr.index) == INTEGER_CST) | |
736 | { | |
737 | off = addr.index; | |
738 | if (addr.step) | |
739 | { | |
820410e0 | 740 | off = fold_binary_to_constant (MULT_EXPR, sizetype, |
ac182688 ZD |
741 | off, addr.step); |
742 | addr.step = NULL_TREE; | |
743 | } | |
744 | ||
745 | if (addr.offset) | |
746 | { | |
820410e0 | 747 | addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype, |
ac182688 ZD |
748 | addr.offset, off); |
749 | } | |
750 | else | |
751 | addr.offset = off; | |
752 | ||
753 | addr.index = NULL_TREE; | |
754 | changed = true; | |
755 | } | |
756 | ||
757 | if (!changed) | |
758 | return NULL_TREE; | |
759 | ||
760 | ret = create_mem_ref_raw (TREE_TYPE (ref), &addr); | |
761 | if (!ret) | |
762 | return NULL_TREE; | |
763 | ||
764 | copy_mem_ref_info (ret, ref); | |
765 | return ret; | |
766 | } | |
767 | ||
768 | /* Dump PARTS to FILE. */ | |
769 | ||
770 | extern void dump_mem_address (FILE *, struct mem_address *); | |
771 | void | |
772 | dump_mem_address (FILE *file, struct mem_address *parts) | |
773 | { | |
774 | if (parts->symbol) | |
775 | { | |
776 | fprintf (file, "symbol: "); | |
777 | print_generic_expr (file, parts->symbol, TDF_SLIM); | |
778 | fprintf (file, "\n"); | |
779 | } | |
780 | if (parts->base) | |
781 | { | |
782 | fprintf (file, "base: "); | |
783 | print_generic_expr (file, parts->base, TDF_SLIM); | |
784 | fprintf (file, "\n"); | |
785 | } | |
786 | if (parts->index) | |
787 | { | |
788 | fprintf (file, "index: "); | |
789 | print_generic_expr (file, parts->index, TDF_SLIM); | |
790 | fprintf (file, "\n"); | |
791 | } | |
792 | if (parts->step) | |
793 | { | |
794 | fprintf (file, "step: "); | |
795 | print_generic_expr (file, parts->step, TDF_SLIM); | |
796 | fprintf (file, "\n"); | |
797 | } | |
798 | if (parts->offset) | |
799 | { | |
800 | fprintf (file, "offset: "); | |
801 | print_generic_expr (file, parts->offset, TDF_SLIM); | |
802 | fprintf (file, "\n"); | |
803 | } | |
804 | } | |
805 | ||
806 | #include "gt-tree-ssa-address.h" |