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 1037922 : 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 1037922 : rtx act_elem;
115 :
116 1037922 : *addr = NULL_RTX;
117 1037922 : if (step_p)
118 190210 : *step_p = NULL;
119 1037922 : if (offset_p)
120 190210 : *offset_p = NULL;
121 :
122 1037922 : if (index && index != const0_rtx)
123 : {
124 555357 : act_elem = index;
125 555357 : if (step)
126 : {
127 272044 : act_elem = gen_rtx_MULT (address_mode, act_elem, step);
128 :
129 272044 : if (step_p)
130 68141 : *step_p = &XEXP (act_elem, 1);
131 : }
132 :
133 555357 : *addr = act_elem;
134 : }
135 :
136 1037922 : if (base && base != const0_rtx)
137 : {
138 832638 : if (*addr)
139 350302 : *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
140 : else
141 482336 : *addr = base;
142 : }
143 :
144 1037922 : if (symbol)
145 : {
146 220592 : act_elem = symbol;
147 220592 : if (offset)
148 : {
149 54517 : act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
150 :
151 54517 : if (offset_p)
152 13495 : *offset_p = &XEXP (act_elem, 1);
153 :
154 54517 : if (GET_CODE (symbol) == SYMBOL_REF
155 54517 : || GET_CODE (symbol) == LABEL_REF
156 17791 : || GET_CODE (symbol) == CONST)
157 36726 : act_elem = gen_rtx_CONST (address_mode, act_elem);
158 : }
159 :
160 220592 : if (*addr)
161 220363 : *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
162 : else
163 229 : *addr = act_elem;
164 : }
165 817330 : else if (offset)
166 : {
167 355559 : if (*addr)
168 : {
169 355559 : *addr = gen_rtx_PLUS (address_mode, *addr, offset);
170 355559 : if (offset_p)
171 67904 : *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 1037922 : if (!*addr)
182 0 : *addr = const0_rtx;
183 1037922 : }
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 18597455 : addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
193 : bool really_expand)
194 : {
195 18597455 : scalar_int_mode address_mode = targetm.addr_space.address_mode (as);
196 18597455 : scalar_int_mode pointer_mode = targetm.addr_space.pointer_mode (as);
197 18597455 : rtx address, sym, bse, idx, st, off;
198 18597455 : struct mem_addr_template *templ;
199 :
200 18597455 : if (addr->step && !integer_onep (addr->step))
201 5628815 : st = immed_wide_int_const (wi::to_wide (addr->step), pointer_mode);
202 : else
203 : st = NULL_RTX;
204 :
205 18597455 : if (addr->offset && !integer_zerop (addr->offset))
206 : {
207 7783810 : poly_offset_int dc
208 7783810 : = poly_offset_int::from (wi::to_poly_wide (addr->offset), SIGNED);
209 7783810 : off = immed_wide_int_const (dc, pointer_mode);
210 : }
211 : else
212 : off = NULL_RTX;
213 :
214 18597455 : if (!really_expand)
215 : {
216 35499486 : unsigned int templ_index
217 38647150 : = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
218 :
219 17749743 : if (templ_index >= vec_safe_length (mem_addr_template_list))
220 105017 : 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 17749743 : templ = &(*mem_addr_template_list)[templ_index];
224 17749743 : if (!templ->ref)
225 : {
226 190210 : sym = (addr->symbol ?
227 30235 : gen_rtx_SYMBOL_REF (pointer_mode, ggc_strdup ("test_symbol"))
228 : : NULL_RTX);
229 190210 : bse = (addr->base ?
230 164834 : gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 1)
231 : : NULL_RTX);
232 190210 : idx = (addr->index ?
233 138748 : gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 2)
234 : : NULL_RTX);
235 :
236 190210 : 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 17749743 : if (st)
245 5424912 : *templ->step_p = st;
246 17749743 : if (off)
247 7455133 : *templ->off_p = off;
248 :
249 17749743 : return templ->ref;
250 : }
251 :
252 : /* Otherwise really expand the expressions. */
253 847712 : sym = (addr->symbol
254 847712 : ? expand_expr (addr->symbol, NULL_RTX, pointer_mode, EXPAND_NORMAL)
255 : : NULL_RTX);
256 847712 : bse = (addr->base
257 847712 : ? expand_expr (addr->base, NULL_RTX, pointer_mode, EXPAND_NORMAL)
258 : : NULL_RTX);
259 847712 : idx = (addr->index
260 847712 : ? 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 847712 : 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 847712 : gen_addr_rtx (pointer_mode, sym, bse, idx, st, off, &address, NULL, NULL);
278 847712 : if (pointer_mode != address_mode)
279 7 : address = convert_memory_address (address_mode, address);
280 847712 : 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 847712 : addr_for_mem_ref (tree exp, addr_space_t as, bool really_expand)
288 : {
289 847712 : struct mem_address addr;
290 847712 : get_address_description (exp, &addr);
291 847712 : return addr_for_mem_ref (&addr, as, really_expand);
292 : }
293 :
294 : /* Returns address of MEM_REF in TYPE. */
295 :
296 : tree
297 58805 : tree_mem_ref_addr (tree type, tree mem_ref)
298 : {
299 58805 : tree addr;
300 58805 : tree act_elem;
301 58805 : tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
302 58805 : tree addr_base = NULL_TREE, addr_off = NULL_TREE;
303 :
304 58805 : addr_base = fold_convert (type, TMR_BASE (mem_ref));
305 :
306 58805 : act_elem = TMR_INDEX (mem_ref);
307 58805 : if (act_elem)
308 : {
309 2995 : if (step)
310 2298 : act_elem = fold_build2 (MULT_EXPR, TREE_TYPE (act_elem),
311 : act_elem, step);
312 : addr_off = act_elem;
313 : }
314 :
315 58805 : act_elem = TMR_INDEX2 (mem_ref);
316 58805 : 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 58805 : if (offset && !integer_zerop (offset))
326 : {
327 42101 : if (addr_off)
328 633 : 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 58805 : if (addr_off)
335 44463 : addr = fold_build_pointer_plus (addr_base, addr_off);
336 : else
337 : addr = addr_base;
338 :
339 58805 : 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 11233564 : valid_mem_ref_p (machine_mode mode, addr_space_t as,
347 : struct mem_address *addr, code_helper ch)
348 : {
349 11233564 : rtx address;
350 :
351 11233564 : address = addr_for_mem_ref (addr, as, false);
352 11233564 : if (!address)
353 : return false;
354 :
355 11233564 : 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 893875 : create_mem_ref_raw (tree type, tree alias_ptr_type, struct mem_address *addr,
364 : bool verify)
365 : {
366 893875 : tree base, index2;
367 :
368 893875 : if (verify
369 893875 : && !valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
370 38023 : return NULL_TREE;
371 :
372 855852 : if (addr->offset)
373 343384 : addr->offset = fold_convert (alias_ptr_type, addr->offset);
374 : else
375 512468 : addr->offset = build_int_cst (alias_ptr_type, 0);
376 :
377 855852 : if (addr->symbol)
378 : {
379 110278 : base = addr->symbol;
380 110278 : index2 = addr->base;
381 : }
382 745574 : else if (addr->base
383 745574 : && POINTER_TYPE_P (TREE_TYPE (addr->base)))
384 : {
385 : base = addr->base;
386 : index2 = NULL_TREE;
387 : }
388 : else
389 : {
390 16 : base = build_int_cst (build_pointer_type (type), 0);
391 16 : 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 663934 : if ((TREE_CODE (base) == ADDR_EXPR || TREE_CODE (base) == INTEGER_CST)
399 191934 : && (!index2 || integer_zerop (index2))
400 1037236 : && (!addr->index || integer_zerop (addr->index)))
401 904 : return fold_build2 (MEM_REF, type, base, addr->offset);
402 :
403 854948 : return build5 (TARGET_MEM_REF, type,
404 854948 : 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 1643231 : fixed_address_object_p (tree obj)
411 : {
412 1643231 : return (VAR_P (obj)
413 1605253 : && (TREE_STATIC (obj) || DECL_EXTERNAL (obj))
414 2267704 : && ! 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 4496600 : move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
422 : {
423 4496600 : unsigned i;
424 4496600 : tree val = NULL_TREE;
425 :
426 9586006 : for (i = 0; i < addr->n; i++)
427 : {
428 5713879 : if (addr->elts[i].coef != 1)
429 1195699 : continue;
430 :
431 4518180 : val = addr->elts[i].val;
432 4518180 : if (TREE_CODE (val) == ADDR_EXPR
433 4518180 : && fixed_address_object_p (TREE_OPERAND (val, 0)))
434 : break;
435 : }
436 :
437 4496600 : if (i == addr->n)
438 : return;
439 :
440 624473 : parts->symbol = val;
441 624473 : 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 454412 : move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
449 : aff_tree *addr)
450 : {
451 454412 : unsigned i;
452 454412 : tree val = NULL_TREE;
453 454412 : int qual;
454 :
455 476754 : for (i = 0; i < addr->n; i++)
456 : {
457 476738 : if (addr->elts[i].coef != 1)
458 21809 : continue;
459 :
460 454929 : val = addr->elts[i].val;
461 454929 : if (operand_equal_p (val, base_hint, 0))
462 : break;
463 : }
464 :
465 454412 : 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 454396 : qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
473 454396 : type = build_qualified_type (void_type_node, qual);
474 454396 : parts->base = fold_convert (build_pointer_type (type), val);
475 454396 : aff_combination_remove_elt (addr, i);
476 454396 : 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 289611 : move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
484 : {
485 289611 : unsigned i;
486 289611 : tree val = NULL_TREE;
487 :
488 316960 : for (i = 0; i < addr->n; i++)
489 : {
490 316944 : if (addr->elts[i].coef != 1)
491 25914 : continue;
492 :
493 291030 : val = addr->elts[i].val;
494 291030 : if (POINTER_TYPE_P (TREE_TYPE (val)))
495 : break;
496 : }
497 :
498 289611 : if (i == addr->n)
499 : return;
500 :
501 289595 : parts->base = val;
502 289595 : 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 399826 : move_variant_to_index (struct mem_address *parts, aff_tree *addr, tree v)
510 : {
511 399826 : unsigned i;
512 399826 : tree val = NULL_TREE;
513 :
514 399826 : gcc_assert (!parts->index);
515 737912 : for (i = 0; i < addr->n; i++)
516 : {
517 737592 : val = addr->elts[i].val;
518 737592 : if (operand_equal_p (val, v, 0))
519 : break;
520 : }
521 :
522 399826 : if (i == addr->n)
523 : return;
524 :
525 399506 : parts->index = fold_convert (sizetype, val);
526 399506 : parts->step = wide_int_to_tree (sizetype, addr->elts[i].coef);
527 399506 : aff_combination_remove_elt (addr, i);
528 : }
529 :
530 : /* Adds ELT to PARTS. */
531 :
532 : static void
533 60749 : add_to_parts (struct mem_address *parts, tree elt)
534 : {
535 60749 : tree type;
536 :
537 60749 : if (!parts->index)
538 : {
539 7343 : parts->index = fold_convert (sizetype, elt);
540 7343 : return;
541 : }
542 :
543 53406 : if (!parts->base)
544 : {
545 10585 : parts->base = elt;
546 10585 : return;
547 : }
548 :
549 : /* Add ELT to base. As we have arbitrarily associated address parts
550 : make sure to use unsigned arithmetic. */
551 42821 : type = TREE_TYPE (parts->base);
552 42821 : if (POINTER_TYPE_P (type))
553 37587 : parts->base
554 37587 : = 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 22259 : multiplier_allowed_in_address_p (HOST_WIDE_INT ratio, machine_mode mode,
568 : addr_space_t as)
569 : {
570 : #define MAX_RATIO 128
571 22259 : unsigned int data_index = (int) as * MAX_MACHINE_MODE + (int) mode;
572 22259 : static vec<sbitmap> valid_mult_list;
573 22259 : sbitmap valid_mult;
574 :
575 22259 : if (data_index >= valid_mult_list.length ())
576 1070 : valid_mult_list.safe_grow_cleared (data_index + 1, true);
577 :
578 22259 : valid_mult = valid_mult_list[data_index];
579 22259 : if (!valid_mult)
580 : {
581 1184 : machine_mode address_mode = targetm.addr_space.address_mode (as);
582 1184 : rtx reg1 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1);
583 1184 : rtx reg2 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2);
584 1184 : rtx addr, scaled;
585 1184 : HOST_WIDE_INT i;
586 :
587 1184 : valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
588 1184 : bitmap_clear (valid_mult);
589 1184 : scaled = gen_rtx_fmt_ee (MULT, address_mode, reg1, NULL_RTX);
590 1184 : addr = gen_rtx_fmt_ee (PLUS, address_mode, scaled, reg2);
591 305472 : for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
592 : {
593 304288 : XEXP (scaled, 1) = gen_int_mode (i, address_mode);
594 304288 : if (memory_address_addr_space_p (mode, addr, as)
595 304288 : || memory_address_addr_space_p (mode, scaled, as))
596 4736 : bitmap_set_bit (valid_mult, i + MAX_RATIO);
597 : }
598 :
599 1184 : 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 1184 : valid_mult_list[data_index] = valid_mult;
610 : }
611 :
612 22259 : if (ratio > MAX_RATIO || ratio < -MAX_RATIO)
613 : return false;
614 :
615 21529 : 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 454732 : most_expensive_mult_to_index (tree type, struct mem_address *parts,
624 : aff_tree *addr, bool speed)
625 : {
626 454732 : addr_space_t as = TYPE_ADDR_SPACE (type);
627 454732 : machine_mode address_mode = targetm.addr_space.address_mode (as);
628 454732 : HOST_WIDE_INT coef;
629 454732 : unsigned best_mult_cost = 0, acost;
630 454732 : tree mult_elt = NULL_TREE, elt;
631 454732 : unsigned i, j;
632 454732 : enum tree_code op_code;
633 :
634 454732 : offset_int best_mult = 0;
635 477823 : for (i = 0; i < addr->n; i++)
636 : {
637 23091 : if (!wi::fits_shwi_p (addr->elts[i].coef))
638 0 : continue;
639 :
640 23091 : coef = addr->elts[i].coef.to_shwi ();
641 38229 : if (coef == 1
642 23091 : || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
643 15138 : continue;
644 :
645 7953 : acost = mult_by_coeff_cost (coef, address_mode, speed);
646 :
647 7953 : if (acost > best_mult_cost)
648 : {
649 7795 : best_mult_cost = acost;
650 7795 : best_mult = offset_int::from (addr->elts[i].coef, SIGNED);
651 : }
652 : }
653 :
654 454732 : if (!best_mult_cost)
655 446937 : return;
656 :
657 : /* Collect elements multiplied by best_mult. */
658 19493 : for (i = j = 0; i < addr->n; i++)
659 : {
660 11698 : offset_int amult = offset_int::from (addr->elts[i].coef, SIGNED);
661 11698 : offset_int amult_neg = -wi::sext (amult, TYPE_PRECISION (addr->type));
662 :
663 11698 : if (amult == best_mult)
664 : op_code = PLUS_EXPR;
665 3777 : else if (amult_neg == best_mult)
666 : op_code = MINUS_EXPR;
667 : else
668 : {
669 292 : addr->elts[j] = addr->elts[i];
670 292 : j++;
671 292 : continue;
672 : }
673 :
674 11406 : elt = fold_convert (sizetype, addr->elts[i].val);
675 11406 : if (mult_elt)
676 3611 : mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
677 7795 : else if (op_code == PLUS_EXPR)
678 : mult_elt = elt;
679 : else
680 790 : mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
681 : }
682 7795 : addr->n = j;
683 :
684 7795 : parts->index = mult_elt;
685 7795 : 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 854238 : 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 854238 : tree part;
706 854238 : unsigned i;
707 :
708 854238 : parts->symbol = NULL_TREE;
709 854238 : parts->base = NULL_TREE;
710 854238 : parts->index = NULL_TREE;
711 854238 : parts->step = NULL_TREE;
712 :
713 854238 : if (maybe_ne (addr->offset, 0))
714 341781 : parts->offset = wide_int_to_tree (sizetype, addr->offset);
715 : else
716 512457 : parts->offset = NULL_TREE;
717 :
718 : /* Try to find a symbol. */
719 854238 : 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 854238 : *var_in_base = (base_hint != NULL && parts->symbol == NULL);
725 854238 : if (*var_in_base)
726 454412 : *var_in_base = move_hint_to_base (type, parts, base_hint, addr);
727 : else
728 399826 : move_variant_to_index (parts, addr, iv_cand);
729 :
730 : /* First move the most expensive feasible multiplication to index. */
731 854238 : if (!parts->index)
732 454732 : most_expensive_mult_to_index (type, parts, addr, speed);
733 :
734 : /* Move pointer into base. */
735 854238 : if (!parts->symbol && !parts->base)
736 289611 : move_pointer_to_base (parts, addr);
737 :
738 : /* Then try to process the remaining elements. */
739 914987 : for (i = 0; i < addr->n; i++)
740 : {
741 60749 : part = fold_convert (sizetype, addr->elts[i].val);
742 60749 : if (addr->elts[i].coef != 1)
743 57936 : part = fold_build2 (MULT_EXPR, sizetype, part,
744 : wide_int_to_tree (sizetype, addr->elts[i].coef));
745 60749 : add_to_parts (parts, part);
746 : }
747 854238 : if (addr->rest)
748 0 : add_to_parts (parts, fold_convert (sizetype, addr->rest));
749 854238 : }
750 :
751 : /* Force the PARTS to register. */
752 :
753 : static void
754 854238 : gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
755 : {
756 854238 : if (parts->base)
757 754576 : parts->base = force_gimple_operand_gsi_1 (gsi, parts->base,
758 : is_gimple_mem_ref_addr, NULL_TREE,
759 : true, GSI_SAME_STMT);
760 854238 : if (parts->index)
761 414644 : parts->index = force_gimple_operand_gsi (gsi, parts->index,
762 : true, NULL_TREE,
763 : true, GSI_SAME_STMT);
764 854238 : }
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 24020 : mem_ref_valid_without_offset_p (tree type, mem_address parts)
771 : {
772 24020 : if (!parts.base)
773 0 : parts.base = parts.offset;
774 24020 : parts.offset = NULL_TREE;
775 24020 : 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 854238 : 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 854238 : bool var_in_base;
806 854238 : tree mem_ref, tmp;
807 854238 : struct mem_address parts;
808 :
809 854238 : addr_to_parts (type, addr, iv_cand, base_hint, &parts, &var_in_base, speed);
810 854238 : gimplify_mem_ref_parts (gsi, &parts);
811 854238 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
812 854238 : 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 37433 : if (parts.symbol)
819 : {
820 910 : tmp = parts.symbol;
821 910 : parts.symbol = NULL_TREE;
822 910 : gcc_assert (is_gimple_val (tmp));
823 :
824 910 : 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 875 : parts.base = tmp;
847 :
848 910 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
849 910 : 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 37113 : if (parts.step && !integer_onep (parts.step))
859 : {
860 37102 : gcc_assert (parts.index);
861 37102 : 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 37102 : 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 37102 : parts.step = NULL_TREE;
874 :
875 37102 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
876 37102 : 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 2803323 : get_address_description (tree op, struct mem_address *addr)
983 : {
984 2803323 : if (TREE_CODE (TMR_BASE (op)) == ADDR_EXPR)
985 : {
986 602024 : addr->symbol = TMR_BASE (op);
987 602024 : addr->base = TMR_INDEX2 (op);
988 : }
989 : else
990 : {
991 2201299 : addr->symbol = NULL_TREE;
992 2201299 : if (TMR_INDEX2 (op))
993 : {
994 67 : gcc_assert (integer_zerop (TMR_BASE (op)));
995 67 : addr->base = TMR_INDEX2 (op);
996 : }
997 : else
998 2201232 : addr->base = TMR_BASE (op);
999 : }
1000 2803323 : addr->index = TMR_INDEX (op);
1001 2803323 : addr->step = TMR_STEP (op);
1002 2803323 : addr->offset = TMR_OFFSET (op);
1003 2803323 : }
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 899055 : copy_ref_info (tree new_ref, tree old_ref)
1010 : {
1011 899055 : tree new_ptr_base = NULL_TREE;
1012 :
1013 899055 : gcc_assert (TREE_CODE (new_ref) == MEM_REF
1014 : || TREE_CODE (new_ref) == TARGET_MEM_REF);
1015 :
1016 899055 : TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (old_ref);
1017 899055 : TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (old_ref);
1018 :
1019 899055 : new_ptr_base = TREE_OPERAND (new_ref, 0);
1020 :
1021 899055 : tree base = get_base_address (old_ref);
1022 899055 : 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 899055 : if (new_ptr_base
1028 899055 : && TREE_CODE (new_ptr_base) == SSA_NAME
1029 1589175 : && !SSA_NAME_PTR_INFO (new_ptr_base))
1030 : {
1031 393172 : if ((TREE_CODE (base) == MEM_REF
1032 393172 : || TREE_CODE (base) == TARGET_MEM_REF)
1033 320706 : && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
1034 713878 : && SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)))
1035 : {
1036 301262 : duplicate_ssa_name_ptr_info
1037 301262 : (new_ptr_base, SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)));
1038 301262 : reset_flow_sensitive_info (new_ptr_base);
1039 : }
1040 91910 : else if (VAR_P (base)
1041 : || TREE_CODE (base) == PARM_DECL
1042 : || TREE_CODE (base) == RESULT_DECL)
1043 : {
1044 72466 : struct ptr_info_def *pi = get_ptr_info (new_ptr_base);
1045 72466 : pt_solution_set_var (&pi->pt, base);
1046 : }
1047 : }
1048 :
1049 : /* We can transfer dependence info. */
1050 899055 : if (!MR_DEPENDENCE_CLIQUE (new_ref)
1051 899055 : && (TREE_CODE (base) == MEM_REF
1052 899055 : || TREE_CODE (base) == TARGET_MEM_REF)
1053 1603917 : && MR_DEPENDENCE_CLIQUE (base))
1054 : {
1055 181457 : MR_DEPENDENCE_CLIQUE (new_ref) = MR_DEPENDENCE_CLIQUE (base);
1056 181457 : 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 899055 : unsigned old_align = get_object_alignment (old_ref);
1063 899055 : unsigned new_align = get_object_alignment (new_ref);
1064 899055 : 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 1955611 : maybe_fold_tmr (tree ref)
1073 : {
1074 1955611 : struct mem_address addr;
1075 1955611 : bool changed = false;
1076 1955611 : tree new_ref, off;
1077 :
1078 1955611 : get_address_description (ref, &addr);
1079 :
1080 1955611 : if (addr.base
1081 1575085 : && TREE_CODE (addr.base) == INTEGER_CST
1082 1955664 : && !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 1955611 : if (addr.symbol
1092 1955611 : && 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 1955611 : else if (addr.symbol
1102 1955611 : && 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 1955611 : if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
1114 : {
1115 1561 : off = addr.index;
1116 1561 : if (addr.step)
1117 : {
1118 1489 : off = fold_binary_to_constant (MULT_EXPR, sizetype,
1119 : off, addr.step);
1120 1489 : addr.step = NULL_TREE;
1121 : }
1122 :
1123 1561 : addr.offset = fold_binary_to_constant (PLUS_EXPR,
1124 1561 : TREE_TYPE (addr.offset),
1125 : addr.offset, off);
1126 1561 : addr.index = NULL_TREE;
1127 1561 : changed = true;
1128 : }
1129 :
1130 1955611 : 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 1614 : new_ref = create_mem_ref_raw (TREE_TYPE (ref),
1138 1614 : TREE_TYPE (addr.offset), &addr, false);
1139 1614 : TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (ref);
1140 1614 : TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (ref);
1141 1614 : 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 531079 : 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 531079 : if (mem_mode == BLKmode)
1153 : return 1;
1154 :
1155 522988 : struct mem_address parts = {};
1156 522988 : addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (base));
1157 522988 : unsigned int fact = GET_MODE_UNIT_SIZE (mem_mode);
1158 :
1159 : /* Addressing mode "base + index". */
1160 522988 : parts.index = integer_one_node;
1161 522988 : parts.base = integer_one_node;
1162 522988 : rtx addr = addr_for_mem_ref (&parts, as, false);
1163 522988 : unsigned cost = address_cost (addr, mem_mode, as, speed);
1164 :
1165 : /* Addressing mode "base + index << scale". */
1166 522988 : parts.step = wide_int_to_tree (sizetype, fact);
1167 522988 : addr = addr_for_mem_ref (&parts, as, false);
1168 522988 : 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 522988 : 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"
|