Line data Source code
1 : /* Memory address lowering and addressing mode selection.
2 : Copyright (C) 2004-2026 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 "backend.h"
27 : #include "target.h"
28 : #include "rtl.h"
29 : #include "tree.h"
30 : #include "gimple.h"
31 : #include "memmodel.h"
32 : #include "stringpool.h"
33 : #include "tree-vrp.h"
34 : #include "tree-ssanames.h"
35 : #include "expmed.h"
36 : #include "insn-config.h"
37 : #include "emit-rtl.h"
38 : #include "recog.h"
39 : #include "tree-pretty-print.h"
40 : #include "fold-const.h"
41 : #include "stor-layout.h"
42 : #include "gimple-iterator.h"
43 : #include "gimplify-me.h"
44 : #include "tree-ssa-loop-ivopts.h"
45 : #include "expr.h"
46 : #include "tree-dfa.h"
47 : #include "dumpfile.h"
48 : #include "tree-affine.h"
49 : #include "gimplify.h"
50 : #include "builtins.h"
51 :
52 : /* FIXME: We compute address costs using RTL. */
53 : #include "tree-ssa-address.h"
54 :
55 : /* TODO -- handling of symbols (according to Richard Hendersons
56 : comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html):
57 :
58 : There are at least 5 different kinds of symbols that we can run up against:
59 :
60 : (1) binds_local_p, small data area.
61 : (2) binds_local_p, eg local statics
62 : (3) !binds_local_p, eg global variables
63 : (4) thread local, local_exec
64 : (5) thread local, !local_exec
65 :
66 : Now, (1) won't appear often in an array context, but it certainly can.
67 : All you have to do is set -GN high enough, or explicitly mark any
68 : random object __attribute__((section (".sdata"))).
69 :
70 : All of these affect whether or not a symbol is in fact a valid address.
71 : The only one tested here is (3). And that result may very well
72 : be incorrect for (4) or (5).
73 :
74 : An incorrect result here does not cause incorrect results out the
75 : back end, because the expander in expr.cc validizes the address. However
76 : it would be nice to improve the handling here in order to produce more
77 : precise results. */
78 :
79 : /* A "template" for memory address, used to determine whether the address is
80 : valid for mode. */
81 :
82 : struct GTY (()) mem_addr_template {
83 : rtx ref; /* The template. */
84 : rtx * GTY ((skip)) step_p; /* The point in template where the step should be
85 : filled in. */
86 : rtx * GTY ((skip)) off_p; /* The point in template where the offset should
87 : be filled in. */
88 : };
89 :
90 :
91 : /* The templates. Each of the low five bits of the index corresponds to one
92 : component of TARGET_MEM_REF being present, while the high bits identify
93 : the address space. See TEMPL_IDX. */
94 :
95 : static GTY(()) vec<mem_addr_template, va_gc> *mem_addr_template_list;
96 :
97 : #define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \
98 : (((int) (AS) << 5) \
99 : | ((SYMBOL != 0) << 4) \
100 : | ((BASE != 0) << 3) \
101 : | ((INDEX != 0) << 2) \
102 : | ((STEP != 0) << 1) \
103 : | (OFFSET != 0))
104 :
105 : /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX,
106 : STEP and OFFSET to *ADDR using address mode ADDRESS_MODE. Stores pointers
107 : to where step is placed to *STEP_P and offset to *OFFSET_P. */
108 :
109 : static void
110 1047021 : gen_addr_rtx (machine_mode address_mode,
111 : rtx symbol, rtx base, rtx index, rtx step, rtx offset,
112 : rtx *addr, rtx **step_p, rtx **offset_p)
113 : {
114 1047021 : rtx act_elem;
115 :
116 1047021 : *addr = NULL_RTX;
117 1047021 : if (step_p)
118 190284 : *step_p = NULL;
119 1047021 : if (offset_p)
120 190284 : *offset_p = NULL;
121 :
122 1047021 : if (index && index != const0_rtx)
123 : {
124 556191 : act_elem = index;
125 556191 : if (step)
126 : {
127 272856 : act_elem = gen_rtx_MULT (address_mode, act_elem, step);
128 :
129 272856 : if (step_p)
130 68100 : *step_p = &XEXP (act_elem, 1);
131 : }
132 :
133 556191 : *addr = act_elem;
134 : }
135 :
136 1047021 : if (base && base != const0_rtx)
137 : {
138 841901 : if (*addr)
139 351296 : *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
140 : else
141 490605 : *addr = base;
142 : }
143 :
144 1047021 : if (symbol)
145 : {
146 220431 : act_elem = symbol;
147 220431 : if (offset)
148 : {
149 54467 : act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
150 :
151 54467 : if (offset_p)
152 13448 : *offset_p = &XEXP (act_elem, 1);
153 :
154 54467 : if (GET_CODE (symbol) == SYMBOL_REF
155 54467 : || GET_CODE (symbol) == LABEL_REF
156 17766 : || GET_CODE (symbol) == CONST)
157 36701 : act_elem = gen_rtx_CONST (address_mode, act_elem);
158 : }
159 :
160 220431 : if (*addr)
161 220206 : *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
162 : else
163 225 : *addr = act_elem;
164 : }
165 826590 : else if (offset)
166 : {
167 361831 : if (*addr)
168 : {
169 361831 : *addr = gen_rtx_PLUS (address_mode, *addr, offset);
170 361831 : if (offset_p)
171 67993 : *offset_p = &XEXP (*addr, 1);
172 : }
173 : else
174 : {
175 0 : *addr = offset;
176 0 : if (offset_p)
177 0 : *offset_p = addr;
178 : }
179 : }
180 :
181 1047021 : if (!*addr)
182 0 : *addr = const0_rtx;
183 1047021 : }
184 :
185 : /* Returns address for TARGET_MEM_REF with parameters given by ADDR
186 : in address space AS.
187 : If REALLY_EXPAND is false, just make fake registers instead
188 : of really expanding the operands, and perform the expansion in-place
189 : by using one of the "templates". */
190 :
191 : rtx
192 18862733 : addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
193 : bool really_expand)
194 : {
195 18862733 : scalar_int_mode address_mode = targetm.addr_space.address_mode (as);
196 18862733 : scalar_int_mode pointer_mode = targetm.addr_space.pointer_mode (as);
197 18862733 : rtx address, sym, bse, idx, st, off;
198 18862733 : struct mem_addr_template *templ;
199 :
200 18862733 : if (addr->step && !integer_onep (addr->step))
201 5646578 : st = immed_wide_int_const (wi::to_wide (addr->step), pointer_mode);
202 : else
203 : st = NULL_RTX;
204 :
205 18862733 : if (addr->offset && !integer_zerop (addr->offset))
206 : {
207 7990811 : poly_offset_int dc
208 7990811 : = poly_offset_int::from (wi::to_poly_wide (addr->offset), SIGNED);
209 7990811 : off = immed_wide_int_const (dc, pointer_mode);
210 : }
211 : else
212 : off = NULL_RTX;
213 :
214 18862733 : if (!really_expand)
215 : {
216 36011992 : unsigned int templ_index
217 39325069 : = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
218 :
219 18005996 : if (templ_index >= vec_safe_length (mem_addr_template_list))
220 105020 : vec_safe_grow_cleared (mem_addr_template_list, templ_index + 1, true);
221 :
222 : /* Reuse the templates for addresses, so that we do not waste memory. */
223 18005996 : templ = &(*mem_addr_template_list)[templ_index];
224 18005996 : if (!templ->ref)
225 : {
226 190284 : sym = (addr->symbol ?
227 30129 : gen_rtx_SYMBOL_REF (pointer_mode, ggc_strdup ("test_symbol"))
228 : : NULL_RTX);
229 190284 : bse = (addr->base ?
230 165019 : gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 1)
231 : : NULL_RTX);
232 190284 : idx = (addr->index ?
233 138732 : gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 2)
234 : : NULL_RTX);
235 :
236 190284 : gen_addr_rtx (pointer_mode, sym, bse, idx,
237 : st? const0_rtx : NULL_RTX,
238 : off? const0_rtx : NULL_RTX,
239 : &templ->ref,
240 : &templ->step_p,
241 : &templ->off_p);
242 : }
243 :
244 18005996 : if (st)
245 5441822 : *templ->step_p = st;
246 18005996 : if (off)
247 7655954 : *templ->off_p = off;
248 :
249 18005996 : return templ->ref;
250 : }
251 :
252 : /* Otherwise really expand the expressions. */
253 856737 : sym = (addr->symbol
254 856737 : ? expand_expr (addr->symbol, NULL_RTX, pointer_mode, EXPAND_NORMAL)
255 : : NULL_RTX);
256 856737 : bse = (addr->base
257 856737 : ? expand_expr (addr->base, NULL_RTX, pointer_mode, EXPAND_NORMAL)
258 : : NULL_RTX);
259 856737 : idx = (addr->index
260 856737 : ? expand_expr (addr->index, NULL_RTX, pointer_mode, EXPAND_NORMAL)
261 : : NULL_RTX);
262 :
263 : /* addr->base could be an SSA_NAME that was set to a constant value. The
264 : call to expand_expr may expose that constant. If so, fold the value
265 : into OFF and clear BSE. Otherwise we may later try to pull a mode from
266 : BSE to generate a REG, which won't work with constants because they
267 : are modeless. */
268 856737 : if (bse && GET_CODE (bse) == CONST_INT)
269 : {
270 0 : if (off)
271 0 : off = simplify_gen_binary (PLUS, pointer_mode, bse, off);
272 : else
273 : off = bse;
274 0 : gcc_assert (GET_CODE (off) == CONST_INT);
275 : bse = NULL_RTX;
276 : }
277 856737 : gen_addr_rtx (pointer_mode, sym, bse, idx, st, off, &address, NULL, NULL);
278 856737 : if (pointer_mode != address_mode)
279 7 : address = convert_memory_address (address_mode, address);
280 856737 : return address;
281 : }
282 :
283 : /* implement addr_for_mem_ref() directly from a tree, which avoids exporting
284 : the mem_address structure. */
285 :
286 : rtx
287 856737 : addr_for_mem_ref (tree exp, addr_space_t as, bool really_expand)
288 : {
289 856737 : struct mem_address addr;
290 856737 : get_address_description (exp, &addr);
291 856737 : return addr_for_mem_ref (&addr, as, really_expand);
292 : }
293 :
294 : /* Returns address of MEM_REF in TYPE. */
295 :
296 : tree
297 67103 : tree_mem_ref_addr (tree type, tree mem_ref)
298 : {
299 67103 : tree addr;
300 67103 : tree act_elem;
301 67103 : tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
302 67103 : tree addr_base = NULL_TREE, addr_off = NULL_TREE;
303 :
304 67103 : addr_base = fold_convert (type, TMR_BASE (mem_ref));
305 :
306 67103 : act_elem = TMR_INDEX (mem_ref);
307 67103 : if (act_elem)
308 : {
309 3043 : if (step)
310 2346 : act_elem = fold_build2 (MULT_EXPR, TREE_TYPE (act_elem),
311 : act_elem, step);
312 : addr_off = act_elem;
313 : }
314 :
315 67103 : act_elem = TMR_INDEX2 (mem_ref);
316 67103 : if (act_elem)
317 : {
318 0 : if (addr_off)
319 0 : addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off),
320 : addr_off, act_elem);
321 : else
322 : addr_off = act_elem;
323 : }
324 :
325 67103 : if (offset && !integer_zerop (offset))
326 : {
327 50160 : if (addr_off)
328 629 : addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off), addr_off,
329 : fold_convert (TREE_TYPE (addr_off), offset));
330 : else
331 : addr_off = offset;
332 : }
333 :
334 67103 : if (addr_off)
335 52574 : addr = fold_build_pointer_plus (addr_base, addr_off);
336 : else
337 : addr = addr_base;
338 :
339 67103 : return addr;
340 : }
341 :
342 : /* Returns true if a memory reference in MODE and with parameters given by
343 : ADDR is valid on the current target. */
344 :
345 : bool
346 11378599 : valid_mem_ref_p (machine_mode mode, addr_space_t as,
347 : struct mem_address *addr, code_helper ch)
348 : {
349 11378599 : rtx address;
350 :
351 11378599 : address = addr_for_mem_ref (addr, as, false);
352 11378599 : if (!address)
353 : return false;
354 :
355 11378599 : return memory_address_addr_space_p (mode, address, as, ch);
356 : }
357 :
358 : /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
359 : is valid on the current target and if so, creates and returns the
360 : TARGET_MEM_REF. If VERIFY is false omit the verification step. */
361 :
362 : static tree
363 904068 : create_mem_ref_raw (tree type, tree alias_ptr_type, struct mem_address *addr,
364 : bool verify)
365 : {
366 904068 : tree base, index2;
367 :
368 904068 : if (verify
369 904068 : && !valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
370 38010 : return NULL_TREE;
371 :
372 866058 : if (addr->offset)
373 350906 : addr->offset = fold_convert (alias_ptr_type, addr->offset);
374 : else
375 515152 : addr->offset = build_int_cst (alias_ptr_type, 0);
376 :
377 866058 : if (addr->symbol)
378 : {
379 110270 : base = addr->symbol;
380 110270 : index2 = addr->base;
381 : }
382 755788 : else if (addr->base
383 755788 : && POINTER_TYPE_P (TREE_TYPE (addr->base)))
384 : {
385 : base = addr->base;
386 : index2 = NULL_TREE;
387 : }
388 : else
389 : {
390 14 : base = build_int_cst (build_pointer_type (type), 0);
391 14 : index2 = addr->base;
392 : }
393 :
394 : /* If possible use a plain MEM_REF instead of a TARGET_MEM_REF.
395 : ??? As IVOPTs does not follow restrictions to where the base
396 : pointer may point to create a MEM_REF only if we know that
397 : base is valid. */
398 674248 : if ((TREE_CODE (base) == ADDR_EXPR || TREE_CODE (base) == INTEGER_CST)
399 191824 : && (!index2 || integer_zerop (index2))
400 1047336 : && (!addr->index || integer_zerop (addr->index)))
401 900 : return fold_build2 (MEM_REF, type, base, addr->offset);
402 :
403 865158 : return build5 (TARGET_MEM_REF, type,
404 865158 : base, addr->offset, addr->index, addr->step, index2);
405 : }
406 :
407 : /* Returns true if OBJ is an object whose address is a link time constant. */
408 :
409 : static bool
410 1640644 : fixed_address_object_p (tree obj)
411 : {
412 1640644 : return (VAR_P (obj)
413 1603050 : && (TREE_STATIC (obj) || DECL_EXTERNAL (obj))
414 2264961 : && ! DECL_DLLIMPORT_P (obj));
415 : }
416 :
417 : /* If ADDR contains an address of object that is a link time constant,
418 : move it to PARTS->symbol. */
419 :
420 : void
421 4534574 : move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
422 : {
423 4534574 : unsigned i;
424 4534574 : tree val = NULL_TREE;
425 :
426 9674677 : for (i = 0; i < addr->n; i++)
427 : {
428 5764420 : if (addr->elts[i].coef != 1)
429 1213178 : continue;
430 :
431 4551242 : val = addr->elts[i].val;
432 4551242 : if (TREE_CODE (val) == ADDR_EXPR
433 4551242 : && fixed_address_object_p (TREE_OPERAND (val, 0)))
434 : break;
435 : }
436 :
437 4534574 : if (i == addr->n)
438 : return;
439 :
440 624317 : parts->symbol = val;
441 624317 : aff_combination_remove_elt (addr, i);
442 : }
443 :
444 : /* Return true if ADDR contains an instance of BASE_HINT and it's moved to
445 : PARTS->base. */
446 :
447 : static bool
448 464733 : move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
449 : aff_tree *addr)
450 : {
451 464733 : unsigned i;
452 464733 : tree val = NULL_TREE;
453 464733 : int qual;
454 :
455 487810 : for (i = 0; i < addr->n; i++)
456 : {
457 487796 : if (addr->elts[i].coef != 1)
458 22512 : continue;
459 :
460 465284 : val = addr->elts[i].val;
461 465284 : if (operand_equal_p (val, base_hint, 0))
462 : break;
463 : }
464 :
465 464733 : if (i == addr->n)
466 : return false;
467 :
468 : /* Cast value to appropriate pointer type. We cannot use a pointer
469 : to TYPE directly, as the back-end will assume registers of pointer
470 : type are aligned, and just the base itself may not actually be.
471 : We use void pointer to the type's address space instead. */
472 464719 : qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
473 464719 : type = build_qualified_type (void_type_node, qual);
474 464719 : parts->base = fold_convert (build_pointer_type (type), val);
475 464719 : aff_combination_remove_elt (addr, i);
476 464719 : return true;
477 : }
478 :
479 : /* If ADDR contains an address of a dereferenced pointer, move it to
480 : PARTS->base. */
481 :
482 : static void
483 289508 : move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
484 : {
485 289508 : unsigned i;
486 289508 : tree val = NULL_TREE;
487 :
488 316822 : for (i = 0; i < addr->n; i++)
489 : {
490 316808 : if (addr->elts[i].coef != 1)
491 25878 : continue;
492 :
493 290930 : val = addr->elts[i].val;
494 290930 : if (POINTER_TYPE_P (TREE_TYPE (val)))
495 : break;
496 : }
497 :
498 289508 : if (i == addr->n)
499 : return;
500 :
501 289494 : parts->base = val;
502 289494 : aff_combination_remove_elt (addr, i);
503 : }
504 :
505 : /* Moves the loop variant part V in linear address ADDR to be the index
506 : of PARTS. */
507 :
508 : static void
509 399720 : move_variant_to_index (struct mem_address *parts, aff_tree *addr, tree v)
510 : {
511 399720 : unsigned i;
512 399720 : tree val = NULL_TREE;
513 :
514 399720 : gcc_assert (!parts->index);
515 737657 : for (i = 0; i < addr->n; i++)
516 : {
517 737334 : val = addr->elts[i].val;
518 737334 : if (operand_equal_p (val, v, 0))
519 : break;
520 : }
521 :
522 399720 : if (i == addr->n)
523 : return;
524 :
525 399397 : parts->index = fold_convert (sizetype, val);
526 399397 : parts->step = wide_int_to_tree (sizetype, addr->elts[i].coef);
527 399397 : aff_combination_remove_elt (addr, i);
528 : }
529 :
530 : /* Adds ELT to PARTS. */
531 :
532 : static void
533 60689 : add_to_parts (struct mem_address *parts, tree elt)
534 : {
535 60689 : tree type;
536 :
537 60689 : if (!parts->index)
538 : {
539 7360 : parts->index = fold_convert (sizetype, elt);
540 7360 : return;
541 : }
542 :
543 53329 : if (!parts->base)
544 : {
545 10581 : parts->base = elt;
546 10581 : return;
547 : }
548 :
549 : /* Add ELT to base. As we have arbitrarily associated address parts
550 : make sure to use unsigned arithmetic. */
551 42748 : type = TREE_TYPE (parts->base);
552 42748 : if (POINTER_TYPE_P (type))
553 37514 : parts->base
554 37514 : = fold_convert (TREE_TYPE (parts->base),
555 : fold_build2 (PLUS_EXPR, sizetype,
556 : fold_convert (sizetype, parts->base),
557 : fold_convert (sizetype, elt)));
558 : else
559 5234 : parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
560 : }
561 :
562 : /* Returns true if multiplying by RATIO is allowed in an address. Test the
563 : validity for a memory reference accessing memory of mode MODE in address
564 : space AS. */
565 :
566 : static bool
567 22965 : multiplier_allowed_in_address_p (HOST_WIDE_INT ratio, machine_mode mode,
568 : addr_space_t as)
569 : {
570 : #define MAX_RATIO 128
571 22965 : unsigned int data_index = (int) as * MAX_MACHINE_MODE + (int) mode;
572 22965 : static vec<sbitmap> valid_mult_list;
573 22965 : sbitmap valid_mult;
574 :
575 22965 : if (data_index >= valid_mult_list.length ())
576 1075 : valid_mult_list.safe_grow_cleared (data_index + 1, true);
577 :
578 22965 : valid_mult = valid_mult_list[data_index];
579 22965 : if (!valid_mult)
580 : {
581 1190 : machine_mode address_mode = targetm.addr_space.address_mode (as);
582 1190 : rtx reg1 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1);
583 1190 : rtx reg2 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2);
584 1190 : rtx addr, scaled;
585 1190 : HOST_WIDE_INT i;
586 :
587 1190 : valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
588 1190 : bitmap_clear (valid_mult);
589 1190 : scaled = gen_rtx_fmt_ee (MULT, address_mode, reg1, NULL_RTX);
590 1190 : addr = gen_rtx_fmt_ee (PLUS, address_mode, scaled, reg2);
591 307020 : for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
592 : {
593 305830 : XEXP (scaled, 1) = gen_int_mode (i, address_mode);
594 305830 : if (memory_address_addr_space_p (mode, addr, as)
595 305830 : || memory_address_addr_space_p (mode, scaled, as))
596 4760 : bitmap_set_bit (valid_mult, i + MAX_RATIO);
597 : }
598 :
599 1190 : if (dump_file && (dump_flags & TDF_DETAILS))
600 : {
601 0 : fprintf (dump_file, " allowed multipliers:");
602 0 : for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
603 0 : if (bitmap_bit_p (valid_mult, i + MAX_RATIO))
604 0 : fprintf (dump_file, " %d", (int) i);
605 0 : fprintf (dump_file, "\n");
606 0 : fprintf (dump_file, "\n");
607 : }
608 :
609 1190 : valid_mult_list[data_index] = valid_mult;
610 : }
611 :
612 22965 : if (ratio > MAX_RATIO || ratio < -MAX_RATIO)
613 : return false;
614 :
615 22235 : return bitmap_bit_p (valid_mult, ratio + MAX_RATIO);
616 : }
617 :
618 : /* Finds the most expensive multiplication in ADDR that can be
619 : expressed in an addressing mode and move the corresponding
620 : element(s) to PARTS. */
621 :
622 : static void
623 465056 : most_expensive_mult_to_index (tree type, struct mem_address *parts,
624 : aff_tree *addr, bool speed)
625 : {
626 465056 : addr_space_t as = TYPE_ADDR_SPACE (type);
627 465056 : machine_mode address_mode = targetm.addr_space.address_mode (as);
628 465056 : HOST_WIDE_INT coef;
629 465056 : unsigned best_mult_cost = 0, acost;
630 465056 : tree mult_elt = NULL_TREE, elt;
631 465056 : unsigned i, j;
632 465056 : enum tree_code op_code;
633 :
634 465056 : offset_int best_mult = 0;
635 488888 : for (i = 0; i < addr->n; i++)
636 : {
637 23832 : if (!wi::fits_shwi_p (addr->elts[i].coef))
638 0 : continue;
639 :
640 23832 : coef = addr->elts[i].coef.to_shwi ();
641 38964 : if (coef == 1
642 23832 : || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
643 15132 : continue;
644 :
645 8700 : acost = mult_by_coeff_cost (coef, address_mode, speed);
646 :
647 8700 : if (acost > best_mult_cost)
648 : {
649 8542 : best_mult_cost = acost;
650 8542 : best_mult = offset_int::from (addr->elts[i].coef, SIGNED);
651 : }
652 : }
653 :
654 465056 : if (!best_mult_cost)
655 456514 : return;
656 :
657 : /* Collect elements multiplied by best_mult. */
658 20988 : for (i = j = 0; i < addr->n; i++)
659 : {
660 12446 : offset_int amult = offset_int::from (addr->elts[i].coef, SIGNED);
661 12446 : offset_int amult_neg = -wi::sext (amult, TYPE_PRECISION (addr->type));
662 :
663 12446 : if (amult == best_mult)
664 : op_code = PLUS_EXPR;
665 3778 : else if (amult_neg == best_mult)
666 : op_code = MINUS_EXPR;
667 : else
668 : {
669 293 : addr->elts[j] = addr->elts[i];
670 293 : j++;
671 293 : continue;
672 : }
673 :
674 12153 : elt = fold_convert (sizetype, addr->elts[i].val);
675 12153 : if (mult_elt)
676 3611 : mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
677 8542 : else if (op_code == PLUS_EXPR)
678 : mult_elt = elt;
679 : else
680 790 : mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
681 : }
682 8542 : addr->n = j;
683 :
684 8542 : parts->index = mult_elt;
685 8542 : parts->step = wide_int_to_tree (sizetype, best_mult);
686 : }
687 :
688 : /* Splits address ADDR for a memory access of type TYPE into PARTS.
689 : If BASE_HINT is non-NULL, it specifies an SSA name to be used
690 : preferentially as base of the reference, and IV_CAND is the selected
691 : iv candidate used in ADDR. Store true to VAR_IN_BASE if variant
692 : part of address is split to PARTS.base.
693 :
694 : TODO -- be more clever about the distribution of the elements of ADDR
695 : to PARTS. Some architectures do not support anything but single
696 : register in address, possibly with a small integer offset; while
697 : create_mem_ref will simplify the address to an acceptable shape
698 : later, it would be more efficient to know that asking for complicated
699 : addressing modes is useless. */
700 :
701 : static void
702 864453 : addr_to_parts (tree type, aff_tree *addr, tree iv_cand, tree base_hint,
703 : struct mem_address *parts, bool *var_in_base, bool speed)
704 : {
705 864453 : tree part;
706 864453 : unsigned i;
707 :
708 864453 : parts->symbol = NULL_TREE;
709 864453 : parts->base = NULL_TREE;
710 864453 : parts->index = NULL_TREE;
711 864453 : parts->step = NULL_TREE;
712 :
713 864453 : if (maybe_ne (addr->offset, 0))
714 349312 : parts->offset = wide_int_to_tree (sizetype, addr->offset);
715 : else
716 515141 : parts->offset = NULL_TREE;
717 :
718 : /* Try to find a symbol. */
719 864453 : move_fixed_address_to_symbol (parts, addr);
720 :
721 : /* Since at the moment there is no reliable way to know how to
722 : distinguish between pointer and its offset, we decide if var
723 : part is the pointer based on guess. */
724 864453 : *var_in_base = (base_hint != NULL && parts->symbol == NULL);
725 864453 : if (*var_in_base)
726 464733 : *var_in_base = move_hint_to_base (type, parts, base_hint, addr);
727 : else
728 399720 : move_variant_to_index (parts, addr, iv_cand);
729 :
730 : /* First move the most expensive feasible multiplication to index. */
731 864453 : if (!parts->index)
732 465056 : most_expensive_mult_to_index (type, parts, addr, speed);
733 :
734 : /* Move pointer into base. */
735 864453 : if (!parts->symbol && !parts->base)
736 289508 : move_pointer_to_base (parts, addr);
737 :
738 : /* Then try to process the remaining elements. */
739 925142 : for (i = 0; i < addr->n; i++)
740 : {
741 60689 : part = fold_convert (sizetype, addr->elts[i].val);
742 60689 : if (addr->elts[i].coef != 1)
743 57843 : part = fold_build2 (MULT_EXPR, sizetype, part,
744 : wide_int_to_tree (sizetype, addr->elts[i].coef));
745 60689 : add_to_parts (parts, part);
746 : }
747 864453 : if (addr->rest)
748 0 : add_to_parts (parts, fold_convert (sizetype, addr->rest));
749 864453 : }
750 :
751 : /* Force the PARTS to register. */
752 :
753 : static void
754 864453 : gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
755 : {
756 864453 : if (parts->base)
757 764794 : parts->base = force_gimple_operand_gsi_1 (gsi, parts->base,
758 : is_gimple_mem_ref_addr, NULL_TREE,
759 : true, GSI_SAME_STMT);
760 864453 : if (parts->index)
761 415299 : parts->index = force_gimple_operand_gsi (gsi, parts->index,
762 : true, NULL_TREE,
763 : true, GSI_SAME_STMT);
764 864453 : }
765 :
766 : /* Return true if the OFFSET in PARTS is the only thing that is making
767 : it an invalid address for type TYPE. */
768 :
769 : static bool
770 24012 : mem_ref_valid_without_offset_p (tree type, mem_address parts)
771 : {
772 24012 : if (!parts.base)
773 0 : parts.base = parts.offset;
774 24012 : parts.offset = NULL_TREE;
775 24012 : return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), &parts);
776 : }
777 :
778 : /* Fold PARTS->offset into PARTS->base, so that there is no longer
779 : a separate offset. Emit any new instructions before GSI. */
780 :
781 : static void
782 0 : add_offset_to_base (gimple_stmt_iterator *gsi, mem_address *parts)
783 : {
784 0 : tree tmp = parts->offset;
785 0 : if (parts->base)
786 : {
787 0 : tmp = fold_build_pointer_plus (parts->base, tmp);
788 0 : tmp = force_gimple_operand_gsi_1 (gsi, tmp, is_gimple_mem_ref_addr,
789 : NULL_TREE, true, GSI_SAME_STMT);
790 : }
791 0 : parts->base = tmp;
792 0 : parts->offset = NULL_TREE;
793 0 : }
794 :
795 : /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
796 : computations are emitted in front of GSI. TYPE is the mode
797 : of created memory reference. IV_CAND is the selected iv candidate in ADDR,
798 : and BASE_HINT is non NULL if IV_CAND comes from a base address
799 : object. */
800 :
801 : tree
802 864453 : create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
803 : tree alias_ptr_type, tree iv_cand, tree base_hint, bool speed)
804 : {
805 864453 : bool var_in_base;
806 864453 : tree mem_ref, tmp;
807 864453 : struct mem_address parts;
808 :
809 864453 : addr_to_parts (type, addr, iv_cand, base_hint, &parts, &var_in_base, speed);
810 864453 : gimplify_mem_ref_parts (gsi, &parts);
811 864453 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
812 864453 : if (mem_ref)
813 : return mem_ref;
814 :
815 : /* The expression is too complicated. Try making it simpler. */
816 :
817 : /* Merge symbol into other parts. */
818 37420 : if (parts.symbol)
819 : {
820 909 : tmp = parts.symbol;
821 909 : parts.symbol = NULL_TREE;
822 909 : gcc_assert (is_gimple_val (tmp));
823 :
824 909 : if (parts.base)
825 : {
826 35 : gcc_assert (useless_type_conversion_p (sizetype,
827 : TREE_TYPE (parts.base)));
828 :
829 35 : if (parts.index)
830 : {
831 : /* Add the symbol to base, eventually forcing it to register. */
832 35 : tmp = fold_build_pointer_plus (tmp, parts.base);
833 35 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
834 : is_gimple_mem_ref_addr,
835 : NULL_TREE, true,
836 : GSI_SAME_STMT);
837 : }
838 : else
839 : {
840 : /* Move base to index, then move the symbol to base. */
841 0 : parts.index = parts.base;
842 : }
843 35 : parts.base = tmp;
844 : }
845 : else
846 874 : parts.base = tmp;
847 :
848 909 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
849 909 : if (mem_ref)
850 : return mem_ref;
851 : }
852 :
853 : /* Move multiplication to index by transforming address expression:
854 : [... + index << step + ...]
855 : into:
856 : index' = index << step;
857 : [... + index' + ,,,]. */
858 37101 : if (parts.step && !integer_onep (parts.step))
859 : {
860 37090 : gcc_assert (parts.index);
861 37090 : if (parts.offset && mem_ref_valid_without_offset_p (type, parts))
862 : {
863 0 : add_offset_to_base (gsi, &parts);
864 0 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
865 0 : gcc_assert (mem_ref);
866 : return mem_ref;
867 : }
868 :
869 37090 : parts.index = force_gimple_operand_gsi (gsi,
870 : fold_build2 (MULT_EXPR, sizetype,
871 : parts.index, parts.step),
872 : true, NULL_TREE, true, GSI_SAME_STMT);
873 37090 : parts.step = NULL_TREE;
874 :
875 37090 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
876 37090 : if (mem_ref)
877 : return mem_ref;
878 : }
879 :
880 : /* Add offset to invariant part by transforming address expression:
881 : [base + index + offset]
882 : into:
883 : base' = base + offset;
884 : [base' + index]
885 : or:
886 : index' = index + offset;
887 : [base + index']
888 : depending on which one is invariant. */
889 11 : if (parts.offset && !integer_zerop (parts.offset))
890 : {
891 11 : tree old_base = unshare_expr (parts.base);
892 11 : tree old_index = unshare_expr (parts.index);
893 11 : tree old_offset = unshare_expr (parts.offset);
894 :
895 11 : tmp = parts.offset;
896 11 : parts.offset = NULL_TREE;
897 : /* Add offset to invariant part. */
898 11 : if (!var_in_base)
899 : {
900 5 : if (parts.base)
901 : {
902 5 : tmp = fold_build_pointer_plus (parts.base, tmp);
903 5 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
904 : is_gimple_mem_ref_addr,
905 : NULL_TREE, true,
906 : GSI_SAME_STMT);
907 : }
908 5 : parts.base = tmp;
909 : }
910 : else
911 : {
912 6 : if (parts.index)
913 : {
914 0 : tmp = fold_build_pointer_plus (parts.index, tmp);
915 0 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
916 : is_gimple_mem_ref_addr,
917 : NULL_TREE, true,
918 : GSI_SAME_STMT);
919 : }
920 6 : parts.index = tmp;
921 : }
922 :
923 11 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
924 11 : if (mem_ref)
925 : return mem_ref;
926 :
927 : /* Restore parts.base, index and offset so that we can check if
928 : [base + offset] addressing mode is supported in next step.
929 : This is necessary for targets only support [base + offset],
930 : but not [base + index] addressing mode. */
931 0 : parts.base = old_base;
932 0 : parts.index = old_index;
933 0 : parts.offset = old_offset;
934 : }
935 :
936 : /* Transform [base + index + ...] into:
937 : base' = base + index;
938 : [base' + ...]. */
939 0 : if (parts.index)
940 : {
941 0 : tmp = parts.index;
942 0 : parts.index = NULL_TREE;
943 : /* Add index to base. */
944 0 : if (parts.base)
945 : {
946 0 : tmp = fold_build_pointer_plus (parts.base, tmp);
947 0 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
948 : is_gimple_mem_ref_addr,
949 : NULL_TREE, true, GSI_SAME_STMT);
950 : }
951 0 : parts.base = tmp;
952 :
953 0 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
954 0 : if (mem_ref)
955 : return mem_ref;
956 : }
957 :
958 : /* Transform [base + offset] into:
959 : base' = base + offset;
960 : [base']. */
961 0 : if (parts.offset && !integer_zerop (parts.offset))
962 : {
963 0 : add_offset_to_base (gsi, &parts);
964 0 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
965 0 : if (mem_ref)
966 : return mem_ref;
967 : }
968 :
969 : /* Verify that the address is in the simplest possible shape
970 : (only a register). If we cannot create such a memory reference,
971 : something is really wrong. */
972 0 : gcc_assert (parts.symbol == NULL_TREE);
973 0 : gcc_assert (parts.index == NULL_TREE);
974 0 : gcc_assert (!parts.step || integer_onep (parts.step));
975 0 : gcc_assert (!parts.offset || integer_zerop (parts.offset));
976 0 : gcc_unreachable ();
977 : }
978 :
979 : /* Copies components of the address from OP to ADDR. */
980 :
981 : void
982 2834737 : get_address_description (tree op, struct mem_address *addr)
983 : {
984 2834737 : if (TREE_CODE (TMR_BASE (op)) == ADDR_EXPR)
985 : {
986 601801 : addr->symbol = TMR_BASE (op);
987 601801 : addr->base = TMR_INDEX2 (op);
988 : }
989 : else
990 : {
991 2232936 : addr->symbol = NULL_TREE;
992 2232936 : if (TMR_INDEX2 (op))
993 : {
994 58 : gcc_assert (integer_zerop (TMR_BASE (op)));
995 58 : addr->base = TMR_INDEX2 (op);
996 : }
997 : else
998 2232878 : addr->base = TMR_BASE (op);
999 : }
1000 2834737 : addr->index = TMR_INDEX (op);
1001 2834737 : addr->step = TMR_STEP (op);
1002 2834737 : addr->offset = TMR_OFFSET (op);
1003 2834737 : }
1004 :
1005 : /* Copies the reference information from OLD_REF to NEW_REF, where
1006 : NEW_REF should be either a MEM_REF or a TARGET_MEM_REF. */
1007 :
1008 : void
1009 909232 : copy_ref_info (tree new_ref, tree old_ref)
1010 : {
1011 909232 : tree new_ptr_base = NULL_TREE;
1012 :
1013 909232 : gcc_assert (TREE_CODE (new_ref) == MEM_REF
1014 : || TREE_CODE (new_ref) == TARGET_MEM_REF);
1015 :
1016 909232 : TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (old_ref);
1017 909232 : TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (old_ref);
1018 :
1019 909232 : new_ptr_base = TREE_OPERAND (new_ref, 0);
1020 :
1021 909232 : tree base = get_base_address (old_ref);
1022 909232 : if (!base)
1023 : return;
1024 :
1025 : /* We can transfer points-to information from an old pointer
1026 : or decl base to the new one. */
1027 909232 : if (new_ptr_base
1028 909232 : && TREE_CODE (new_ptr_base) == SSA_NAME
1029 1609654 : && !SSA_NAME_PTR_INFO (new_ptr_base))
1030 : {
1031 396679 : if ((TREE_CODE (base) == MEM_REF
1032 396679 : || TREE_CODE (base) == TARGET_MEM_REF)
1033 324303 : && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
1034 720982 : && SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)))
1035 : {
1036 304732 : duplicate_ssa_name_ptr_info
1037 304732 : (new_ptr_base, SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)));
1038 304732 : reset_flow_sensitive_info (new_ptr_base);
1039 : }
1040 91947 : else if (VAR_P (base)
1041 : || TREE_CODE (base) == PARM_DECL
1042 : || TREE_CODE (base) == RESULT_DECL)
1043 : {
1044 72376 : struct ptr_info_def *pi = get_ptr_info (new_ptr_base);
1045 72376 : pt_solution_set_var (&pi->pt, base);
1046 : }
1047 : }
1048 :
1049 : /* We can transfer dependence info. */
1050 909232 : if (!MR_DEPENDENCE_CLIQUE (new_ref)
1051 909232 : && (TREE_CODE (base) == MEM_REF
1052 909232 : || TREE_CODE (base) == TARGET_MEM_REF)
1053 1624348 : && MR_DEPENDENCE_CLIQUE (base))
1054 : {
1055 182015 : MR_DEPENDENCE_CLIQUE (new_ref) = MR_DEPENDENCE_CLIQUE (base);
1056 182015 : MR_DEPENDENCE_BASE (new_ref) = MR_DEPENDENCE_BASE (base);
1057 : }
1058 :
1059 : /* And alignment info. Note we cannot transfer misalignment info
1060 : since that sits on the SSA name but this is flow-sensitive info
1061 : which we cannot transfer in this generic routine. */
1062 909232 : unsigned old_align = get_object_alignment (old_ref);
1063 909232 : unsigned new_align = get_object_alignment (new_ref);
1064 909232 : if (new_align < old_align)
1065 719 : TREE_TYPE (new_ref) = build_aligned_type (TREE_TYPE (new_ref), old_align);
1066 : }
1067 :
1068 : /* Move constants in target_mem_ref REF to offset. Returns the new target
1069 : mem ref if anything changes, NULL_TREE otherwise. */
1070 :
1071 : tree
1072 1978000 : maybe_fold_tmr (tree ref)
1073 : {
1074 1978000 : struct mem_address addr;
1075 1978000 : bool changed = false;
1076 1978000 : tree new_ref, off;
1077 :
1078 1978000 : get_address_description (ref, &addr);
1079 :
1080 1978000 : if (addr.base
1081 1597636 : && TREE_CODE (addr.base) == INTEGER_CST
1082 1978053 : && !integer_zerop (addr.base))
1083 : {
1084 53 : addr.offset = fold_binary_to_constant (PLUS_EXPR,
1085 53 : TREE_TYPE (addr.offset),
1086 : addr.offset, addr.base);
1087 53 : addr.base = NULL_TREE;
1088 53 : changed = true;
1089 : }
1090 :
1091 1978000 : if (addr.symbol
1092 1978000 : && TREE_CODE (TREE_OPERAND (addr.symbol, 0)) == MEM_REF)
1093 : {
1094 0 : addr.offset = fold_binary_to_constant
1095 0 : (PLUS_EXPR, TREE_TYPE (addr.offset),
1096 : addr.offset,
1097 0 : TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 1));
1098 0 : addr.symbol = TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 0);
1099 0 : changed = true;
1100 : }
1101 1978000 : else if (addr.symbol
1102 1978000 : && handled_component_p (TREE_OPERAND (addr.symbol, 0)))
1103 : {
1104 0 : poly_int64 offset;
1105 0 : addr.symbol = build_fold_addr_expr
1106 : (get_addr_base_and_unit_offset
1107 : (TREE_OPERAND (addr.symbol, 0), &offset));
1108 0 : addr.offset = int_const_binop (PLUS_EXPR,
1109 0 : addr.offset, size_int (offset));
1110 0 : changed = true;
1111 : }
1112 :
1113 1978000 : if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
1114 : {
1115 1552 : off = addr.index;
1116 1552 : if (addr.step)
1117 : {
1118 1480 : off = fold_binary_to_constant (MULT_EXPR, sizetype,
1119 : off, addr.step);
1120 1480 : addr.step = NULL_TREE;
1121 : }
1122 :
1123 1552 : addr.offset = fold_binary_to_constant (PLUS_EXPR,
1124 1552 : TREE_TYPE (addr.offset),
1125 : addr.offset, off);
1126 1552 : addr.index = NULL_TREE;
1127 1552 : changed = true;
1128 : }
1129 :
1130 1978000 : if (!changed)
1131 : return NULL_TREE;
1132 :
1133 : /* If we have propagated something into this TARGET_MEM_REF and thus
1134 : ended up folding it, always create a new TARGET_MEM_REF regardless
1135 : if it is valid in this for on the target - the propagation result
1136 : wouldn't be anyway. */
1137 1605 : new_ref = create_mem_ref_raw (TREE_TYPE (ref),
1138 1605 : TREE_TYPE (addr.offset), &addr, false);
1139 1605 : TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (ref);
1140 1605 : TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (ref);
1141 1605 : return new_ref;
1142 : }
1143 :
1144 : /* Return the preferred index scale factor for accessing memory of mode
1145 : MEM_MODE in the address space of pointer BASE. Assume that we're
1146 : optimizing for speed if SPEED is true and for size otherwise. */
1147 : unsigned int
1148 532010 : preferred_mem_scale_factor (tree base, machine_mode mem_mode,
1149 : bool speed)
1150 : {
1151 : /* For BLKmode, we can't do anything so return 1. */
1152 532010 : if (mem_mode == BLKmode)
1153 : return 1;
1154 :
1155 523919 : struct mem_address parts = {};
1156 523919 : addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (base));
1157 523919 : unsigned int fact = GET_MODE_UNIT_SIZE (mem_mode);
1158 :
1159 : /* Addressing mode "base + index". */
1160 523919 : parts.index = integer_one_node;
1161 523919 : parts.base = integer_one_node;
1162 523919 : rtx addr = addr_for_mem_ref (&parts, as, false);
1163 523919 : unsigned cost = address_cost (addr, mem_mode, as, speed);
1164 :
1165 : /* Addressing mode "base + index << scale". */
1166 523919 : parts.step = wide_int_to_tree (sizetype, fact);
1167 523919 : addr = addr_for_mem_ref (&parts, as, false);
1168 523919 : unsigned new_cost = address_cost (addr, mem_mode, as, speed);
1169 :
1170 : /* Compare the cost of an address with an unscaled index with
1171 : a scaled index and return factor if useful. */
1172 523919 : if (new_cost < cost)
1173 0 : return GET_MODE_UNIT_SIZE (mem_mode);
1174 : return 1;
1175 : }
1176 :
1177 : /* Dump PARTS to FILE. */
1178 :
1179 : extern void dump_mem_address (FILE *, struct mem_address *);
1180 : void
1181 0 : dump_mem_address (FILE *file, struct mem_address *parts)
1182 : {
1183 0 : if (parts->symbol)
1184 : {
1185 0 : fprintf (file, "symbol: ");
1186 0 : print_generic_expr (file, TREE_OPERAND (parts->symbol, 0), TDF_SLIM);
1187 0 : fprintf (file, "\n");
1188 : }
1189 0 : if (parts->base)
1190 : {
1191 0 : fprintf (file, "base: ");
1192 0 : print_generic_expr (file, parts->base, TDF_SLIM);
1193 0 : fprintf (file, "\n");
1194 : }
1195 0 : if (parts->index)
1196 : {
1197 0 : fprintf (file, "index: ");
1198 0 : print_generic_expr (file, parts->index, TDF_SLIM);
1199 0 : fprintf (file, "\n");
1200 : }
1201 0 : if (parts->step)
1202 : {
1203 0 : fprintf (file, "step: ");
1204 0 : print_generic_expr (file, parts->step, TDF_SLIM);
1205 0 : fprintf (file, "\n");
1206 : }
1207 0 : if (parts->offset)
1208 : {
1209 0 : fprintf (file, "offset: ");
1210 0 : print_generic_expr (file, parts->offset, TDF_SLIM);
1211 0 : fprintf (file, "\n");
1212 : }
1213 0 : }
1214 :
1215 : #include "gt-tree-ssa-address.h"
|