]>
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 | { | |
820410e0 | 293 | if (addr_base) |
5be014d5 AP |
294 | addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off); |
295 | else | |
296 | addr = fold_convert (type, addr_off); | |
820410e0 ZD |
297 | } |
298 | else if (addr_base) | |
299 | addr = addr_base; | |
300 | else | |
ac182688 ZD |
301 | addr = build_int_cst (type, 0); |
302 | ||
303 | return addr; | |
304 | } | |
305 | ||
306 | /* Returns true if a memory reference in MODE and with parameters given by | |
307 | ADDR is valid on the current target. */ | |
308 | ||
309 | static bool | |
310 | valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr) | |
311 | { | |
312 | rtx address; | |
313 | ||
314 | address = addr_for_mem_ref (addr, false); | |
315 | if (!address) | |
316 | return false; | |
317 | ||
318 | return memory_address_p (mode, address); | |
319 | } | |
320 | ||
321 | /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR | |
322 | is valid on the current target and if so, creates and returns the | |
323 | TARGET_MEM_REF. */ | |
324 | ||
325 | static tree | |
326 | create_mem_ref_raw (tree type, struct mem_address *addr) | |
327 | { | |
328 | if (!valid_mem_ref_p (TYPE_MODE (type), addr)) | |
329 | return NULL_TREE; | |
330 | ||
331 | if (addr->step && integer_onep (addr->step)) | |
332 | addr->step = NULL_TREE; | |
333 | ||
6e682d7e | 334 | if (addr->offset && integer_zerop (addr->offset)) |
ac182688 ZD |
335 | addr->offset = NULL_TREE; |
336 | ||
337 | return build7 (TARGET_MEM_REF, type, | |
338 | addr->symbol, addr->base, addr->index, | |
339 | addr->step, addr->offset, NULL, NULL); | |
340 | } | |
341 | ||
342 | /* Returns true if OBJ is an object whose address is a link time constant. */ | |
343 | ||
344 | static bool | |
345 | fixed_address_object_p (tree obj) | |
346 | { | |
347 | return (TREE_CODE (obj) == VAR_DECL | |
348 | && (TREE_STATIC (obj) | |
349 | || DECL_EXTERNAL (obj))); | |
350 | } | |
351 | ||
820410e0 ZD |
352 | /* If ADDR contains an address of object that is a link time constant, |
353 | move it to PARTS->symbol. */ | |
ac182688 ZD |
354 | |
355 | static void | |
820410e0 | 356 | move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr) |
ac182688 | 357 | { |
820410e0 ZD |
358 | unsigned i; |
359 | tree val = NULL_TREE; | |
73f30c63 | 360 | |
820410e0 | 361 | for (i = 0; i < addr->n; i++) |
ac182688 | 362 | { |
820410e0 ZD |
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; | |
ac182688 ZD |
370 | } |
371 | ||
820410e0 ZD |
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++) | |
ac182688 | 389 | { |
820410e0 ZD |
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; | |
ac182688 ZD |
396 | } |
397 | ||
820410e0 ZD |
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 | ||
ac182688 ZD |
412 | if (!parts->index) |
413 | { | |
5be014d5 | 414 | parts->index = fold_convert (sizetype, elt); |
ac182688 ZD |
415 | return; |
416 | } | |
417 | ||
820410e0 ZD |
418 | if (!parts->base) |
419 | { | |
420 | parts->base = elt; | |
421 | return; | |
422 | } | |
423 | ||
ac182688 | 424 | /* Add ELT to base. */ |
820410e0 ZD |
425 | type = TREE_TYPE (parts->base); |
426 | parts->base = fold_build2 (PLUS_EXPR, type, | |
427 | parts->base, | |
428 | fold_convert (type, elt)); | |
ac182688 ZD |
429 | } |
430 | ||
431 | /* Finds the most expensive multiplication in ADDR that can be | |
432 | expressed in an addressing mode and move the corresponding | |
820410e0 | 433 | element(s) to PARTS. */ |
ac182688 ZD |
434 | |
435 | static void | |
820410e0 | 436 | most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr) |
ac182688 | 437 | { |
73f30c63 ZD |
438 | HOST_WIDE_INT coef; |
439 | double_int best_mult, amult, amult_neg; | |
ac182688 ZD |
440 | unsigned best_mult_cost = 0, acost; |
441 | tree mult_elt = NULL_TREE, elt; | |
442 | unsigned i, j; | |
73f30c63 | 443 | enum tree_code op_code; |
ac182688 | 444 | |
73f30c63 | 445 | best_mult = double_int_zero; |
ac182688 ZD |
446 | for (i = 0; i < addr->n; i++) |
447 | { | |
73f30c63 ZD |
448 | if (!double_int_fits_in_shwi_p (addr->elts[i].coef)) |
449 | continue; | |
450 | ||
dd5f63f8 | 451 | /* FIXME: Should use the correct memory mode rather than Pmode. */ |
73f30c63 ZD |
452 | |
453 | coef = double_int_to_shwi (addr->elts[i].coef); | |
454 | if (coef == 1 | |
455 | || !multiplier_allowed_in_address_p (coef, Pmode)) | |
ac182688 | 456 | continue; |
73f30c63 ZD |
457 | |
458 | acost = multiply_by_cost (coef, Pmode); | |
ac182688 ZD |
459 | |
460 | if (acost > best_mult_cost) | |
461 | { | |
462 | best_mult_cost = acost; | |
73f30c63 | 463 | best_mult = addr->elts[i].coef; |
ac182688 ZD |
464 | } |
465 | } | |
466 | ||
73f30c63 | 467 | if (!best_mult_cost) |
ac182688 ZD |
468 | return; |
469 | ||
73f30c63 | 470 | /* Collect elements multiplied by best_mult. */ |
ac182688 ZD |
471 | for (i = j = 0; i < addr->n; i++) |
472 | { | |
73f30c63 ZD |
473 | amult = addr->elts[i].coef; |
474 | amult_neg = double_int_ext_for_comb (double_int_neg (amult), addr); | |
475 | ||
476 | if (double_int_equal_p (amult, best_mult)) | |
477 | op_code = PLUS_EXPR; | |
478 | else if (double_int_equal_p (amult_neg, best_mult)) | |
479 | op_code = MINUS_EXPR; | |
480 | else | |
ac182688 | 481 | { |
ac182688 ZD |
482 | addr->elts[j] = addr->elts[i]; |
483 | j++; | |
484 | continue; | |
485 | } | |
5be014d5 | 486 | |
820410e0 | 487 | elt = fold_convert (sizetype, addr->elts[i].val); |
73f30c63 | 488 | if (mult_elt) |
820410e0 | 489 | mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt); |
73f30c63 | 490 | else if (op_code == PLUS_EXPR) |
ac182688 ZD |
491 | mult_elt = elt; |
492 | else | |
820410e0 | 493 | mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt); |
ac182688 ZD |
494 | } |
495 | addr->n = j; | |
73f30c63 | 496 | |
ac182688 | 497 | parts->index = mult_elt; |
820410e0 | 498 | parts->step = double_int_to_tree (sizetype, best_mult); |
ac182688 ZD |
499 | } |
500 | ||
501 | /* Splits address ADDR into PARTS. | |
502 | ||
503 | TODO -- be more clever about the distribution of the elements of ADDR | |
504 | to PARTS. Some architectures do not support anything but single | |
505 | register in address, possibly with a small integer offset; while | |
506 | create_mem_ref will simplify the address to an acceptable shape | |
73f30c63 ZD |
507 | later, it would be more efficient to know that asking for complicated |
508 | addressing modes is useless. */ | |
ac182688 ZD |
509 | |
510 | static void | |
820410e0 | 511 | addr_to_parts (aff_tree *addr, struct mem_address *parts) |
ac182688 | 512 | { |
73f30c63 | 513 | tree part; |
ac182688 ZD |
514 | unsigned i; |
515 | ||
516 | parts->symbol = NULL_TREE; | |
517 | parts->base = NULL_TREE; | |
518 | parts->index = NULL_TREE; | |
519 | parts->step = NULL_TREE; | |
520 | ||
73f30c63 | 521 | if (!double_int_zero_p (addr->offset)) |
820410e0 | 522 | parts->offset = double_int_to_tree (sizetype, addr->offset); |
ac182688 ZD |
523 | else |
524 | parts->offset = NULL_TREE; | |
525 | ||
820410e0 ZD |
526 | /* Try to find a symbol. */ |
527 | move_fixed_address_to_symbol (parts, addr); | |
528 | ||
ac182688 ZD |
529 | /* First move the most expensive feasible multiplication |
530 | to index. */ | |
820410e0 ZD |
531 | most_expensive_mult_to_index (parts, addr); |
532 | ||
533 | /* Try to find a base of the reference. Since at the moment | |
534 | there is no reliable way how to distinguish between pointer and its | |
535 | offset, this is just a guess. */ | |
536 | if (!parts->symbol) | |
537 | move_pointer_to_base (parts, addr); | |
ac182688 ZD |
538 | |
539 | /* Then try to process the remaining elements. */ | |
540 | for (i = 0; i < addr->n; i++) | |
73f30c63 | 541 | { |
820410e0 | 542 | part = fold_convert (sizetype, addr->elts[i].val); |
73f30c63 | 543 | if (!double_int_one_p (addr->elts[i].coef)) |
820410e0 ZD |
544 | part = fold_build2 (MULT_EXPR, sizetype, part, |
545 | double_int_to_tree (sizetype, addr->elts[i].coef)); | |
546 | add_to_parts (parts, part); | |
73f30c63 | 547 | } |
ac182688 | 548 | if (addr->rest) |
820410e0 | 549 | add_to_parts (parts, fold_convert (sizetype, addr->rest)); |
ac182688 ZD |
550 | } |
551 | ||
552 | /* Force the PARTS to register. */ | |
553 | ||
554 | static void | |
555 | gimplify_mem_ref_parts (block_stmt_iterator *bsi, struct mem_address *parts) | |
556 | { | |
557 | if (parts->base) | |
558 | parts->base = force_gimple_operand_bsi (bsi, parts->base, | |
559 | true, NULL_TREE); | |
560 | if (parts->index) | |
561 | parts->index = force_gimple_operand_bsi (bsi, parts->index, | |
562 | true, NULL_TREE); | |
563 | } | |
564 | ||
565 | /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary | |
566 | computations are emitted in front of BSI. TYPE is the mode | |
567 | of created memory reference. */ | |
568 | ||
569 | tree | |
73f30c63 | 570 | create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr) |
ac182688 ZD |
571 | { |
572 | tree mem_ref, tmp; | |
69bd3423 | 573 | tree atype; |
ac182688 ZD |
574 | struct mem_address parts; |
575 | ||
820410e0 | 576 | addr_to_parts (addr, &parts); |
ac182688 ZD |
577 | gimplify_mem_ref_parts (bsi, &parts); |
578 | mem_ref = create_mem_ref_raw (type, &parts); | |
579 | if (mem_ref) | |
580 | return mem_ref; | |
581 | ||
582 | /* The expression is too complicated. Try making it simpler. */ | |
583 | ||
584 | if (parts.step && !integer_onep (parts.step)) | |
585 | { | |
586 | /* Move the multiplication to index. */ | |
587 | gcc_assert (parts.index); | |
588 | parts.index = force_gimple_operand_bsi (bsi, | |
820410e0 ZD |
589 | fold_build2 (MULT_EXPR, sizetype, |
590 | parts.index, parts.step), | |
591 | true, NULL_TREE); | |
ac182688 ZD |
592 | parts.step = NULL_TREE; |
593 | ||
594 | mem_ref = create_mem_ref_raw (type, &parts); | |
595 | if (mem_ref) | |
596 | return mem_ref; | |
597 | } | |
598 | ||
599 | if (parts.symbol) | |
600 | { | |
69bd3423 ZD |
601 | tmp = build_addr (parts.symbol, current_function_decl); |
602 | gcc_assert (is_gimple_val (tmp)); | |
ac182688 ZD |
603 | |
604 | /* Add the symbol to base, eventually forcing it to register. */ | |
605 | if (parts.base) | |
39278c14 | 606 | { |
5f787cbc ZD |
607 | gcc_assert (tree_ssa_useless_type_conversion_1 |
608 | (sizetype, TREE_TYPE (parts.base))); | |
69bd3423 | 609 | |
39278c14 | 610 | if (parts.index) |
69bd3423 ZD |
611 | { |
612 | atype = TREE_TYPE (tmp); | |
613 | parts.base = force_gimple_operand_bsi (bsi, | |
614 | fold_build2 (PLUS_EXPR, atype, | |
615 | fold_convert (atype, parts.base), | |
820410e0 ZD |
616 | tmp), |
617 | true, NULL_TREE); | |
69bd3423 | 618 | } |
39278c14 AK |
619 | else |
620 | { | |
621 | parts.index = parts.base; | |
622 | parts.base = tmp; | |
623 | } | |
624 | } | |
ac182688 ZD |
625 | else |
626 | parts.base = tmp; | |
627 | parts.symbol = NULL_TREE; | |
628 | ||
629 | mem_ref = create_mem_ref_raw (type, &parts); | |
630 | if (mem_ref) | |
631 | return mem_ref; | |
632 | } | |
633 | ||
820410e0 | 634 | if (parts.index) |
ac182688 | 635 | { |
820410e0 ZD |
636 | /* Add index to base. */ |
637 | if (parts.base) | |
638 | { | |
639 | atype = TREE_TYPE (parts.base); | |
640 | parts.base = force_gimple_operand_bsi (bsi, | |
641 | fold_build2 (PLUS_EXPR, atype, | |
642 | parts.base, | |
643 | fold_convert (atype, parts.index)), | |
644 | true, NULL_TREE); | |
645 | } | |
ac182688 | 646 | else |
820410e0 ZD |
647 | parts.base = parts.index; |
648 | parts.index = NULL_TREE; | |
ac182688 ZD |
649 | |
650 | mem_ref = create_mem_ref_raw (type, &parts); | |
651 | if (mem_ref) | |
652 | return mem_ref; | |
653 | } | |
654 | ||
655 | if (parts.offset && !integer_zerop (parts.offset)) | |
656 | { | |
820410e0 ZD |
657 | /* Try adding offset to base. */ |
658 | if (parts.base) | |
659 | { | |
660 | atype = TREE_TYPE (parts.base); | |
661 | parts.base = force_gimple_operand_bsi (bsi, | |
5be014d5 | 662 | fold_build2 (POINTER_PLUS_EXPR, atype, |
820410e0 | 663 | parts.base, |
5be014d5 | 664 | fold_convert (sizetype, parts.offset)), |
820410e0 ZD |
665 | true, NULL_TREE); |
666 | } | |
ac182688 | 667 | else |
cdd76d88 | 668 | parts.base = parts.offset; |
ac182688 ZD |
669 | |
670 | parts.offset = NULL_TREE; | |
671 | ||
672 | mem_ref = create_mem_ref_raw (type, &parts); | |
673 | if (mem_ref) | |
674 | return mem_ref; | |
675 | } | |
676 | ||
677 | /* Verify that the address is in the simplest possible shape | |
678 | (only a register). If we cannot create such a memory reference, | |
679 | something is really wrong. */ | |
680 | gcc_assert (parts.symbol == NULL_TREE); | |
820410e0 | 681 | gcc_assert (parts.index == NULL_TREE); |
ac182688 ZD |
682 | gcc_assert (!parts.step || integer_onep (parts.step)); |
683 | gcc_assert (!parts.offset || integer_zerop (parts.offset)); | |
684 | gcc_unreachable (); | |
685 | } | |
686 | ||
687 | /* Copies components of the address from OP to ADDR. */ | |
688 | ||
689 | void | |
690 | get_address_description (tree op, struct mem_address *addr) | |
691 | { | |
692 | addr->symbol = TMR_SYMBOL (op); | |
693 | addr->base = TMR_BASE (op); | |
694 | addr->index = TMR_INDEX (op); | |
695 | addr->step = TMR_STEP (op); | |
696 | addr->offset = TMR_OFFSET (op); | |
697 | } | |
698 | ||
699 | /* Copies the additional information attached to target_mem_ref FROM to TO. */ | |
700 | ||
701 | void | |
702 | copy_mem_ref_info (tree to, tree from) | |
703 | { | |
704 | /* Copy the annotation, to preserve the aliasing information. */ | |
705 | TMR_TAG (to) = TMR_TAG (from); | |
706 | ||
707 | /* And the info about the original reference. */ | |
708 | TMR_ORIGINAL (to) = TMR_ORIGINAL (from); | |
709 | } | |
710 | ||
711 | /* Move constants in target_mem_ref REF to offset. Returns the new target | |
712 | mem ref if anything changes, NULL_TREE otherwise. */ | |
713 | ||
714 | tree | |
715 | maybe_fold_tmr (tree ref) | |
716 | { | |
717 | struct mem_address addr; | |
718 | bool changed = false; | |
719 | tree ret, off; | |
720 | ||
721 | get_address_description (ref, &addr); | |
722 | ||
723 | if (addr.base && TREE_CODE (addr.base) == INTEGER_CST) | |
724 | { | |
725 | if (addr.offset) | |
820410e0 ZD |
726 | addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype, |
727 | addr.offset, | |
728 | fold_convert (sizetype, addr.base)); | |
ac182688 ZD |
729 | else |
730 | addr.offset = addr.base; | |
731 | ||
732 | addr.base = NULL_TREE; | |
733 | changed = true; | |
734 | } | |
735 | ||
736 | if (addr.index && TREE_CODE (addr.index) == INTEGER_CST) | |
737 | { | |
738 | off = addr.index; | |
739 | if (addr.step) | |
740 | { | |
820410e0 | 741 | off = fold_binary_to_constant (MULT_EXPR, sizetype, |
ac182688 ZD |
742 | off, addr.step); |
743 | addr.step = NULL_TREE; | |
744 | } | |
745 | ||
746 | if (addr.offset) | |
747 | { | |
820410e0 | 748 | addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype, |
ac182688 ZD |
749 | addr.offset, off); |
750 | } | |
751 | else | |
752 | addr.offset = off; | |
753 | ||
754 | addr.index = NULL_TREE; | |
755 | changed = true; | |
756 | } | |
757 | ||
758 | if (!changed) | |
759 | return NULL_TREE; | |
760 | ||
761 | ret = create_mem_ref_raw (TREE_TYPE (ref), &addr); | |
762 | if (!ret) | |
763 | return NULL_TREE; | |
764 | ||
765 | copy_mem_ref_info (ret, ref); | |
766 | return ret; | |
767 | } | |
768 | ||
769 | /* Dump PARTS to FILE. */ | |
770 | ||
771 | extern void dump_mem_address (FILE *, struct mem_address *); | |
772 | void | |
773 | dump_mem_address (FILE *file, struct mem_address *parts) | |
774 | { | |
775 | if (parts->symbol) | |
776 | { | |
777 | fprintf (file, "symbol: "); | |
778 | print_generic_expr (file, parts->symbol, TDF_SLIM); | |
779 | fprintf (file, "\n"); | |
780 | } | |
781 | if (parts->base) | |
782 | { | |
783 | fprintf (file, "base: "); | |
784 | print_generic_expr (file, parts->base, TDF_SLIM); | |
785 | fprintf (file, "\n"); | |
786 | } | |
787 | if (parts->index) | |
788 | { | |
789 | fprintf (file, "index: "); | |
790 | print_generic_expr (file, parts->index, TDF_SLIM); | |
791 | fprintf (file, "\n"); | |
792 | } | |
793 | if (parts->step) | |
794 | { | |
795 | fprintf (file, "step: "); | |
796 | print_generic_expr (file, parts->step, TDF_SLIM); | |
797 | fprintf (file, "\n"); | |
798 | } | |
799 | if (parts->offset) | |
800 | { | |
801 | fprintf (file, "offset: "); | |
802 | print_generic_expr (file, parts->offset, TDF_SLIM); | |
803 | fprintf (file, "\n"); | |
804 | } | |
805 | } | |
806 | ||
807 | #include "gt-tree-ssa-address.h" |