]>
Commit | Line | Data |
---|---|---|
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 | |
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 | |
9dcd6f09 | 8 | Free Software Foundation; either version 3, or (at your option) any |
ac182688 ZD |
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 | |
9dcd6f09 NC |
17 | along 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 | 73 | struct 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 | ||
84 | static 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 | ||
97 | static void | |
98 | gen_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 | ||
177 | rtx | |
178 | addr_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 | ||
247 | tree | |
248 | tree_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 | ||
307 | static bool | |
308 | valid_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 | ||
323 | static tree | |
324 | create_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 | ||
342 | static bool | |
343 | fixed_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 | |
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 | { | |
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 | |
438 | static void | |
f40751dd JH |
439 | most_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 | |
514 | static void | |
f40751dd | 515 | addr_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 | ||
558 | static void | |
726a989a | 559 | gimplify_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 | ||
575 | tree | |
f40751dd JH |
576 | create_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 | ||
696 | void | |
697 | get_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 | ||
708 | void | |
709 | copy_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 | ||
718 | tree | |
719 | maybe_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 | ||
775 | extern void dump_mem_address (FILE *, struct mem_address *); | |
776 | void | |
777 | dump_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" |