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 1041984 : 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 1041984 : rtx act_elem;
115 :
116 1041984 : *addr = NULL_RTX;
117 1041984 : if (step_p)
118 187765 : *step_p = NULL;
119 1041984 : if (offset_p)
120 187765 : *offset_p = NULL;
121 :
122 1041984 : if (index && index != const0_rtx)
123 : {
124 557575 : act_elem = index;
125 557575 : if (step)
126 : {
127 275558 : act_elem = gen_rtx_MULT (address_mode, act_elem, step);
128 :
129 275558 : if (step_p)
130 67086 : *step_p = &XEXP (act_elem, 1);
131 : }
132 :
133 557575 : *addr = act_elem;
134 : }
135 :
136 1041984 : if (base && base != const0_rtx)
137 : {
138 833814 : if (*addr)
139 349625 : *addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
140 : else
141 484189 : *addr = base;
142 : }
143 :
144 1041984 : if (symbol)
145 : {
146 223519 : act_elem = symbol;
147 223519 : if (offset)
148 : {
149 54728 : act_elem = gen_rtx_PLUS (address_mode, act_elem, offset);
150 :
151 54728 : if (offset_p)
152 13249 : *offset_p = &XEXP (act_elem, 1);
153 :
154 54728 : if (GET_CODE (symbol) == SYMBOL_REF
155 54728 : || GET_CODE (symbol) == LABEL_REF
156 18349 : || GET_CODE (symbol) == CONST)
157 36379 : act_elem = gen_rtx_CONST (address_mode, act_elem);
158 : }
159 :
160 223519 : if (*addr)
161 223299 : *addr = gen_rtx_PLUS (address_mode, *addr, act_elem);
162 : else
163 220 : *addr = act_elem;
164 : }
165 818465 : else if (offset)
166 : {
167 355874 : if (*addr)
168 : {
169 355874 : *addr = gen_rtx_PLUS (address_mode, *addr, offset);
170 355874 : if (offset_p)
171 67177 : *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 1041984 : if (!*addr)
182 0 : *addr = const0_rtx;
183 1041984 : }
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 18707231 : addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
193 : bool really_expand)
194 : {
195 18707231 : scalar_int_mode address_mode = targetm.addr_space.address_mode (as);
196 18707231 : scalar_int_mode pointer_mode = targetm.addr_space.pointer_mode (as);
197 18707231 : rtx address, sym, bse, idx, st, off;
198 18707231 : struct mem_addr_template *templ;
199 :
200 18707231 : if (addr->step && !integer_onep (addr->step))
201 5643517 : st = immed_wide_int_const (wi::to_wide (addr->step), pointer_mode);
202 : else
203 : st = NULL_RTX;
204 :
205 18707231 : if (addr->offset && !integer_zerop (addr->offset))
206 : {
207 7865742 : poly_offset_int dc
208 7865742 : = poly_offset_int::from (wi::to_poly_wide (addr->offset), SIGNED);
209 7865742 : off = immed_wide_int_const (dc, pointer_mode);
210 : }
211 : else
212 : off = NULL_RTX;
213 :
214 18707231 : if (!really_expand)
215 : {
216 35706024 : unsigned int templ_index
217 38933976 : = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off);
218 :
219 17853012 : if (templ_index >= vec_safe_length (mem_addr_template_list))
220 103836 : 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 17853012 : templ = &(*mem_addr_template_list)[templ_index];
224 17853012 : if (!templ->ref)
225 : {
226 187765 : sym = (addr->symbol ?
227 29785 : gen_rtx_SYMBOL_REF (pointer_mode, ggc_strdup ("test_symbol"))
228 : : NULL_RTX);
229 187765 : bse = (addr->base ?
230 162847 : gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 1)
231 : : NULL_RTX);
232 187765 : idx = (addr->index ?
233 136894 : gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 2)
234 : : NULL_RTX);
235 :
236 187765 : 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 17853012 : if (st)
245 5435045 : *templ->step_p = st;
246 17853012 : if (off)
247 7535566 : *templ->off_p = off;
248 :
249 17853012 : return templ->ref;
250 : }
251 :
252 : /* Otherwise really expand the expressions. */
253 854219 : sym = (addr->symbol
254 854219 : ? expand_expr (addr->symbol, NULL_RTX, pointer_mode, EXPAND_NORMAL)
255 : : NULL_RTX);
256 854219 : bse = (addr->base
257 854219 : ? expand_expr (addr->base, NULL_RTX, pointer_mode, EXPAND_NORMAL)
258 : : NULL_RTX);
259 854219 : idx = (addr->index
260 854219 : ? 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 854219 : 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 854219 : gen_addr_rtx (pointer_mode, sym, bse, idx, st, off, &address, NULL, NULL);
278 854219 : if (pointer_mode != address_mode)
279 8 : address = convert_memory_address (address_mode, address);
280 854219 : 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 854219 : addr_for_mem_ref (tree exp, addr_space_t as, bool really_expand)
288 : {
289 854219 : struct mem_address addr;
290 854219 : get_address_description (exp, &addr);
291 854219 : return addr_for_mem_ref (&addr, as, really_expand);
292 : }
293 :
294 : /* Returns address of MEM_REF in TYPE. */
295 :
296 : tree
297 64931 : tree_mem_ref_addr (tree type, tree mem_ref)
298 : {
299 64931 : tree addr;
300 64931 : tree act_elem;
301 64931 : tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
302 64931 : tree addr_base = NULL_TREE, addr_off = NULL_TREE;
303 :
304 64931 : addr_base = fold_convert (type, TMR_BASE (mem_ref));
305 :
306 64931 : act_elem = TMR_INDEX (mem_ref);
307 64931 : if (act_elem)
308 : {
309 2601 : if (step)
310 2031 : act_elem = fold_build2 (MULT_EXPR, TREE_TYPE (act_elem),
311 : act_elem, step);
312 : addr_off = act_elem;
313 : }
314 :
315 64931 : act_elem = TMR_INDEX2 (mem_ref);
316 64931 : 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 64931 : if (offset && !integer_zerop (offset))
326 : {
327 48429 : if (addr_off)
328 521 : 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 64931 : if (addr_off)
335 50509 : addr = fold_build_pointer_plus (addr_base, addr_off);
336 : else
337 : addr = addr_base;
338 :
339 64931 : 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 11282732 : valid_mem_ref_p (machine_mode mode, addr_space_t as,
347 : struct mem_address *addr, code_helper ch)
348 : {
349 11282732 : rtx address;
350 :
351 11282732 : address = addr_for_mem_ref (addr, as, false);
352 11282732 : if (!address)
353 : return false;
354 :
355 11282732 : 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 897922 : create_mem_ref_raw (tree type, tree alias_ptr_type, struct mem_address *addr,
364 : bool verify)
365 : {
366 897922 : tree base, index2;
367 :
368 897922 : if (verify
369 897922 : && !valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
370 38763 : return NULL_TREE;
371 :
372 859159 : if (addr->offset)
373 344218 : addr->offset = fold_convert (alias_ptr_type, addr->offset);
374 : else
375 514941 : addr->offset = build_int_cst (alias_ptr_type, 0);
376 :
377 859159 : if (addr->symbol)
378 : {
379 110352 : base = addr->symbol;
380 110352 : index2 = addr->base;
381 : }
382 748807 : else if (addr->base
383 748807 : && POINTER_TYPE_P (TREE_TYPE (addr->base)))
384 : {
385 : base = addr->base;
386 : index2 = NULL_TREE;
387 : }
388 : else
389 : {
390 20 : base = build_int_cst (build_pointer_type (type), 0);
391 20 : 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 664163 : if ((TREE_CODE (base) == ADDR_EXPR || TREE_CODE (base) == INTEGER_CST)
399 195016 : && (!index2 || integer_zerop (index2))
400 1043609 : && (!addr->index || integer_zerop (addr->index)))
401 936 : return fold_build2 (MEM_REF, type, base, addr->offset);
402 :
403 858223 : return build5 (TARGET_MEM_REF, type,
404 858223 : 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 1602209 : fixed_address_object_p (tree obj)
411 : {
412 1602209 : return (VAR_P (obj)
413 1568180 : && (TREE_STATIC (obj) || DECL_EXTERNAL (obj))
414 2216765 : && ! 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 4512155 : move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
422 : {
423 4512155 : unsigned i;
424 4512155 : tree val = NULL_TREE;
425 :
426 9632408 : for (i = 0; i < addr->n; i++)
427 : {
428 5734809 : if (addr->elts[i].coef != 1)
429 1209199 : continue;
430 :
431 4525610 : val = addr->elts[i].val;
432 4525610 : if (TREE_CODE (val) == ADDR_EXPR
433 4525610 : && fixed_address_object_p (TREE_OPERAND (val, 0)))
434 : break;
435 : }
436 :
437 4512155 : if (i == addr->n)
438 : return;
439 :
440 614556 : parts->symbol = val;
441 614556 : 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 455997 : move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
449 : aff_tree *addr)
450 : {
451 455997 : unsigned i;
452 455997 : tree val = NULL_TREE;
453 455997 : int qual;
454 :
455 478098 : for (i = 0; i < addr->n; i++)
456 : {
457 478078 : if (addr->elts[i].coef != 1)
458 21538 : continue;
459 :
460 456540 : val = addr->elts[i].val;
461 456540 : if (operand_equal_p (val, base_hint, 0))
462 : break;
463 : }
464 :
465 455997 : 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 455977 : qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
473 455977 : type = build_qualified_type (void_type_node, qual);
474 455977 : parts->base = fold_convert (build_pointer_type (type), val);
475 455977 : aff_combination_remove_elt (addr, i);
476 455977 : 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 291171 : move_pointer_to_base (struct mem_address *parts, aff_tree *addr)
484 : {
485 291171 : unsigned i;
486 291171 : tree val = NULL_TREE;
487 :
488 317254 : for (i = 0; i < addr->n; i++)
489 : {
490 317234 : if (addr->elts[i].coef != 1)
491 24697 : continue;
492 :
493 292537 : val = addr->elts[i].val;
494 292537 : if (POINTER_TYPE_P (TREE_TYPE (val)))
495 : break;
496 : }
497 :
498 291171 : if (i == addr->n)
499 : return;
500 :
501 291151 : parts->base = val;
502 291151 : 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 401472 : move_variant_to_index (struct mem_address *parts, aff_tree *addr, tree v)
510 : {
511 401472 : unsigned i;
512 401472 : tree val = NULL_TREE;
513 :
514 401472 : gcc_assert (!parts->index);
515 738961 : for (i = 0; i < addr->n; i++)
516 : {
517 738573 : val = addr->elts[i].val;
518 738573 : if (operand_equal_p (val, v, 0))
519 : break;
520 : }
521 :
522 401472 : if (i == addr->n)
523 : return;
524 :
525 401084 : parts->index = fold_convert (sizetype, val);
526 401084 : parts->step = wide_int_to_tree (sizetype, addr->elts[i].coef);
527 401084 : aff_combination_remove_elt (addr, i);
528 : }
529 :
530 : /* Adds ELT to PARTS. */
531 :
532 : static void
533 57793 : add_to_parts (struct mem_address *parts, tree elt)
534 : {
535 57793 : tree type;
536 :
537 57793 : if (!parts->index)
538 : {
539 7105 : parts->index = fold_convert (sizetype, elt);
540 7105 : return;
541 : }
542 :
543 50688 : if (!parts->base)
544 : {
545 10578 : parts->base = elt;
546 10578 : return;
547 : }
548 :
549 : /* Add ELT to base. */
550 40110 : type = TREE_TYPE (parts->base);
551 40110 : if (POINTER_TYPE_P (type))
552 34882 : parts->base = fold_build_pointer_plus (parts->base, elt);
553 : else
554 5228 : parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
555 : }
556 :
557 : /* Returns true if multiplying by RATIO is allowed in an address. Test the
558 : validity for a memory reference accessing memory of mode MODE in address
559 : space AS. */
560 :
561 : static bool
562 22054 : multiplier_allowed_in_address_p (HOST_WIDE_INT ratio, machine_mode mode,
563 : addr_space_t as)
564 : {
565 : #define MAX_RATIO 128
566 22054 : unsigned int data_index = (int) as * MAX_MACHINE_MODE + (int) mode;
567 22054 : static vec<sbitmap> valid_mult_list;
568 22054 : sbitmap valid_mult;
569 :
570 22054 : if (data_index >= valid_mult_list.length ())
571 1098 : valid_mult_list.safe_grow_cleared (data_index + 1, true);
572 :
573 22054 : valid_mult = valid_mult_list[data_index];
574 22054 : if (!valid_mult)
575 : {
576 1218 : machine_mode address_mode = targetm.addr_space.address_mode (as);
577 1218 : rtx reg1 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1);
578 1218 : rtx reg2 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2);
579 1218 : rtx addr, scaled;
580 1218 : HOST_WIDE_INT i;
581 :
582 1218 : valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1);
583 1218 : bitmap_clear (valid_mult);
584 1218 : scaled = gen_rtx_fmt_ee (MULT, address_mode, reg1, NULL_RTX);
585 1218 : addr = gen_rtx_fmt_ee (PLUS, address_mode, scaled, reg2);
586 314244 : for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
587 : {
588 313026 : XEXP (scaled, 1) = gen_int_mode (i, address_mode);
589 313026 : if (memory_address_addr_space_p (mode, addr, as)
590 313026 : || memory_address_addr_space_p (mode, scaled, as))
591 4872 : bitmap_set_bit (valid_mult, i + MAX_RATIO);
592 : }
593 :
594 1218 : if (dump_file && (dump_flags & TDF_DETAILS))
595 : {
596 0 : fprintf (dump_file, " allowed multipliers:");
597 0 : for (i = -MAX_RATIO; i <= MAX_RATIO; i++)
598 0 : if (bitmap_bit_p (valid_mult, i + MAX_RATIO))
599 0 : fprintf (dump_file, " %d", (int) i);
600 0 : fprintf (dump_file, "\n");
601 0 : fprintf (dump_file, "\n");
602 : }
603 :
604 1218 : valid_mult_list[data_index] = valid_mult;
605 : }
606 :
607 22054 : if (ratio > MAX_RATIO || ratio < -MAX_RATIO)
608 : return false;
609 :
610 21199 : return bitmap_bit_p (valid_mult, ratio + MAX_RATIO);
611 : }
612 :
613 : /* Finds the most expensive multiplication in ADDR that can be
614 : expressed in an addressing mode and move the corresponding
615 : element(s) to PARTS. */
616 :
617 : static void
618 456385 : most_expensive_mult_to_index (tree type, struct mem_address *parts,
619 : aff_tree *addr, bool speed)
620 : {
621 456385 : addr_space_t as = TYPE_ADDR_SPACE (type);
622 456385 : machine_mode address_mode = targetm.addr_space.address_mode (as);
623 456385 : HOST_WIDE_INT coef;
624 456385 : unsigned best_mult_cost = 0, acost;
625 456385 : tree mult_elt = NULL_TREE, elt;
626 456385 : unsigned i, j;
627 456385 : enum tree_code op_code;
628 :
629 456385 : offset_int best_mult = 0;
630 479368 : for (i = 0; i < addr->n; i++)
631 : {
632 22983 : if (!wi::fits_shwi_p (addr->elts[i].coef))
633 0 : continue;
634 :
635 22983 : coef = addr->elts[i].coef.to_shwi ();
636 37322 : if (coef == 1
637 22983 : || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
638 14339 : continue;
639 :
640 8644 : acost = mult_by_coeff_cost (coef, address_mode, speed);
641 :
642 8644 : if (acost > best_mult_cost)
643 : {
644 8471 : best_mult_cost = acost;
645 8471 : best_mult = offset_int::from (addr->elts[i].coef, SIGNED);
646 : }
647 : }
648 :
649 456385 : if (!best_mult_cost)
650 447914 : return;
651 :
652 : /* Collect elements multiplied by best_mult. */
653 20805 : for (i = j = 0; i < addr->n; i++)
654 : {
655 12334 : offset_int amult = offset_int::from (addr->elts[i].coef, SIGNED);
656 12334 : offset_int amult_neg = -wi::sext (amult, TYPE_PRECISION (addr->type));
657 :
658 12334 : if (amult == best_mult)
659 : op_code = PLUS_EXPR;
660 3738 : else if (amult_neg == best_mult)
661 : op_code = MINUS_EXPR;
662 : else
663 : {
664 380 : addr->elts[j] = addr->elts[i];
665 380 : j++;
666 380 : continue;
667 : }
668 :
669 11954 : elt = fold_convert (sizetype, addr->elts[i].val);
670 11954 : if (mult_elt)
671 3483 : mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
672 8471 : else if (op_code == PLUS_EXPR)
673 : mult_elt = elt;
674 : else
675 774 : mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
676 : }
677 8471 : addr->n = j;
678 :
679 8471 : parts->index = mult_elt;
680 8471 : parts->step = wide_int_to_tree (sizetype, best_mult);
681 : }
682 :
683 : /* Splits address ADDR for a memory access of type TYPE into PARTS.
684 : If BASE_HINT is non-NULL, it specifies an SSA name to be used
685 : preferentially as base of the reference, and IV_CAND is the selected
686 : iv candidate used in ADDR. Store true to VAR_IN_BASE if variant
687 : part of address is split to PARTS.base.
688 :
689 : TODO -- be more clever about the distribution of the elements of ADDR
690 : to PARTS. Some architectures do not support anything but single
691 : register in address, possibly with a small integer offset; while
692 : create_mem_ref will simplify the address to an acceptable shape
693 : later, it would be more efficient to know that asking for complicated
694 : addressing modes is useless. */
695 :
696 : static void
697 857469 : addr_to_parts (tree type, aff_tree *addr, tree iv_cand, tree base_hint,
698 : struct mem_address *parts, bool *var_in_base, bool speed)
699 : {
700 857469 : tree part;
701 857469 : unsigned i;
702 :
703 857469 : parts->symbol = NULL_TREE;
704 857469 : parts->base = NULL_TREE;
705 857469 : parts->index = NULL_TREE;
706 857469 : parts->step = NULL_TREE;
707 :
708 857469 : if (maybe_ne (addr->offset, 0))
709 342542 : parts->offset = wide_int_to_tree (sizetype, addr->offset);
710 : else
711 514927 : parts->offset = NULL_TREE;
712 :
713 : /* Try to find a symbol. */
714 857469 : move_fixed_address_to_symbol (parts, addr);
715 :
716 : /* Since at the moment there is no reliable way to know how to
717 : distinguish between pointer and its offset, we decide if var
718 : part is the pointer based on guess. */
719 857469 : *var_in_base = (base_hint != NULL && parts->symbol == NULL);
720 857469 : if (*var_in_base)
721 455997 : *var_in_base = move_hint_to_base (type, parts, base_hint, addr);
722 : else
723 401472 : move_variant_to_index (parts, addr, iv_cand);
724 :
725 : /* First move the most expensive feasible multiplication to index. */
726 857469 : if (!parts->index)
727 456385 : most_expensive_mult_to_index (type, parts, addr, speed);
728 :
729 : /* Move pointer into base. */
730 857469 : if (!parts->symbol && !parts->base)
731 291171 : move_pointer_to_base (parts, addr);
732 :
733 : /* Then try to process the remaining elements. */
734 915262 : for (i = 0; i < addr->n; i++)
735 : {
736 57793 : part = fold_convert (sizetype, addr->elts[i].val);
737 57793 : if (addr->elts[i].coef != 1)
738 55010 : part = fold_build2 (MULT_EXPR, sizetype, part,
739 : wide_int_to_tree (sizetype, addr->elts[i].coef));
740 57793 : add_to_parts (parts, part);
741 : }
742 857469 : if (addr->rest)
743 0 : add_to_parts (parts, fold_convert (sizetype, addr->rest));
744 857469 : }
745 :
746 : /* Force the PARTS to register. */
747 :
748 : static void
749 857469 : gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
750 : {
751 857469 : if (parts->base)
752 757706 : parts->base = force_gimple_operand_gsi_1 (gsi, parts->base,
753 : is_gimple_mem_ref_addr, NULL_TREE,
754 : true, GSI_SAME_STMT);
755 857469 : if (parts->index)
756 416660 : parts->index = force_gimple_operand_gsi (gsi, parts->index,
757 : true, NULL_TREE,
758 : true, GSI_SAME_STMT);
759 857469 : }
760 :
761 : /* Return true if the OFFSET in PARTS is the only thing that is making
762 : it an invalid address for type TYPE. */
763 :
764 : static bool
765 24157 : mem_ref_valid_without_offset_p (tree type, mem_address parts)
766 : {
767 24157 : if (!parts.base)
768 0 : parts.base = parts.offset;
769 24157 : parts.offset = NULL_TREE;
770 24157 : return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), &parts);
771 : }
772 :
773 : /* Fold PARTS->offset into PARTS->base, so that there is no longer
774 : a separate offset. Emit any new instructions before GSI. */
775 :
776 : static void
777 0 : add_offset_to_base (gimple_stmt_iterator *gsi, mem_address *parts)
778 : {
779 0 : tree tmp = parts->offset;
780 0 : if (parts->base)
781 : {
782 0 : tmp = fold_build_pointer_plus (parts->base, tmp);
783 0 : tmp = force_gimple_operand_gsi_1 (gsi, tmp, is_gimple_mem_ref_addr,
784 : NULL_TREE, true, GSI_SAME_STMT);
785 : }
786 0 : parts->base = tmp;
787 0 : parts->offset = NULL_TREE;
788 0 : }
789 :
790 : /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
791 : computations are emitted in front of GSI. TYPE is the mode
792 : of created memory reference. IV_CAND is the selected iv candidate in ADDR,
793 : and BASE_HINT is non NULL if IV_CAND comes from a base address
794 : object. */
795 :
796 : tree
797 857469 : create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
798 : tree alias_ptr_type, tree iv_cand, tree base_hint, bool speed)
799 : {
800 857469 : bool var_in_base;
801 857469 : tree mem_ref, tmp;
802 857469 : struct mem_address parts;
803 :
804 857469 : addr_to_parts (type, addr, iv_cand, base_hint, &parts, &var_in_base, speed);
805 857469 : gimplify_mem_ref_parts (gsi, &parts);
806 857469 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
807 857469 : if (mem_ref)
808 : return mem_ref;
809 :
810 : /* The expression is too complicated. Try making it simpler. */
811 :
812 : /* Merge symbol into other parts. */
813 38105 : if (parts.symbol)
814 : {
815 975 : tmp = parts.symbol;
816 975 : parts.symbol = NULL_TREE;
817 975 : gcc_assert (is_gimple_val (tmp));
818 :
819 975 : if (parts.base)
820 : {
821 35 : gcc_assert (useless_type_conversion_p (sizetype,
822 : TREE_TYPE (parts.base)));
823 :
824 35 : if (parts.index)
825 : {
826 : /* Add the symbol to base, eventually forcing it to register. */
827 35 : tmp = fold_build_pointer_plus (tmp, parts.base);
828 35 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
829 : is_gimple_mem_ref_addr,
830 : NULL_TREE, true,
831 : GSI_SAME_STMT);
832 : }
833 : else
834 : {
835 : /* Move base to index, then move the symbol to base. */
836 0 : parts.index = parts.base;
837 : }
838 35 : parts.base = tmp;
839 : }
840 : else
841 940 : parts.base = tmp;
842 :
843 975 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
844 975 : if (mem_ref)
845 : return mem_ref;
846 : }
847 :
848 : /* Move multiplication to index by transforming address expression:
849 : [... + index << step + ...]
850 : into:
851 : index' = index << step;
852 : [... + index' + ,,,]. */
853 37788 : if (parts.step && !integer_onep (parts.step))
854 : {
855 37774 : gcc_assert (parts.index);
856 37774 : if (parts.offset && mem_ref_valid_without_offset_p (type, parts))
857 : {
858 0 : add_offset_to_base (gsi, &parts);
859 0 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
860 0 : gcc_assert (mem_ref);
861 : return mem_ref;
862 : }
863 :
864 37774 : parts.index = force_gimple_operand_gsi (gsi,
865 : fold_build2 (MULT_EXPR, sizetype,
866 : parts.index, parts.step),
867 : true, NULL_TREE, true, GSI_SAME_STMT);
868 37774 : parts.step = NULL_TREE;
869 :
870 37774 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
871 37774 : if (mem_ref)
872 : return mem_ref;
873 : }
874 :
875 : /* Add offset to invariant part by transforming address expression:
876 : [base + index + offset]
877 : into:
878 : base' = base + offset;
879 : [base' + index]
880 : or:
881 : index' = index + offset;
882 : [base + index']
883 : depending on which one is invariant. */
884 14 : if (parts.offset && !integer_zerop (parts.offset))
885 : {
886 14 : tree old_base = unshare_expr (parts.base);
887 14 : tree old_index = unshare_expr (parts.index);
888 14 : tree old_offset = unshare_expr (parts.offset);
889 :
890 14 : tmp = parts.offset;
891 14 : parts.offset = NULL_TREE;
892 : /* Add offset to invariant part. */
893 14 : if (!var_in_base)
894 : {
895 8 : if (parts.base)
896 : {
897 8 : tmp = fold_build_pointer_plus (parts.base, tmp);
898 8 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
899 : is_gimple_mem_ref_addr,
900 : NULL_TREE, true,
901 : GSI_SAME_STMT);
902 : }
903 8 : parts.base = tmp;
904 : }
905 : else
906 : {
907 6 : if (parts.index)
908 : {
909 0 : tmp = fold_build_pointer_plus (parts.index, tmp);
910 0 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
911 : is_gimple_mem_ref_addr,
912 : NULL_TREE, true,
913 : GSI_SAME_STMT);
914 : }
915 6 : parts.index = tmp;
916 : }
917 :
918 14 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
919 14 : if (mem_ref)
920 : return mem_ref;
921 :
922 : /* Restore parts.base, index and offset so that we can check if
923 : [base + offset] addressing mode is supported in next step.
924 : This is necessary for targets only support [base + offset],
925 : but not [base + index] addressing mode. */
926 0 : parts.base = old_base;
927 0 : parts.index = old_index;
928 0 : parts.offset = old_offset;
929 : }
930 :
931 : /* Transform [base + index + ...] into:
932 : base' = base + index;
933 : [base' + ...]. */
934 0 : if (parts.index)
935 : {
936 0 : tmp = parts.index;
937 0 : parts.index = NULL_TREE;
938 : /* Add index to base. */
939 0 : if (parts.base)
940 : {
941 0 : tmp = fold_build_pointer_plus (parts.base, tmp);
942 0 : tmp = force_gimple_operand_gsi_1 (gsi, tmp,
943 : is_gimple_mem_ref_addr,
944 : NULL_TREE, true, GSI_SAME_STMT);
945 : }
946 0 : parts.base = tmp;
947 :
948 0 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
949 0 : if (mem_ref)
950 : return mem_ref;
951 : }
952 :
953 : /* Transform [base + offset] into:
954 : base' = base + offset;
955 : [base']. */
956 0 : if (parts.offset && !integer_zerop (parts.offset))
957 : {
958 0 : add_offset_to_base (gsi, &parts);
959 0 : mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
960 0 : if (mem_ref)
961 : return mem_ref;
962 : }
963 :
964 : /* Verify that the address is in the simplest possible shape
965 : (only a register). If we cannot create such a memory reference,
966 : something is really wrong. */
967 0 : gcc_assert (parts.symbol == NULL_TREE);
968 0 : gcc_assert (parts.index == NULL_TREE);
969 0 : gcc_assert (!parts.step || integer_onep (parts.step));
970 0 : gcc_assert (!parts.offset || integer_zerop (parts.offset));
971 0 : gcc_unreachable ();
972 : }
973 :
974 : /* Copies components of the address from OP to ADDR. */
975 :
976 : void
977 2830262 : get_address_description (tree op, struct mem_address *addr)
978 : {
979 2830262 : if (TREE_CODE (TMR_BASE (op)) == ADDR_EXPR)
980 : {
981 613765 : addr->symbol = TMR_BASE (op);
982 613765 : addr->base = TMR_INDEX2 (op);
983 : }
984 : else
985 : {
986 2216497 : addr->symbol = NULL_TREE;
987 2216497 : if (TMR_INDEX2 (op))
988 : {
989 82 : gcc_assert (integer_zerop (TMR_BASE (op)));
990 82 : addr->base = TMR_INDEX2 (op);
991 : }
992 : else
993 2216415 : addr->base = TMR_BASE (op);
994 : }
995 2830262 : addr->index = TMR_INDEX (op);
996 2830262 : addr->step = TMR_STEP (op);
997 2830262 : addr->offset = TMR_OFFSET (op);
998 2830262 : }
999 :
1000 : /* Copies the reference information from OLD_REF to NEW_REF, where
1001 : NEW_REF should be either a MEM_REF or a TARGET_MEM_REF. */
1002 :
1003 : void
1004 901929 : copy_ref_info (tree new_ref, tree old_ref)
1005 : {
1006 901929 : tree new_ptr_base = NULL_TREE;
1007 :
1008 901929 : gcc_assert (TREE_CODE (new_ref) == MEM_REF
1009 : || TREE_CODE (new_ref) == TARGET_MEM_REF);
1010 :
1011 901929 : TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (old_ref);
1012 901929 : TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (old_ref);
1013 :
1014 901929 : new_ptr_base = TREE_OPERAND (new_ref, 0);
1015 :
1016 901929 : tree base = get_base_address (old_ref);
1017 901929 : if (!base)
1018 : return;
1019 :
1020 : /* We can transfer points-to information from an old pointer
1021 : or decl base to the new one. */
1022 901929 : if (new_ptr_base
1023 901929 : && TREE_CODE (new_ptr_base) == SSA_NAME
1024 1591886 : && !SSA_NAME_PTR_INFO (new_ptr_base))
1025 : {
1026 388362 : if ((TREE_CODE (base) == MEM_REF
1027 388362 : || TREE_CODE (base) == TARGET_MEM_REF)
1028 319211 : && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
1029 707573 : && SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)))
1030 : {
1031 295760 : duplicate_ssa_name_ptr_info
1032 295760 : (new_ptr_base, SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)));
1033 295760 : reset_flow_sensitive_info (new_ptr_base);
1034 : }
1035 92602 : else if (VAR_P (base)
1036 : || TREE_CODE (base) == PARM_DECL
1037 : || TREE_CODE (base) == RESULT_DECL)
1038 : {
1039 69151 : struct ptr_info_def *pi = get_ptr_info (new_ptr_base);
1040 69151 : pt_solution_set_var (&pi->pt, base);
1041 : }
1042 : }
1043 :
1044 : /* We can transfer dependence info. */
1045 901929 : if (!MR_DEPENDENCE_CLIQUE (new_ref)
1046 901929 : && (TREE_CODE (base) == MEM_REF
1047 901929 : || TREE_CODE (base) == TARGET_MEM_REF)
1048 1609993 : && MR_DEPENDENCE_CLIQUE (base))
1049 : {
1050 188110 : MR_DEPENDENCE_CLIQUE (new_ref) = MR_DEPENDENCE_CLIQUE (base);
1051 188110 : MR_DEPENDENCE_BASE (new_ref) = MR_DEPENDENCE_BASE (base);
1052 : }
1053 :
1054 : /* And alignment info. Note we cannot transfer misalignment info
1055 : since that sits on the SSA name but this is flow-sensitive info
1056 : which we cannot transfer in this generic routine. */
1057 901929 : unsigned old_align = get_object_alignment (old_ref);
1058 901929 : unsigned new_align = get_object_alignment (new_ref);
1059 901929 : if (new_align < old_align)
1060 775 : TREE_TYPE (new_ref) = build_aligned_type (TREE_TYPE (new_ref), old_align);
1061 : }
1062 :
1063 : /* Move constants in target_mem_ref REF to offset. Returns the new target
1064 : mem ref if anything changes, NULL_TREE otherwise. */
1065 :
1066 : tree
1067 1976043 : maybe_fold_tmr (tree ref)
1068 : {
1069 1976043 : struct mem_address addr;
1070 1976043 : bool changed = false;
1071 1976043 : tree new_ref, off;
1072 :
1073 1976043 : get_address_description (ref, &addr);
1074 :
1075 1976043 : if (addr.base
1076 1587287 : && TREE_CODE (addr.base) == INTEGER_CST
1077 1976090 : && !integer_zerop (addr.base))
1078 : {
1079 47 : addr.offset = fold_binary_to_constant (PLUS_EXPR,
1080 47 : TREE_TYPE (addr.offset),
1081 : addr.offset, addr.base);
1082 47 : addr.base = NULL_TREE;
1083 47 : changed = true;
1084 : }
1085 :
1086 1976043 : if (addr.symbol
1087 1976043 : && TREE_CODE (TREE_OPERAND (addr.symbol, 0)) == MEM_REF)
1088 : {
1089 0 : addr.offset = fold_binary_to_constant
1090 0 : (PLUS_EXPR, TREE_TYPE (addr.offset),
1091 : addr.offset,
1092 0 : TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 1));
1093 0 : addr.symbol = TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 0);
1094 0 : changed = true;
1095 : }
1096 1976043 : else if (addr.symbol
1097 1976043 : && handled_component_p (TREE_OPERAND (addr.symbol, 0)))
1098 : {
1099 0 : poly_int64 offset;
1100 0 : addr.symbol = build_fold_addr_expr
1101 : (get_addr_base_and_unit_offset
1102 : (TREE_OPERAND (addr.symbol, 0), &offset));
1103 0 : addr.offset = int_const_binop (PLUS_EXPR,
1104 0 : addr.offset, size_int (offset));
1105 0 : changed = true;
1106 : }
1107 :
1108 1976043 : if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
1109 : {
1110 1643 : off = addr.index;
1111 1643 : if (addr.step)
1112 : {
1113 1527 : off = fold_binary_to_constant (MULT_EXPR, sizetype,
1114 : off, addr.step);
1115 1527 : addr.step = NULL_TREE;
1116 : }
1117 :
1118 1643 : addr.offset = fold_binary_to_constant (PLUS_EXPR,
1119 1643 : TREE_TYPE (addr.offset),
1120 : addr.offset, off);
1121 1643 : addr.index = NULL_TREE;
1122 1643 : changed = true;
1123 : }
1124 :
1125 1976043 : if (!changed)
1126 : return NULL_TREE;
1127 :
1128 : /* If we have propagated something into this TARGET_MEM_REF and thus
1129 : ended up folding it, always create a new TARGET_MEM_REF regardless
1130 : if it is valid in this for on the target - the propagation result
1131 : wouldn't be anyway. */
1132 1690 : new_ref = create_mem_ref_raw (TREE_TYPE (ref),
1133 1690 : TREE_TYPE (addr.offset), &addr, false);
1134 1690 : TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (ref);
1135 1690 : TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (ref);
1136 1690 : return new_ref;
1137 : }
1138 :
1139 : /* Return the preferred index scale factor for accessing memory of mode
1140 : MEM_MODE in the address space of pointer BASE. Assume that we're
1141 : optimizing for speed if SPEED is true and for size otherwise. */
1142 : unsigned int
1143 531835 : preferred_mem_scale_factor (tree base, machine_mode mem_mode,
1144 : bool speed)
1145 : {
1146 : /* For BLKmode, we can't do anything so return 1. */
1147 531835 : if (mem_mode == BLKmode)
1148 : return 1;
1149 :
1150 523014 : struct mem_address parts = {};
1151 523014 : addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (base));
1152 523014 : unsigned int fact = GET_MODE_UNIT_SIZE (mem_mode);
1153 :
1154 : /* Addressing mode "base + index". */
1155 523014 : parts.index = integer_one_node;
1156 523014 : parts.base = integer_one_node;
1157 523014 : rtx addr = addr_for_mem_ref (&parts, as, false);
1158 523014 : unsigned cost = address_cost (addr, mem_mode, as, speed);
1159 :
1160 : /* Addressing mode "base + index << scale". */
1161 523014 : parts.step = wide_int_to_tree (sizetype, fact);
1162 523014 : addr = addr_for_mem_ref (&parts, as, false);
1163 523014 : unsigned new_cost = address_cost (addr, mem_mode, as, speed);
1164 :
1165 : /* Compare the cost of an address with an unscaled index with
1166 : a scaled index and return factor if useful. */
1167 523014 : if (new_cost < cost)
1168 0 : return GET_MODE_UNIT_SIZE (mem_mode);
1169 : return 1;
1170 : }
1171 :
1172 : /* Dump PARTS to FILE. */
1173 :
1174 : extern void dump_mem_address (FILE *, struct mem_address *);
1175 : void
1176 0 : dump_mem_address (FILE *file, struct mem_address *parts)
1177 : {
1178 0 : if (parts->symbol)
1179 : {
1180 0 : fprintf (file, "symbol: ");
1181 0 : print_generic_expr (file, TREE_OPERAND (parts->symbol, 0), TDF_SLIM);
1182 0 : fprintf (file, "\n");
1183 : }
1184 0 : if (parts->base)
1185 : {
1186 0 : fprintf (file, "base: ");
1187 0 : print_generic_expr (file, parts->base, TDF_SLIM);
1188 0 : fprintf (file, "\n");
1189 : }
1190 0 : if (parts->index)
1191 : {
1192 0 : fprintf (file, "index: ");
1193 0 : print_generic_expr (file, parts->index, TDF_SLIM);
1194 0 : fprintf (file, "\n");
1195 : }
1196 0 : if (parts->step)
1197 : {
1198 0 : fprintf (file, "step: ");
1199 0 : print_generic_expr (file, parts->step, TDF_SLIM);
1200 0 : fprintf (file, "\n");
1201 : }
1202 0 : if (parts->offset)
1203 : {
1204 0 : fprintf (file, "offset: ");
1205 0 : print_generic_expr (file, parts->offset, TDF_SLIM);
1206 0 : fprintf (file, "\n");
1207 : }
1208 0 : }
1209 :
1210 : #include "gt-tree-ssa-address.h"
|